2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/utils/mono-proclib.h>
18 #include <mono/utils/mono-mmap.h>
21 #ifdef TARGET_POWERPC64
22 #include "cpu-ppc64.h"
29 #include <sys/sysctl.h>
35 #define FORCE_INDIR_CALL 1
46 /* cpu_hw_caps contains the flags defined below */
47 static int cpu_hw_caps
= 0;
48 static int cachelinesize
= 0;
49 static int cachelineinc
= 0;
51 PPC_ICACHE_SNOOP
= 1 << 0,
52 PPC_MULTIPLE_LS_UNITS
= 1 << 1,
53 PPC_SMP_CAPABLE
= 1 << 2,
56 PPC_MOVE_FPR_GPR
= 1 << 5,
60 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
65 static CRITICAL_SECTION mini_arch_mutex
;
67 int mono_exc_esp_offset
= 0;
68 static int tls_mode
= TLS_MODE_DETECT
;
69 static int lmf_pthread_key
= -1;
70 static int monodomain_key
= -1;
73 * The code generated for sequence points reads from this location, which is
74 * made read-only when single stepping is enabled.
76 static gpointer ss_trigger_page
;
78 /* Enabled breakpoints read from this trigger page */
79 static gpointer bp_trigger_page
;
82 offsets_from_pthread_key (guint32 key
, int *offset2
)
86 *offset2
= idx2
* sizeof (gpointer
);
87 return 284 + idx1
* sizeof (gpointer
);
90 #define emit_linuxthreads_tls(code,dreg,key) do {\
92 off1 = offsets_from_pthread_key ((key), &off2); \
93 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
94 ppc_ldptr ((code), (dreg), off2, (dreg)); \
97 #define emit_darwing5_tls(code,dreg,key) do {\
98 int off1 = 0x48 + key * sizeof (gpointer); \
99 ppc_mfspr ((code), (dreg), 104); \
100 ppc_ldptr ((code), (dreg), off1, (dreg)); \
103 /* FIXME: ensure the sc call preserves all but r3 */
104 #define emit_darwing4_tls(code,dreg,key) do {\
105 int off1 = 0x48 + key * sizeof (gpointer); \
106 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
107 ppc_li ((code), ppc_r0, 0x7FF2); \
109 ppc_lwz ((code), (dreg), off1, ppc_r3); \
110 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
113 #ifdef PPC_THREAD_PTR_REG
114 #define emit_nptl_tls(code,dreg,key) do { \
116 int off2 = key >> 15; \
117 if ((off2 == 0) || (off2 == -1)) { \
118 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
120 int off3 = (off2 + 1) > 1; \
121 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
122 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
126 #define emit_nptl_tls(code,dreg,key) do { \
127 g_assert_not_reached (); \
131 #define emit_tls_access(code,dreg,key) do { \
132 switch (tls_mode) { \
133 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
134 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
135 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
137 default: g_assert_not_reached (); \
141 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
143 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
144 inst->type = STACK_R8; \
146 inst->inst_p0 = (void*)(addr); \
147 mono_bblock_add_inst (cfg->cbb, inst); \
151 mono_arch_regname (int reg
) {
152 static const char rnames
[][4] = {
153 "r0", "sp", "r2", "r3", "r4",
154 "r5", "r6", "r7", "r8", "r9",
155 "r10", "r11", "r12", "r13", "r14",
156 "r15", "r16", "r17", "r18", "r19",
157 "r20", "r21", "r22", "r23", "r24",
158 "r25", "r26", "r27", "r28", "r29",
161 if (reg
>= 0 && reg
< 32)
167 mono_arch_fregname (int reg
) {
168 static const char rnames
[][4] = {
169 "f0", "f1", "f2", "f3", "f4",
170 "f5", "f6", "f7", "f8", "f9",
171 "f10", "f11", "f12", "f13", "f14",
172 "f15", "f16", "f17", "f18", "f19",
173 "f20", "f21", "f22", "f23", "f24",
174 "f25", "f26", "f27", "f28", "f29",
177 if (reg
>= 0 && reg
< 32)
182 /* this function overwrites r0, r11, r12 */
184 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
186 /* unrolled, use the counter in big */
187 if (size
> sizeof (gpointer
) * 5) {
188 long shifted
= size
/ SIZEOF_VOID_P
;
189 guint8
*copy_loop_start
, *copy_loop_jump
;
191 ppc_load (code
, ppc_r0
, shifted
);
192 ppc_mtctr (code
, ppc_r0
);
193 //g_assert (sreg == ppc_r11);
194 ppc_addi (code
, ppc_r12
, dreg
, (doffset
- sizeof (gpointer
)));
195 ppc_addi (code
, ppc_r11
, sreg
, (soffset
- sizeof (gpointer
)));
196 copy_loop_start
= code
;
197 ppc_ldptr_update (code
, ppc_r0
, (unsigned int)sizeof (gpointer
), ppc_r11
);
198 ppc_stptr_update (code
, ppc_r0
, (unsigned int)sizeof (gpointer
), ppc_r12
);
199 copy_loop_jump
= code
;
200 ppc_bc (code
, PPC_BR_DEC_CTR_NONZERO
, 0, 0);
201 ppc_patch (copy_loop_jump
, copy_loop_start
);
202 size
-= shifted
* sizeof (gpointer
);
203 doffset
= soffset
= 0;
206 #ifdef __mono_ppc64__
207 /* the hardware has multiple load/store units and the move is long
208 enough to use more then one regiester, then use load/load/store/store
209 to execute 2 instructions per cycle. */
210 if ((cpu_hw_caps
& PPC_MULTIPLE_LS_UNITS
) && (dreg
!= ppc_r12
) && (sreg
!= ppc_r12
)) {
212 ppc_ldptr (code
, ppc_r0
, soffset
, sreg
);
213 ppc_ldptr (code
, ppc_r12
, soffset
+8, sreg
);
214 ppc_stptr (code
, ppc_r0
, doffset
, dreg
);
215 ppc_stptr (code
, ppc_r12
, doffset
+8, dreg
);
222 ppc_ldr (code
, ppc_r0
, soffset
, sreg
);
223 ppc_str (code
, ppc_r0
, doffset
, dreg
);
229 if ((cpu_hw_caps
& PPC_MULTIPLE_LS_UNITS
) && (dreg
!= ppc_r12
) && (sreg
!= ppc_r12
)) {
231 ppc_lwz (code
, ppc_r0
, soffset
, sreg
);
232 ppc_lwz (code
, ppc_r12
, soffset
+4, sreg
);
233 ppc_stw (code
, ppc_r0
, doffset
, dreg
);
234 ppc_stw (code
, ppc_r12
, doffset
+4, dreg
);
242 ppc_lwz (code
, ppc_r0
, soffset
, sreg
);
243 ppc_stw (code
, ppc_r0
, doffset
, dreg
);
249 ppc_lhz (code
, ppc_r0
, soffset
, sreg
);
250 ppc_sth (code
, ppc_r0
, doffset
, dreg
);
256 ppc_lbz (code
, ppc_r0
, soffset
, sreg
);
257 ppc_stb (code
, ppc_r0
, doffset
, dreg
);
266 * mono_arch_get_argument_info:
267 * @csig: a method signature
268 * @param_count: the number of parameters to consider
269 * @arg_info: an array to store the result infos
271 * Gathers information on parameters such as size, alignment and
272 * padding. arg_info should be large enought to hold param_count + 1 entries.
274 * Returns the size of the activation frame.
277 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
279 #ifdef __mono_ppc64__
283 int k
, frame_size
= 0;
284 int size
, align
, pad
;
287 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
288 frame_size
+= sizeof (gpointer
);
292 arg_info
[0].offset
= offset
;
295 frame_size
+= sizeof (gpointer
);
299 arg_info
[0].size
= frame_size
;
301 for (k
= 0; k
< param_count
; k
++) {
304 size
= mono_type_native_stack_size (csig
->params
[k
], (guint32
*)&align
);
306 size
= mini_type_stack_size (NULL
, csig
->params
[k
], &align
);
308 /* ignore alignment for now */
311 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
312 arg_info
[k
].pad
= pad
;
314 arg_info
[k
+ 1].pad
= 0;
315 arg_info
[k
+ 1].size
= size
;
317 arg_info
[k
+ 1].offset
= offset
;
321 align
= MONO_ARCH_FRAME_ALIGNMENT
;
322 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
323 arg_info
[k
].pad
= pad
;
329 #ifdef __mono_ppc64__
331 is_load_sequence (guint32
*seq
)
333 return ppc_opcode (seq
[0]) == 15 && /* lis */
334 ppc_opcode (seq
[1]) == 24 && /* ori */
335 ppc_opcode (seq
[2]) == 30 && /* sldi */
336 ppc_opcode (seq
[3]) == 25 && /* oris */
337 ppc_opcode (seq
[4]) == 24; /* ori */
340 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
341 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
345 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
347 /* code must point to the blrl */
349 mono_ppc_is_direct_call_sequence (guint32
*code
)
351 #ifdef __mono_ppc64__
352 g_assert(*code
== 0x4e800021 || *code
== 0x4e800020 || *code
== 0x4e800420);
354 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
355 if (ppc_opcode (code
[-1]) == 31) { /* mtlr */
356 if (ppc_is_load_op (code
[-2]) && ppc_is_load_op (code
[-3])) { /* ld/ld */
357 if (!is_load_sequence (&code
[-8]))
359 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
360 return (ppc_load_get_dest (code
[-2]) == ppc_r2
&& ppc_load_get_off (code
[-2]) == sizeof (gpointer
)) ||
361 (ppc_load_get_dest (code
[-3]) == ppc_r2
&& ppc_load_get_off (code
[-3]) == sizeof (gpointer
));
363 if (ppc_opcode (code
[-2]) == 24 && ppc_opcode (code
[-3]) == 31) /* mr/nop */
364 return is_load_sequence (&code
[-8]);
366 return is_load_sequence (&code
[-6]);
370 g_assert(*code
== 0x4e800021);
372 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
373 return ppc_opcode (code
[-1]) == 31 &&
374 ppc_opcode (code
[-2]) == 24 &&
375 ppc_opcode (code
[-3]) == 15;
379 #define MAX_ARCH_DELEGATE_PARAMS 7
382 get_delegate_invoke_impl (gboolean has_target
, guint32 param_count
, guint32
*code_len
, gboolean aot
)
384 guint8
*code
, *start
;
387 int size
= MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE
;
389 start
= code
= mono_global_codeman_reserve (size
);
391 code
= mono_ppc_create_pre_code_ftnptr (code
);
393 /* Replace the this argument with the target */
394 ppc_ldptr (code
, ppc_r0
, G_STRUCT_OFFSET (MonoDelegate
, method_ptr
), ppc_r3
);
395 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
396 /* it's a function descriptor */
397 /* Can't use ldptr as it doesn't work with r0 */
398 ppc_ldptr_indexed (code
, ppc_r0
, 0, ppc_r0
);
400 ppc_mtctr (code
, ppc_r0
);
401 ppc_ldptr (code
, ppc_r3
, G_STRUCT_OFFSET (MonoDelegate
, target
), ppc_r3
);
402 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
404 g_assert ((code
- start
) <= size
);
406 mono_arch_flush_icache (start
, size
);
410 size
= MONO_PPC_32_64_CASE (32, 32) + param_count
* 4 + PPC_FTNPTR_SIZE
;
411 start
= code
= mono_global_codeman_reserve (size
);
413 code
= mono_ppc_create_pre_code_ftnptr (code
);
415 ppc_ldptr (code
, ppc_r0
, G_STRUCT_OFFSET (MonoDelegate
, method_ptr
), ppc_r3
);
416 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
417 /* it's a function descriptor */
418 ppc_ldptr_indexed (code
, ppc_r0
, 0, ppc_r0
);
420 ppc_mtctr (code
, ppc_r0
);
421 /* slide down the arguments */
422 for (i
= 0; i
< param_count
; ++i
) {
423 ppc_mr (code
, (ppc_r3
+ i
), (ppc_r3
+ i
+ 1));
425 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
427 g_assert ((code
- start
) <= size
);
429 mono_arch_flush_icache (start
, size
);
433 *code_len
= code
- start
;
439 mono_arch_get_delegate_invoke_impls (void)
446 code
= get_delegate_invoke_impl (TRUE
, 0, &code_len
, TRUE
);
447 res
= g_slist_prepend (res
, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code
, code_len
, NULL
, NULL
));
449 for (i
= 0; i
< MAX_ARCH_DELEGATE_PARAMS
; ++i
) {
450 code
= get_delegate_invoke_impl (FALSE
, i
, &code_len
, TRUE
);
451 res
= g_slist_prepend (res
, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i
), code
, code_len
, NULL
, NULL
));
458 mono_arch_get_delegate_invoke_impl (MonoMethodSignature
*sig
, gboolean has_target
)
460 guint8
*code
, *start
;
462 /* FIXME: Support more cases */
463 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
467 static guint8
* cached
= NULL
;
473 start
= mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
475 start
= get_delegate_invoke_impl (TRUE
, 0, NULL
, FALSE
);
477 mono_memory_barrier ();
481 static guint8
* cache
[MAX_ARCH_DELEGATE_PARAMS
+ 1] = {NULL
};
484 if (sig
->param_count
> MAX_ARCH_DELEGATE_PARAMS
)
486 for (i
= 0; i
< sig
->param_count
; ++i
)
487 if (!mono_is_regsize_var (sig
->params
[i
]))
491 code
= cache
[sig
->param_count
];
496 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", sig
->param_count
);
497 start
= mono_aot_get_trampoline (name
);
500 start
= get_delegate_invoke_impl (FALSE
, sig
->param_count
, NULL
, FALSE
);
503 mono_memory_barrier ();
505 cache
[sig
->param_count
] = start
;
511 mono_arch_get_this_arg_from_call (mgreg_t
*regs
, guint8
*code
)
513 mgreg_t
*r
= (mgreg_t
*)regs
;
515 return (gpointer
)(gsize
)r
[ppc_r3
];
523 #ifdef USE_ENVIRON_HACK
525 linux_find_auxv (int *count
)
529 char **result
= __environ
;
530 /* Scan over the env vector looking for the ending NULL */
531 for (; *result
!= NULL
; ++result
) {
533 /* Bump the pointer one more step, which should be the auxv. */
535 vec
= (AuxVec
*)result
;
536 if (vec
->type
!= 22 /*AT_IGNOREPPC*/) {
540 while (vec
->type
!= 0 /*AT_NULL*/) {
545 return (AuxVec
*)result
;
549 #define MAX_AUX_ENTRIES 128
551 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
552 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
554 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
556 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
557 #define ISA_64 0x40000000
559 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
560 #define ISA_MOVE_FPR_GPR 0x00000200
562 * Initialize the cpu to execute managed code.
565 mono_arch_cpu_init (void)
570 * Initialize architecture specific code.
573 mono_arch_init (void)
575 #if defined(MONO_CROSS_COMPILE)
576 #elif defined(__APPLE__)
580 mib
[1] = HW_CACHELINE
;
581 len
= sizeof (cachelinesize
);
582 if (sysctl (mib
, 2, &cachelinesize
, (size_t*)&len
, NULL
, 0) == -1) {
586 cachelineinc
= cachelinesize
;
588 #elif defined(__linux__)
589 AuxVec vec
[MAX_AUX_ENTRIES
];
590 int i
, vec_entries
= 0;
591 /* sadly this will work only with 2.6 kernels... */
592 FILE* f
= fopen ("/proc/self/auxv", "rb");
594 vec_entries
= fread (&vec
, sizeof (AuxVec
), MAX_AUX_ENTRIES
, f
);
596 #ifdef USE_ENVIRON_HACK
598 AuxVec
*evec
= linux_find_auxv (&vec_entries
);
600 memcpy (&vec
, evec
, sizeof (AuxVec
) * MIN (vec_entries
, MAX_AUX_ENTRIES
));
603 for (i
= 0; i
< vec_entries
; i
++) {
604 int type
= vec
[i
].type
;
605 if (type
== 19) { /* AT_DCACHEBSIZE */
606 cachelinesize
= vec
[i
].value
;
608 } else if (type
== 16) { /* AT_HWCAP */
609 if (vec
[i
].value
& 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
610 cpu_hw_caps
|= PPC_ICACHE_SNOOP
;
611 if (vec
[i
].value
& ISA_2X
)
612 cpu_hw_caps
|= PPC_ISA_2X
;
613 if (vec
[i
].value
& ISA_64
)
614 cpu_hw_caps
|= PPC_ISA_64
;
615 if (vec
[i
].value
& ISA_MOVE_FPR_GPR
)
616 cpu_hw_caps
|= PPC_MOVE_FPR_GPR
;
618 } else if (type
== 15) { /* AT_PLATFORM */
619 const char *arch
= (char*)vec
[i
].value
;
620 if (strcmp (arch
, "ppc970") == 0 ||
621 (strncmp (arch
, "power", 5) == 0 && arch
[5] >= '4' && arch
[5] <= '7'))
622 cpu_hw_caps
|= PPC_MULTIPLE_LS_UNITS
;
623 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
627 #elif defined(G_COMPILER_CODEWARRIOR)
631 //#error Need a way to get cache line size
636 cachelineinc
= cachelinesize
;
638 if (mono_cpu_count () > 1)
639 cpu_hw_caps
|= PPC_SMP_CAPABLE
;
640 InitializeCriticalSection (&mini_arch_mutex
);
642 ss_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
);
643 bp_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
);
644 mono_mprotect (bp_trigger_page
, mono_pagesize (), 0);
646 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception
);
650 * Cleanup architecture specific code.
653 mono_arch_cleanup (void)
655 DeleteCriticalSection (&mini_arch_mutex
);
659 * This function returns the optimizations supported on this cpu.
662 mono_arch_cpu_optimizazions (guint32
*exclude_mask
)
666 /* no ppc-specific optimizations yet */
671 #ifdef __mono_ppc64__
672 #define CASE_PPC32(c)
673 #define CASE_PPC64(c) case c:
675 #define CASE_PPC32(c) case c:
676 #define CASE_PPC64(c)
680 is_regsize_var (MonoType
*t
) {
683 t
= mini_type_get_underlying_type (NULL
, t
);
687 CASE_PPC64 (MONO_TYPE_I8
)
688 CASE_PPC64 (MONO_TYPE_U8
)
692 case MONO_TYPE_FNPTR
:
694 case MONO_TYPE_OBJECT
:
695 case MONO_TYPE_STRING
:
696 case MONO_TYPE_CLASS
:
697 case MONO_TYPE_SZARRAY
:
698 case MONO_TYPE_ARRAY
:
700 case MONO_TYPE_GENERICINST
:
701 if (!mono_type_generic_inst_is_valuetype (t
))
704 case MONO_TYPE_VALUETYPE
:
712 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
717 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
718 MonoInst
*ins
= cfg
->varinfo
[i
];
719 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
722 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
725 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
728 /* we can only allocate 32 bit values */
729 if (is_regsize_var (ins
->inst_vtype
)) {
730 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
731 g_assert (i
== vmv
->idx
);
732 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
738 #endif /* ifndef DISABLE_JIT */
741 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
745 if (cfg
->frame_reg
!= ppc_sp
)
747 /* ppc_r13 is used by the system on PPC EABI */
748 for (i
= 14; i
< top
; ++i
) {
750 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
751 * since the trampolines can clobber r11.
753 if (!(cfg
->compile_aot
&& i
== 29))
754 regs
= g_list_prepend (regs
, GUINT_TO_POINTER (i
));
761 * mono_arch_regalloc_cost:
763 * Return the cost, in number of memory references, of the action of
764 * allocating the variable VMV into a register during global register
768 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
775 mono_arch_flush_icache (guint8
*code
, gint size
)
777 #ifdef MONO_CROSS_COMPILE
780 guint8
*endp
, *start
;
784 start
= (guint8
*)((gsize
)start
& ~(cachelinesize
- 1));
785 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
786 #if defined(G_COMPILER_CODEWARRIOR)
787 if (cpu_hw_caps
& PPC_SMP_CAPABLE
) {
788 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
792 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
798 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
809 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
810 * The sync is required to insure that the store queue is completely empty.
811 * While the icbi performs no cache operations, icbi/isync is required to
812 * kill local prefetch.
814 if (cpu_hw_caps
& PPC_ICACHE_SNOOP
) {
816 asm ("icbi 0,%0;" : : "r"(code
) : "memory");
820 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
821 if (cpu_hw_caps
& PPC_SMP_CAPABLE
) {
822 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
823 asm ("dcbf 0,%0;" : : "r"(p
) : "memory");
826 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
827 asm ("dcbst 0,%0;" : : "r"(p
) : "memory");
832 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
833 /* for ISA2.0+ implementations we should not need any extra sync between the
834 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
835 * So I am not sure which chip had this problem but its not an issue on
836 * of the ISA V2 chips.
838 if (cpu_hw_caps
& PPC_ISA_2X
)
839 asm ("icbi 0,%0;" : : "r"(p
) : "memory");
841 asm ("icbi 0,%0; sync;" : : "r"(p
) : "memory");
843 if (!(cpu_hw_caps
& PPC_ISA_2X
))
851 mono_arch_flush_register_windows (void)
856 #define ALWAYS_ON_STACK(s) s
857 #define FP_ALSO_IN_REG(s) s
859 #ifdef __mono_ppc64__
860 #define ALWAYS_ON_STACK(s) s
861 #define FP_ALSO_IN_REG(s) s
863 #define ALWAYS_ON_STACK(s)
864 #define FP_ALSO_IN_REG(s)
866 #define ALIGN_DOUBLES
879 guint32 vtsize
; /* in param area */
881 guint8 vtregs
; /* number of registers used to pass a RegTypeStructByVal */
882 guint8 regtype
: 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
883 guint8 size
: 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
884 guint8 bytes
: 4; /* size in bytes - only valid for
885 RegTypeStructByVal if the struct fits
886 in one word, otherwise it's 0*/
895 gboolean vtype_retaddr
;
903 add_general (guint
*gr
, guint
*stack_size
, ArgInfo
*ainfo
, gboolean simple
)
905 #ifdef __mono_ppc64__
910 if (*gr
>= 3 + PPC_NUM_REG_ARGS
) {
911 ainfo
->offset
= PPC_STACK_PARAM_OFFSET
+ *stack_size
;
912 ainfo
->reg
= ppc_sp
; /* in the caller */
913 ainfo
->regtype
= RegTypeBase
;
914 *stack_size
+= sizeof (gpointer
);
916 ALWAYS_ON_STACK (*stack_size
+= sizeof (gpointer
));
920 if (*gr
>= 3 + PPC_NUM_REG_ARGS
- 1) {
922 //*stack_size += (*stack_size % 8);
924 ainfo
->offset
= PPC_STACK_PARAM_OFFSET
+ *stack_size
;
925 ainfo
->reg
= ppc_sp
; /* in the caller */
926 ainfo
->regtype
= RegTypeBase
;
933 ALWAYS_ON_STACK (*stack_size
+= 8);
941 #if defined(__APPLE__) || defined(__mono_ppc64__)
943 has_only_a_r48_field (MonoClass
*klass
)
947 gboolean have_field
= FALSE
;
949 while ((f
= mono_class_get_fields (klass
, &iter
))) {
950 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
953 if (!f
->type
->byref
&& (f
->type
->type
== MONO_TYPE_R4
|| f
->type
->type
== MONO_TYPE_R8
))
964 get_call_info (MonoGenericSharingContext
*gsctx
, MonoMethodSignature
*sig
)
966 guint i
, fr
, gr
, pstart
;
967 int n
= sig
->hasthis
+ sig
->param_count
;
968 MonoType
*simpletype
;
969 guint32 stack_size
= 0;
970 CallInfo
*cinfo
= g_malloc0 (sizeof (CallInfo
) + sizeof (ArgInfo
) * n
);
971 gboolean is_pinvoke
= sig
->pinvoke
;
973 fr
= PPC_FIRST_FPARG_REG
;
974 gr
= PPC_FIRST_ARG_REG
;
976 /* FIXME: handle returning a struct */
977 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
978 cinfo
->vtype_retaddr
= TRUE
;
984 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
985 * the first argument, allowing 'this' to be always passed in the first arg reg.
986 * Also do this if the first argument is a reference type, since virtual calls
987 * are sometimes made using calli without sig->hasthis set, like in the delegate
990 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]))))) {
992 add_general (&gr
, &stack_size
, cinfo
->args
+ 0, TRUE
);
995 add_general (&gr
, &stack_size
, &cinfo
->args
[sig
->hasthis
+ 0], TRUE
);
999 add_general (&gr
, &stack_size
, &cinfo
->ret
, TRUE
);
1000 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1001 cinfo
->vret_arg_index
= 1;
1005 add_general (&gr
, &stack_size
, cinfo
->args
+ 0, TRUE
);
1009 if (cinfo
->vtype_retaddr
) {
1010 add_general (&gr
, &stack_size
, &cinfo
->ret
, TRUE
);
1011 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1015 DEBUG(printf("params: %d\n", sig
->param_count
));
1016 for (i
= pstart
; i
< sig
->param_count
; ++i
) {
1017 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1018 /* Prevent implicit arguments and sig_cookie from
1019 being passed in registers */
1020 gr
= PPC_LAST_ARG_REG
+ 1;
1021 /* FIXME: don't we have to set fr, too? */
1022 /* Emit the signature cookie just before the implicit arguments */
1023 add_general (&gr
, &stack_size
, &cinfo
->sig_cookie
, TRUE
);
1025 DEBUG(printf("param %d: ", i
));
1026 if (sig
->params
[i
]->byref
) {
1027 DEBUG(printf("byref\n"));
1028 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1032 simpletype
= mini_type_get_underlying_type (NULL
, sig
->params
[i
]);
1033 switch (simpletype
->type
) {
1034 case MONO_TYPE_BOOLEAN
:
1037 cinfo
->args
[n
].size
= 1;
1038 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1041 case MONO_TYPE_CHAR
:
1044 cinfo
->args
[n
].size
= 2;
1045 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1050 cinfo
->args
[n
].size
= 4;
1051 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1057 case MONO_TYPE_FNPTR
:
1058 case MONO_TYPE_CLASS
:
1059 case MONO_TYPE_OBJECT
:
1060 case MONO_TYPE_STRING
:
1061 case MONO_TYPE_SZARRAY
:
1062 case MONO_TYPE_ARRAY
:
1063 cinfo
->args
[n
].size
= sizeof (gpointer
);
1064 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1067 case MONO_TYPE_GENERICINST
:
1068 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1069 cinfo
->args
[n
].size
= sizeof (gpointer
);
1070 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1075 case MONO_TYPE_VALUETYPE
:
1076 case MONO_TYPE_TYPEDBYREF
: {
1080 klass
= mono_class_from_mono_type (sig
->params
[i
]);
1081 if (simpletype
->type
== MONO_TYPE_TYPEDBYREF
)
1082 size
= sizeof (MonoTypedRef
);
1083 else if (is_pinvoke
)
1084 size
= mono_class_native_size (klass
, NULL
);
1086 size
= mono_class_value_size (klass
, NULL
);
1088 #if defined(__APPLE__) || defined(__mono_ppc64__)
1089 if ((size
== 4 || size
== 8) && has_only_a_r48_field (klass
)) {
1090 cinfo
->args
[n
].size
= size
;
1092 /* It was 7, now it is 8 in LinuxPPC */
1093 if (fr
<= PPC_LAST_FPARG_REG
) {
1094 cinfo
->args
[n
].regtype
= RegTypeFP
;
1095 cinfo
->args
[n
].reg
= fr
;
1097 FP_ALSO_IN_REG (gr
++);
1099 FP_ALSO_IN_REG (gr
++);
1100 ALWAYS_ON_STACK (stack_size
+= size
);
1102 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
1103 cinfo
->args
[n
].regtype
= RegTypeBase
;
1104 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
1111 DEBUG(printf ("load %d bytes struct\n",
1112 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
)));
1114 #if PPC_PASS_STRUCTS_BY_VALUE
1116 int align_size
= size
;
1118 int rest
= PPC_LAST_ARG_REG
- gr
+ 1;
1121 align_size
+= (sizeof (gpointer
) - 1);
1122 align_size
&= ~(sizeof (gpointer
) - 1);
1123 nregs
= (align_size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
1124 n_in_regs
= MIN (rest
, nregs
);
1128 /* FIXME: check this */
1129 if (size
>= 3 && size
% 4 != 0)
1132 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
1133 cinfo
->args
[n
].vtregs
= n_in_regs
;
1134 cinfo
->args
[n
].size
= n_in_regs
;
1135 cinfo
->args
[n
].vtsize
= nregs
- n_in_regs
;
1136 cinfo
->args
[n
].reg
= gr
;
1138 #ifdef __mono_ppc64__
1139 if (nregs
== 1 && is_pinvoke
)
1140 cinfo
->args
[n
].bytes
= size
;
1143 cinfo
->args
[n
].bytes
= 0;
1145 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
1146 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1147 stack_size
+= nregs
* sizeof (gpointer
);
1150 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1151 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
1152 cinfo
->args
[n
].vtsize
= size
;
1159 cinfo
->args
[n
].size
= 8;
1160 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, SIZEOF_REGISTER
== 8);
1164 cinfo
->args
[n
].size
= 4;
1166 /* It was 7, now it is 8 in LinuxPPC */
1167 if (fr
<= PPC_LAST_FPARG_REG
) {
1168 cinfo
->args
[n
].regtype
= RegTypeFP
;
1169 cinfo
->args
[n
].reg
= fr
;
1171 FP_ALSO_IN_REG (gr
++);
1172 ALWAYS_ON_STACK (stack_size
+= SIZEOF_REGISTER
);
1174 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
+ MONO_PPC_32_64_CASE (0, 4);
1175 cinfo
->args
[n
].regtype
= RegTypeBase
;
1176 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
1177 stack_size
+= SIZEOF_REGISTER
;
1182 cinfo
->args
[n
].size
= 8;
1183 /* It was 7, now it is 8 in LinuxPPC */
1184 if (fr
<= PPC_LAST_FPARG_REG
) {
1185 cinfo
->args
[n
].regtype
= RegTypeFP
;
1186 cinfo
->args
[n
].reg
= fr
;
1188 FP_ALSO_IN_REG (gr
+= sizeof (double) / SIZEOF_REGISTER
);
1189 ALWAYS_ON_STACK (stack_size
+= 8);
1191 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
1192 cinfo
->args
[n
].regtype
= RegTypeBase
;
1193 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
1199 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1204 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1205 /* Prevent implicit arguments and sig_cookie from
1206 being passed in registers */
1207 gr
= PPC_LAST_ARG_REG
+ 1;
1208 /* Emit the signature cookie just before the implicit arguments */
1209 add_general (&gr
, &stack_size
, &cinfo
->sig_cookie
, TRUE
);
1213 simpletype
= mini_type_get_underlying_type (NULL
, sig
->ret
);
1214 switch (simpletype
->type
) {
1215 case MONO_TYPE_BOOLEAN
:
1220 case MONO_TYPE_CHAR
:
1226 case MONO_TYPE_FNPTR
:
1227 case MONO_TYPE_CLASS
:
1228 case MONO_TYPE_OBJECT
:
1229 case MONO_TYPE_SZARRAY
:
1230 case MONO_TYPE_ARRAY
:
1231 case MONO_TYPE_STRING
:
1232 cinfo
->ret
.reg
= ppc_r3
;
1236 cinfo
->ret
.reg
= ppc_r3
;
1240 cinfo
->ret
.reg
= ppc_f1
;
1241 cinfo
->ret
.regtype
= RegTypeFP
;
1243 case MONO_TYPE_GENERICINST
:
1244 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1245 cinfo
->ret
.reg
= ppc_r3
;
1249 case MONO_TYPE_VALUETYPE
:
1251 case MONO_TYPE_TYPEDBYREF
:
1252 case MONO_TYPE_VOID
:
1255 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1259 /* align stack size to 16 */
1260 DEBUG (printf (" stack size: %d (%d)\n", (stack_size
+ 15) & ~15, stack_size
));
1261 stack_size
= (stack_size
+ 15) & ~15;
1263 cinfo
->stack_usage
= stack_size
;
1267 G_GNUC_UNUSED
static void
1272 G_GNUC_UNUSED
static gboolean
1275 static int count
= 0;
1278 if (!getenv ("COUNT"))
1281 if (count
== atoi (getenv ("COUNT"))) {
1285 if (count
> atoi (getenv ("COUNT"))) {
1293 mono_ppc_tail_call_supported (MonoMethodSignature
*caller_sig
, MonoMethodSignature
*callee_sig
)
1299 c1
= get_call_info (NULL
, caller_sig
);
1300 c2
= get_call_info (NULL
, callee_sig
);
1301 res
= c1
->stack_usage
>= c2
->stack_usage
;
1302 if (callee_sig
->ret
&& MONO_TYPE_ISSTRUCT (callee_sig
->ret
))
1303 /* An address on the callee's stack is passed as the first argument */
1305 for (i
= 0; i
< c2
->nargs
; ++i
) {
1306 if (c2
->args
[i
].regtype
== RegTypeStructByAddr
)
1307 /* An address on the callee's stack is passed as the argument */
1312 if (!debug_count ())
1323 * Set var information according to the calling convention. ppc version.
1324 * The locals var stuff should most likely be split in another method.
1327 mono_arch_allocate_vars (MonoCompile
*m
)
1329 MonoMethodSignature
*sig
;
1330 MonoMethodHeader
*header
;
1332 int i
, offset
, size
, align
, curinst
;
1333 int frame_reg
= ppc_sp
;
1335 guint32 locals_stack_size
, locals_stack_align
;
1337 m
->flags
|= MONO_CFG_HAS_SPILLUP
;
1339 /* allow room for the vararg method args: void* and long/double */
1340 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (m
->method
))
1341 m
->param_area
= MAX (m
->param_area
, sizeof (gpointer
)*8);
1342 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1343 * call convs needs to be handled this way.
1345 if (m
->flags
& MONO_CFG_HAS_VARARGS
)
1346 m
->param_area
= MAX (m
->param_area
, sizeof (gpointer
)*8);
1347 /* gtk-sharp and other broken code will dllimport vararg functions even with
1348 * non-varargs signatures. Since there is little hope people will get this right
1349 * we assume they won't.
1351 if (m
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1352 m
->param_area
= MAX (m
->param_area
, sizeof (gpointer
)*8);
1357 * We use the frame register also for any method that has
1358 * exception clauses. This way, when the handlers are called,
1359 * the code will reference local variables using the frame reg instead of
1360 * the stack pointer: if we had to restore the stack pointer, we'd
1361 * corrupt the method frames that are already on the stack (since
1362 * filters get called before stack unwinding happens) when the filter
1363 * code would call any method (this also applies to finally etc.).
1365 if ((m
->flags
& MONO_CFG_HAS_ALLOCA
) || header
->num_clauses
)
1366 frame_reg
= ppc_r31
;
1367 m
->frame_reg
= frame_reg
;
1368 if (frame_reg
!= ppc_sp
) {
1369 m
->used_int_regs
|= 1 << frame_reg
;
1372 sig
= mono_method_signature (m
->method
);
1376 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1377 m
->ret
->opcode
= OP_REGVAR
;
1378 m
->ret
->inst_c0
= m
->ret
->dreg
= ppc_r3
;
1380 /* FIXME: handle long values? */
1381 switch (mini_type_get_underlying_type (m
->generic_sharing_context
, sig
->ret
)->type
) {
1382 case MONO_TYPE_VOID
:
1386 m
->ret
->opcode
= OP_REGVAR
;
1387 m
->ret
->inst_c0
= m
->ret
->dreg
= ppc_f1
;
1390 m
->ret
->opcode
= OP_REGVAR
;
1391 m
->ret
->inst_c0
= m
->ret
->dreg
= ppc_r3
;
1395 /* local vars are at a positive offset from the stack pointer */
1397 * also note that if the function uses alloca, we use ppc_r31
1398 * to point at the local variables.
1400 offset
= PPC_MINIMAL_STACK_SIZE
; /* linkage area */
1401 /* align the offset to 16 bytes: not sure this is needed here */
1403 //offset &= ~(16 - 1);
1405 /* add parameter area size for called functions */
1406 offset
+= m
->param_area
;
1408 offset
&= ~(16 - 1);
1410 /* allow room to save the return value */
1411 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (m
->method
))
1414 /* the MonoLMF structure is stored just below the stack pointer */
1417 /* this stuff should not be needed on ppc and the new jit,
1418 * because a call on ppc to the handlers doesn't change the
1419 * stack pointer and the jist doesn't manipulate the stack pointer
1420 * for operations involving valuetypes.
1422 /* reserve space to store the esp */
1423 offset
+= sizeof (gpointer
);
1425 /* this is a global constant */
1426 mono_exc_esp_offset
= offset
;
1429 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1430 offset
+= sizeof(gpointer
) - 1;
1431 offset
&= ~(sizeof(gpointer
) - 1);
1433 m
->vret_addr
->opcode
= OP_REGOFFSET
;
1434 m
->vret_addr
->inst_basereg
= frame_reg
;
1435 m
->vret_addr
->inst_offset
= offset
;
1437 if (G_UNLIKELY (m
->verbose_level
> 1)) {
1438 printf ("vret_addr =");
1439 mono_print_ins (m
->vret_addr
);
1442 offset
+= sizeof(gpointer
);
1445 offsets
= mono_allocate_stack_slots (m
, FALSE
, &locals_stack_size
, &locals_stack_align
);
1446 if (locals_stack_align
) {
1447 offset
+= (locals_stack_align
- 1);
1448 offset
&= ~(locals_stack_align
- 1);
1450 for (i
= m
->locals_start
; i
< m
->num_varinfo
; i
++) {
1451 if (offsets
[i
] != -1) {
1452 MonoInst
*inst
= m
->varinfo
[i
];
1453 inst
->opcode
= OP_REGOFFSET
;
1454 inst
->inst_basereg
= frame_reg
;
1455 inst
->inst_offset
= offset
+ offsets
[i
];
1457 g_print ("allocating local %d (%s) to %d\n",
1458 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1462 offset
+= locals_stack_size
;
1466 inst
= m
->args
[curinst
];
1467 if (inst
->opcode
!= OP_REGVAR
) {
1468 inst
->opcode
= OP_REGOFFSET
;
1469 inst
->inst_basereg
= frame_reg
;
1470 offset
+= sizeof (gpointer
) - 1;
1471 offset
&= ~(sizeof (gpointer
) - 1);
1472 inst
->inst_offset
= offset
;
1473 offset
+= sizeof (gpointer
);
1478 for (i
= 0; i
< sig
->param_count
; ++i
) {
1479 inst
= m
->args
[curinst
];
1480 if (inst
->opcode
!= OP_REGVAR
) {
1481 inst
->opcode
= OP_REGOFFSET
;
1482 inst
->inst_basereg
= frame_reg
;
1484 size
= mono_type_native_stack_size (sig
->params
[i
], (guint32
*)&align
);
1485 inst
->backend
.is_pinvoke
= 1;
1487 size
= mono_type_size (sig
->params
[i
], &align
);
1489 if (MONO_TYPE_ISSTRUCT (sig
->params
[i
]) && size
< sizeof (gpointer
))
1490 size
= align
= sizeof (gpointer
);
1492 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1493 * they are saved using std in the prolog.
1495 align
= sizeof (gpointer
);
1496 offset
+= align
- 1;
1497 offset
&= ~(align
- 1);
1498 inst
->inst_offset
= offset
;
1504 /* some storage for fp conversions */
1507 m
->arch
.fp_conv_var_offset
= offset
;
1510 /* align the offset to 16 bytes */
1512 offset
&= ~(16 - 1);
1515 m
->stack_offset
= offset
;
1517 if (sig
->call_convention
== MONO_CALL_VARARG
) {
1518 CallInfo
*cinfo
= get_call_info (m
->generic_sharing_context
, m
->method
->signature
);
1520 m
->sig_cookie
= cinfo
->sig_cookie
.offset
;
1527 mono_arch_create_vars (MonoCompile
*cfg
)
1529 MonoMethodSignature
*sig
= mono_method_signature (cfg
->method
);
1531 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1532 cfg
->vret_addr
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_ARG
);
1536 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1537 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1541 emit_sig_cookie (MonoCompile
*cfg
, MonoCallInst
*call
, CallInfo
*cinfo
)
1543 int sig_reg
= mono_alloc_ireg (cfg
);
1545 /* FIXME: Add support for signature tokens to AOT */
1546 cfg
->disable_aot
= TRUE
;
1548 MONO_EMIT_NEW_ICONST (cfg
, sig_reg
, (gulong
)call
->signature
);
1549 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
,
1550 ppc_r1
, cinfo
->sig_cookie
.offset
, sig_reg
);
1554 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
1557 MonoMethodSignature
*sig
;
1561 sig
= call
->signature
;
1562 n
= sig
->param_count
+ sig
->hasthis
;
1564 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
);
1566 for (i
= 0; i
< n
; ++i
) {
1567 ArgInfo
*ainfo
= cinfo
->args
+ i
;
1570 if (i
>= sig
->hasthis
)
1571 t
= sig
->params
[i
- sig
->hasthis
];
1573 t
= &mono_defaults
.int_class
->byval_arg
;
1574 t
= mini_type_get_underlying_type (cfg
->generic_sharing_context
, t
);
1576 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
))
1577 emit_sig_cookie (cfg
, call
, cinfo
);
1579 in
= call
->args
[i
];
1581 if (ainfo
->regtype
== RegTypeGeneral
) {
1582 #ifndef __mono_ppc64__
1583 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1584 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1585 ins
->dreg
= mono_alloc_ireg (cfg
);
1586 ins
->sreg1
= in
->dreg
+ 1;
1587 MONO_ADD_INS (cfg
->cbb
, ins
);
1588 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ 1, FALSE
);
1590 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1591 ins
->dreg
= mono_alloc_ireg (cfg
);
1592 ins
->sreg1
= in
->dreg
+ 2;
1593 MONO_ADD_INS (cfg
->cbb
, ins
);
1594 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1598 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1599 ins
->dreg
= mono_alloc_ireg (cfg
);
1600 ins
->sreg1
= in
->dreg
;
1601 MONO_ADD_INS (cfg
->cbb
, ins
);
1603 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1605 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
1606 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1607 ins
->opcode
= OP_OUTARG_VT
;
1608 ins
->sreg1
= in
->dreg
;
1609 ins
->klass
= in
->klass
;
1610 ins
->inst_p0
= call
;
1611 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1612 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1613 MONO_ADD_INS (cfg
->cbb
, ins
);
1614 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
1615 /* this is further handled in mono_arch_emit_outarg_vt () */
1616 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1617 ins
->opcode
= OP_OUTARG_VT
;
1618 ins
->sreg1
= in
->dreg
;
1619 ins
->klass
= in
->klass
;
1620 ins
->inst_p0
= call
;
1621 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1622 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1623 MONO_ADD_INS (cfg
->cbb
, ins
);
1624 } else if (ainfo
->regtype
== RegTypeBase
) {
1625 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1626 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1627 } else if (!t
->byref
&& ((t
->type
== MONO_TYPE_R4
) || (t
->type
== MONO_TYPE_R8
))) {
1628 if (t
->type
== MONO_TYPE_R8
)
1629 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1631 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1633 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1635 } else if (ainfo
->regtype
== RegTypeFP
) {
1636 if (t
->type
== MONO_TYPE_VALUETYPE
) {
1637 /* this is further handled in mono_arch_emit_outarg_vt () */
1638 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1639 ins
->opcode
= OP_OUTARG_VT
;
1640 ins
->sreg1
= in
->dreg
;
1641 ins
->klass
= in
->klass
;
1642 ins
->inst_p0
= call
;
1643 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1644 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1645 MONO_ADD_INS (cfg
->cbb
, ins
);
1647 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1649 int dreg
= mono_alloc_freg (cfg
);
1651 if (ainfo
->size
== 4) {
1652 MONO_EMIT_NEW_UNALU (cfg
, OP_FCONV_TO_R4
, dreg
, in
->dreg
);
1654 MONO_INST_NEW (cfg
, ins
, OP_FMOVE
);
1656 ins
->sreg1
= in
->dreg
;
1657 MONO_ADD_INS (cfg
->cbb
, ins
);
1660 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1661 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1664 g_assert_not_reached ();
1668 /* Emit the signature cookie in the case that there is no
1669 additional argument */
1670 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== sig
->sentinelpos
))
1671 emit_sig_cookie (cfg
, call
, cinfo
);
1673 if (cinfo
->struct_ret
) {
1676 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
1677 vtarg
->sreg1
= call
->vret_var
->dreg
;
1678 vtarg
->dreg
= mono_alloc_preg (cfg
);
1679 MONO_ADD_INS (cfg
->cbb
, vtarg
);
1681 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
, cinfo
->struct_ret
, FALSE
);
1684 call
->stack_usage
= cinfo
->stack_usage
;
1685 cfg
->param_area
= MAX (PPC_MINIMAL_PARAM_AREA_SIZE
, MAX (cfg
->param_area
, cinfo
->stack_usage
));
1686 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1694 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
1696 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p0
;
1697 ArgInfo
*ainfo
= ins
->inst_p1
;
1698 int ovf_size
= ainfo
->vtsize
;
1699 int doffset
= ainfo
->offset
;
1700 int i
, soffset
, dreg
;
1702 if (ainfo
->regtype
== RegTypeStructByVal
) {
1709 * Darwin pinvokes needs some special handling for 1
1710 * and 2 byte arguments
1712 g_assert (ins
->klass
);
1713 if (call
->signature
->pinvoke
)
1714 size
= mono_class_native_size (ins
->klass
, NULL
);
1715 if (size
== 2 || size
== 1) {
1716 int tmpr
= mono_alloc_ireg (cfg
);
1718 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI1_MEMBASE
, tmpr
, src
->dreg
, soffset
);
1720 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI2_MEMBASE
, tmpr
, src
->dreg
, soffset
);
1721 dreg
= mono_alloc_ireg (cfg
);
1722 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, dreg
, tmpr
);
1723 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, FALSE
);
1726 for (i
= 0; i
< ainfo
->vtregs
; ++i
) {
1727 int antipadding
= 0;
1730 antipadding
= sizeof (gpointer
) - ainfo
->bytes
;
1732 dreg
= mono_alloc_ireg (cfg
);
1733 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1735 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_UN_IMM
, dreg
, dreg
, antipadding
* 8);
1736 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+ i
, FALSE
);
1737 soffset
+= sizeof (gpointer
);
1740 mini_emit_memcpy (cfg
, ppc_r1
, doffset
+ soffset
, src
->dreg
, soffset
, ovf_size
* sizeof (gpointer
), 0);
1741 } else if (ainfo
->regtype
== RegTypeFP
) {
1742 int tmpr
= mono_alloc_freg (cfg
);
1743 if (ainfo
->size
== 4)
1744 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, 0);
1746 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, 0);
1747 dreg
= mono_alloc_freg (cfg
);
1748 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1749 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1751 MonoInst
*vtcopy
= mono_compile_create_var (cfg
, &src
->klass
->byval_arg
, OP_LOCAL
);
1755 /* FIXME: alignment? */
1756 if (call
->signature
->pinvoke
) {
1757 size
= mono_type_native_stack_size (&src
->klass
->byval_arg
, NULL
);
1758 vtcopy
->backend
.is_pinvoke
= 1;
1760 size
= mini_type_stack_size (cfg
->generic_sharing_context
, &src
->klass
->byval_arg
, NULL
);
1763 g_assert (ovf_size
> 0);
1765 EMIT_NEW_VARLOADA (cfg
, load
, vtcopy
, vtcopy
->inst_vtype
);
1766 mini_emit_memcpy (cfg
, load
->dreg
, 0, src
->dreg
, 0, size
, 0);
1769 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, load
->dreg
);
1771 mono_call_inst_add_outarg_reg (cfg
, call
, load
->dreg
, ainfo
->reg
, FALSE
);
1776 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
1778 MonoType
*ret
= mini_type_get_underlying_type (cfg
->generic_sharing_context
,
1779 mono_method_signature (method
)->ret
);
1782 #ifndef __mono_ppc64__
1783 if (ret
->type
== MONO_TYPE_I8
|| ret
->type
== MONO_TYPE_U8
) {
1786 MONO_INST_NEW (cfg
, ins
, OP_SETLRET
);
1787 ins
->sreg1
= val
->dreg
+ 1;
1788 ins
->sreg2
= val
->dreg
+ 2;
1789 MONO_ADD_INS (cfg
->cbb
, ins
);
1793 if (ret
->type
== MONO_TYPE_R8
|| ret
->type
== MONO_TYPE_R4
) {
1794 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, cfg
->ret
->dreg
, val
->dreg
);
1798 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, cfg
->ret
->dreg
, val
->dreg
);
1801 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1803 mono_arch_is_inst_imm (gint64 imm
)
1808 #endif /* DISABLE_JIT */
1811 * Allow tracing to work with this interface (with an optional argument)
1815 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
1819 ppc_load_ptr (code
, ppc_r3
, cfg
->method
);
1820 ppc_li (code
, ppc_r4
, 0); /* NULL ebp for now */
1821 ppc_load_func (code
, ppc_r0
, func
);
1822 ppc_mtlr (code
, ppc_r0
);
1836 mono_arch_instrument_epilog_full (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
, gboolean preserve_argument_registers
)
1839 int save_mode
= SAVE_NONE
;
1841 MonoMethod
*method
= cfg
->method
;
1842 int rtype
= mini_type_get_underlying_type (cfg
->generic_sharing_context
,
1843 mono_method_signature (method
)->ret
)->type
;
1844 int save_offset
= PPC_STACK_PARAM_OFFSET
+ cfg
->param_area
;
1848 offset
= code
- cfg
->native_code
;
1849 /* we need about 16 instructions */
1850 if (offset
> (cfg
->code_size
- 16 * 4)) {
1851 cfg
->code_size
*= 2;
1852 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
1853 code
= cfg
->native_code
+ offset
;
1857 case MONO_TYPE_VOID
:
1858 /* special case string .ctor icall */
1859 if (strcmp (".ctor", method
->name
) && method
->klass
== mono_defaults
.string_class
)
1860 save_mode
= SAVE_ONE
;
1862 save_mode
= SAVE_NONE
;
1864 #ifndef __mono_ppc64__
1867 save_mode
= SAVE_TWO
;
1872 save_mode
= SAVE_FP
;
1874 case MONO_TYPE_VALUETYPE
:
1875 save_mode
= SAVE_STRUCT
;
1878 save_mode
= SAVE_ONE
;
1882 switch (save_mode
) {
1884 ppc_stw (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
1885 ppc_stw (code
, ppc_r4
, save_offset
+ 4, cfg
->frame_reg
);
1886 if (enable_arguments
) {
1887 ppc_mr (code
, ppc_r5
, ppc_r4
);
1888 ppc_mr (code
, ppc_r4
, ppc_r3
);
1892 ppc_stptr (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
1893 if (enable_arguments
) {
1894 ppc_mr (code
, ppc_r4
, ppc_r3
);
1898 ppc_stfd (code
, ppc_f1
, save_offset
, cfg
->frame_reg
);
1899 if (enable_arguments
) {
1900 /* FIXME: what reg? */
1901 ppc_fmr (code
, ppc_f3
, ppc_f1
);
1902 /* FIXME: use 8 byte load on PPC64 */
1903 ppc_lwz (code
, ppc_r4
, save_offset
, cfg
->frame_reg
);
1904 ppc_lwz (code
, ppc_r5
, save_offset
+ 4, cfg
->frame_reg
);
1908 if (enable_arguments
) {
1909 /* FIXME: get the actual address */
1910 ppc_mr (code
, ppc_r4
, ppc_r3
);
1918 ppc_load_ptr (code
, ppc_r3
, cfg
->method
);
1919 ppc_load_func (code
, ppc_r0
, func
);
1920 ppc_mtlr (code
, ppc_r0
);
1923 switch (save_mode
) {
1925 ppc_lwz (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
1926 ppc_lwz (code
, ppc_r4
, save_offset
+ 4, cfg
->frame_reg
);
1929 ppc_ldptr (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
1932 ppc_lfd (code
, ppc_f1
, save_offset
, cfg
->frame_reg
);
1942 * Conditional branches have a small offset, so if it is likely overflowed,
1943 * we do a branch to the end of the method (uncond branches have much larger
1944 * offsets) where we perform the conditional and jump back unconditionally.
1945 * It's slightly slower, since we add two uncond branches, but it's very simple
1946 * with the current patch implementation and such large methods are likely not
1947 * going to be perf critical anyway.
1952 const char *exception
;
1959 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1960 if (0 && ins->inst_true_bb->native_offset) { \
1961 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1963 int br_disp = ins->inst_true_bb->max_offset - offset; \
1964 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1965 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1966 ovfj->data.bb = ins->inst_true_bb; \
1967 ovfj->ip_offset = 0; \
1968 ovfj->b0_cond = (b0); \
1969 ovfj->b1_cond = (b1); \
1970 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1973 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1974 ppc_bc (code, (b0), (b1), 0); \
1978 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1980 /* emit an exception if condition is fail
1982 * We assign the extra code used to throw the implicit exceptions
1983 * to cfg->bb_exit as far as the big branch handling is concerned
1985 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1987 int br_disp = cfg->bb_exit->max_offset - offset; \
1988 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1989 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1990 ovfj->data.exception = (exc_name); \
1991 ovfj->ip_offset = code - cfg->native_code; \
1992 ovfj->b0_cond = (b0); \
1993 ovfj->b1_cond = (b1); \
1994 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1996 cfg->bb_exit->max_offset += 24; \
1998 mono_add_patch_info (cfg, code - cfg->native_code, \
1999 MONO_PATCH_INFO_EXC, exc_name); \
2000 ppc_bcl (code, (b0), (b1), 0); \
2004 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2007 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2012 normalize_opcode (int opcode
)
2015 #ifndef __mono_ilp32__
2016 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE
, OP_LOADI8_MEMBASE
):
2017 return OP_LOAD_MEMBASE
;
2018 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX
, OP_LOADI8_MEMINDEX
):
2019 return OP_LOAD_MEMINDEX
;
2020 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG
, OP_STOREI8_MEMBASE_REG
):
2021 return OP_STORE_MEMBASE_REG
;
2022 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM
, OP_STOREI8_MEMBASE_IMM
):
2023 return OP_STORE_MEMBASE_IMM
;
2024 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX
, OP_STOREI8_MEMINDEX
):
2025 return OP_STORE_MEMINDEX
;
2027 case MONO_PPC_32_64_CASE (OP_ISHR_IMM
, OP_LSHR_IMM
):
2029 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM
, OP_LSHR_UN_IMM
):
2030 return OP_SHR_UN_IMM
;
2037 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2039 MonoInst
*ins
, *n
, *last_ins
= NULL
;
2041 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
2042 switch (normalize_opcode (ins
->opcode
)) {
2044 /* remove unnecessary multiplication with 1 */
2045 if (ins
->inst_imm
== 1) {
2046 if (ins
->dreg
!= ins
->sreg1
) {
2047 ins
->opcode
= OP_MOVE
;
2049 MONO_DELETE_INS (bb
, ins
);
2053 int power2
= mono_is_power_of_two (ins
->inst_imm
);
2055 ins
->opcode
= OP_SHL_IMM
;
2056 ins
->inst_imm
= power2
;
2060 case OP_LOAD_MEMBASE
:
2062 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2063 * OP_LOAD_MEMBASE offset(basereg), reg
2065 if (last_ins
&& normalize_opcode (last_ins
->opcode
) == OP_STORE_MEMBASE_REG
&&
2066 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2067 ins
->inst_offset
== last_ins
->inst_offset
) {
2068 if (ins
->dreg
== last_ins
->sreg1
) {
2069 MONO_DELETE_INS (bb
, ins
);
2072 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2073 ins
->opcode
= OP_MOVE
;
2074 ins
->sreg1
= last_ins
->sreg1
;
2078 * Note: reg1 must be different from the basereg in the second load
2079 * OP_LOAD_MEMBASE offset(basereg), reg1
2080 * OP_LOAD_MEMBASE offset(basereg), reg2
2082 * OP_LOAD_MEMBASE offset(basereg), reg1
2083 * OP_MOVE reg1, reg2
2085 } else if (last_ins
&& normalize_opcode (last_ins
->opcode
) == OP_LOAD_MEMBASE
&&
2086 ins
->inst_basereg
!= last_ins
->dreg
&&
2087 ins
->inst_basereg
== last_ins
->inst_basereg
&&
2088 ins
->inst_offset
== last_ins
->inst_offset
) {
2090 if (ins
->dreg
== last_ins
->dreg
) {
2091 MONO_DELETE_INS (bb
, ins
);
2094 ins
->opcode
= OP_MOVE
;
2095 ins
->sreg1
= last_ins
->dreg
;
2098 //g_assert_not_reached ();
2102 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2103 * OP_LOAD_MEMBASE offset(basereg), reg
2105 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2106 * OP_ICONST reg, imm
2108 } else if (last_ins
&& normalize_opcode (last_ins
->opcode
) == OP_STORE_MEMBASE_IMM
&&
2109 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2110 ins
->inst_offset
== last_ins
->inst_offset
) {
2111 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2112 ins
->opcode
= OP_ICONST
;
2113 ins
->inst_c0
= last_ins
->inst_imm
;
2114 g_assert_not_reached (); // check this rule
2118 case OP_LOADU1_MEMBASE
:
2119 case OP_LOADI1_MEMBASE
:
2120 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
2121 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2122 ins
->inst_offset
== last_ins
->inst_offset
) {
2123 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_ICONV_TO_I1
: OP_ICONV_TO_U1
;
2124 ins
->sreg1
= last_ins
->sreg1
;
2127 case OP_LOADU2_MEMBASE
:
2128 case OP_LOADI2_MEMBASE
:
2129 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
2130 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2131 ins
->inst_offset
== last_ins
->inst_offset
) {
2132 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_ICONV_TO_I2
: OP_ICONV_TO_U2
;
2133 ins
->sreg1
= last_ins
->sreg1
;
2136 #ifdef __mono_ppc64__
2137 case OP_LOADU4_MEMBASE
:
2138 case OP_LOADI4_MEMBASE
:
2139 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
) &&
2140 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2141 ins
->inst_offset
== last_ins
->inst_offset
) {
2142 ins
->opcode
= (ins
->opcode
== OP_LOADI4_MEMBASE
) ? OP_ICONV_TO_I4
: OP_ICONV_TO_U4
;
2143 ins
->sreg1
= last_ins
->sreg1
;
2148 ins
->opcode
= OP_MOVE
;
2152 if (ins
->dreg
== ins
->sreg1
) {
2153 MONO_DELETE_INS (bb
, ins
);
2157 * OP_MOVE sreg, dreg
2158 * OP_MOVE dreg, sreg
2160 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
2161 ins
->sreg1
== last_ins
->dreg
&&
2162 ins
->dreg
== last_ins
->sreg1
) {
2163 MONO_DELETE_INS (bb
, ins
);
2171 bb
->last_ins
= last_ins
;
2175 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2177 switch (ins
->opcode
) {
2178 case OP_ICONV_TO_R_UN
: {
2179 #if G_BYTE_ORDER == G_BIG_ENDIAN
2180 static const guint64 adjust_val
= 0x4330000000000000ULL
;
2182 static const guint64 adjust_val
= 0x0000000000003043ULL
;
2184 int msw_reg
= mono_alloc_ireg (cfg
);
2185 int adj_reg
= mono_alloc_freg (cfg
);
2186 int tmp_reg
= mono_alloc_freg (cfg
);
2187 int basereg
= ppc_sp
;
2189 MONO_EMIT_NEW_ICONST (cfg
, msw_reg
, 0x43300000);
2190 if (!ppc_is_imm16 (offset
+ 4)) {
2191 basereg
= mono_alloc_ireg (cfg
);
2192 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, basereg
, cfg
->frame_reg
, offset
);
2194 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
, msw_reg
);
2195 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
+ 4, ins
->sreg1
);
2196 MONO_EMIT_NEW_LOAD_R8 (cfg
, adj_reg
, &adjust_val
);
2197 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmp_reg
, basereg
, offset
);
2198 MONO_EMIT_NEW_BIALU (cfg
, OP_FSUB
, ins
->dreg
, tmp_reg
, adj_reg
);
2199 ins
->opcode
= OP_NOP
;
2202 #ifndef __mono_ppc64__
2203 case OP_ICONV_TO_R4
:
2204 case OP_ICONV_TO_R8
: {
2205 /* If we have a PPC_FEATURE_64 machine we can avoid
2206 this and use the fcfid instruction. Otherwise
2207 on an old 32-bit chip and we have to do this the
2209 if (!(cpu_hw_caps
& PPC_ISA_64
)) {
2210 /* FIXME: change precision for CEE_CONV_R4 */
2211 static const guint64 adjust_val
= 0x4330000080000000ULL
;
2212 int msw_reg
= mono_alloc_ireg (cfg
);
2213 int xored
= mono_alloc_ireg (cfg
);
2214 int adj_reg
= mono_alloc_freg (cfg
);
2215 int tmp_reg
= mono_alloc_freg (cfg
);
2216 int basereg
= ppc_sp
;
2218 if (!ppc_is_imm16 (offset
+ 4)) {
2219 basereg
= mono_alloc_ireg (cfg
);
2220 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, basereg
, cfg
->frame_reg
, offset
);
2222 MONO_EMIT_NEW_ICONST (cfg
, msw_reg
, 0x43300000);
2223 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
, msw_reg
);
2224 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, xored
, ins
->sreg1
, 0x80000000);
2225 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
+ 4, xored
);
2226 MONO_EMIT_NEW_LOAD_R8 (cfg
, adj_reg
, (gpointer
)&adjust_val
);
2227 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmp_reg
, basereg
, offset
);
2228 MONO_EMIT_NEW_BIALU (cfg
, OP_FSUB
, ins
->dreg
, tmp_reg
, adj_reg
);
2229 if (ins
->opcode
== OP_ICONV_TO_R4
)
2230 MONO_EMIT_NEW_UNALU (cfg
, OP_FCONV_TO_R4
, ins
->dreg
, ins
->dreg
);
2231 ins
->opcode
= OP_NOP
;
2237 int msw_reg
= mono_alloc_ireg (cfg
);
2238 int basereg
= ppc_sp
;
2240 if (!ppc_is_imm16 (offset
+ 4)) {
2241 basereg
= mono_alloc_ireg (cfg
);
2242 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, basereg
, cfg
->frame_reg
, offset
);
2244 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, basereg
, offset
, ins
->sreg1
);
2245 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, msw_reg
, basereg
, offset
);
2246 MONO_EMIT_NEW_UNALU (cfg
, OP_CHECK_FINITE
, -1, msw_reg
);
2247 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, ins
->dreg
, ins
->sreg1
);
2248 ins
->opcode
= OP_NOP
;
2251 #ifdef __mono_ppc64__
2253 case OP_IADD_OVF_UN
:
2255 int shifted1_reg
= mono_alloc_ireg (cfg
);
2256 int shifted2_reg
= mono_alloc_ireg (cfg
);
2257 int result_shifted_reg
= mono_alloc_ireg (cfg
);
2259 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHL_IMM
, shifted1_reg
, ins
->sreg1
, 32);
2260 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHL_IMM
, shifted2_reg
, ins
->sreg2
, 32);
2261 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, result_shifted_reg
, shifted1_reg
, shifted2_reg
);
2262 if (ins
->opcode
== OP_IADD_OVF_UN
)
2263 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_UN_IMM
, ins
->dreg
, result_shifted_reg
, 32);
2265 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, ins
->dreg
, result_shifted_reg
, 32);
2266 ins
->opcode
= OP_NOP
;
2273 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2275 switch (ins
->opcode
) {
2277 /* ADC sets the condition code */
2278 MONO_EMIT_NEW_BIALU (cfg
, OP_ADDCC
, ins
->dreg
+ 1, ins
->sreg1
+ 1, ins
->sreg2
+ 1);
2279 MONO_EMIT_NEW_BIALU (cfg
, OP_ADD_OVF_CARRY
, ins
->dreg
+ 2, ins
->sreg1
+ 2, ins
->sreg2
+ 2);
2282 case OP_LADD_OVF_UN
:
2283 /* ADC sets the condition code */
2284 MONO_EMIT_NEW_BIALU (cfg
, OP_ADDCC
, ins
->dreg
+ 1, ins
->sreg1
+ 1, ins
->sreg2
+ 1);
2285 MONO_EMIT_NEW_BIALU (cfg
, OP_ADD_OVF_UN_CARRY
, ins
->dreg
+ 2, ins
->sreg1
+ 2, ins
->sreg2
+ 2);
2289 /* SBB sets the condition code */
2290 MONO_EMIT_NEW_BIALU (cfg
, OP_SUBCC
, ins
->dreg
+ 1, ins
->sreg1
+ 1, ins
->sreg2
+ 1);
2291 MONO_EMIT_NEW_BIALU (cfg
, OP_SUB_OVF_CARRY
, ins
->dreg
+ 2, ins
->sreg1
+ 2, ins
->sreg2
+ 2);
2294 case OP_LSUB_OVF_UN
:
2295 /* SBB sets the condition code */
2296 MONO_EMIT_NEW_BIALU (cfg
, OP_SUBCC
, ins
->dreg
+ 1, ins
->sreg1
+ 1, ins
->sreg2
+ 1);
2297 MONO_EMIT_NEW_BIALU (cfg
, OP_SUB_OVF_UN_CARRY
, ins
->dreg
+ 2, ins
->sreg1
+ 2, ins
->sreg2
+ 2);
2301 /* From gcc generated code */
2302 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_PPC_SUBFIC
, ins
->dreg
+ 1, ins
->sreg1
+ 1, 0);
2303 MONO_EMIT_NEW_UNALU (cfg
, OP_PPC_SUBFZE
, ins
->dreg
+ 2, ins
->sreg1
+ 2);
2312 * the branch_b0_table should maintain the order of these
2326 branch_b0_table
[] = {
2341 branch_b1_table
[] = {
2355 #define NEW_INS(cfg,dest,op) do { \
2356 MONO_INST_NEW((cfg), (dest), (op)); \
2357 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2361 map_to_reg_reg_op (int op
)
2370 case OP_COMPARE_IMM
:
2372 case OP_ICOMPARE_IMM
:
2374 case OP_LCOMPARE_IMM
:
2390 case OP_LOAD_MEMBASE
:
2391 return OP_LOAD_MEMINDEX
;
2392 case OP_LOADI4_MEMBASE
:
2393 return OP_LOADI4_MEMINDEX
;
2394 case OP_LOADU4_MEMBASE
:
2395 return OP_LOADU4_MEMINDEX
;
2396 case OP_LOADI8_MEMBASE
:
2397 return OP_LOADI8_MEMINDEX
;
2398 case OP_LOADU1_MEMBASE
:
2399 return OP_LOADU1_MEMINDEX
;
2400 case OP_LOADI2_MEMBASE
:
2401 return OP_LOADI2_MEMINDEX
;
2402 case OP_LOADU2_MEMBASE
:
2403 return OP_LOADU2_MEMINDEX
;
2404 case OP_LOADI1_MEMBASE
:
2405 return OP_LOADI1_MEMINDEX
;
2406 case OP_LOADR4_MEMBASE
:
2407 return OP_LOADR4_MEMINDEX
;
2408 case OP_LOADR8_MEMBASE
:
2409 return OP_LOADR8_MEMINDEX
;
2410 case OP_STOREI1_MEMBASE_REG
:
2411 return OP_STOREI1_MEMINDEX
;
2412 case OP_STOREI2_MEMBASE_REG
:
2413 return OP_STOREI2_MEMINDEX
;
2414 case OP_STOREI4_MEMBASE_REG
:
2415 return OP_STOREI4_MEMINDEX
;
2416 case OP_STOREI8_MEMBASE_REG
:
2417 return OP_STOREI8_MEMINDEX
;
2418 case OP_STORE_MEMBASE_REG
:
2419 return OP_STORE_MEMINDEX
;
2420 case OP_STORER4_MEMBASE_REG
:
2421 return OP_STORER4_MEMINDEX
;
2422 case OP_STORER8_MEMBASE_REG
:
2423 return OP_STORER8_MEMINDEX
;
2424 case OP_STORE_MEMBASE_IMM
:
2425 return OP_STORE_MEMBASE_REG
;
2426 case OP_STOREI1_MEMBASE_IMM
:
2427 return OP_STOREI1_MEMBASE_REG
;
2428 case OP_STOREI2_MEMBASE_IMM
:
2429 return OP_STOREI2_MEMBASE_REG
;
2430 case OP_STOREI4_MEMBASE_IMM
:
2431 return OP_STOREI4_MEMBASE_REG
;
2432 case OP_STOREI8_MEMBASE_IMM
:
2433 return OP_STOREI8_MEMBASE_REG
;
2435 return mono_op_imm_to_op (op
);
2438 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2440 #define compare_opcode_is_unsigned(opcode) \
2441 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2442 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2443 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2444 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2445 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2446 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2447 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2448 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2451 * Remove from the instruction list the instructions that can't be
2452 * represented with very simple instructions with no register
2456 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2458 MonoInst
*ins
, *next
, *temp
, *last_ins
= NULL
;
2461 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2463 switch (ins
->opcode
) {
2464 case OP_IDIV_UN_IMM
:
2467 case OP_IREM_UN_IMM
:
2468 NEW_INS (cfg
, temp
, OP_ICONST
);
2469 temp
->inst_c0
= ins
->inst_imm
;
2470 temp
->dreg
= mono_alloc_ireg (cfg
);
2471 ins
->sreg2
= temp
->dreg
;
2472 if (ins
->opcode
== OP_IDIV_IMM
)
2473 ins
->opcode
= OP_IDIV
;
2474 else if (ins
->opcode
== OP_IREM_IMM
)
2475 ins
->opcode
= OP_IREM
;
2476 else if (ins
->opcode
== OP_IDIV_UN_IMM
)
2477 ins
->opcode
= OP_IDIV_UN
;
2478 else if (ins
->opcode
== OP_IREM_UN_IMM
)
2479 ins
->opcode
= OP_IREM_UN
;
2481 /* handle rem separately */
2485 CASE_PPC64 (OP_LREM
)
2486 CASE_PPC64 (OP_LREM_UN
) {
2488 /* we change a rem dest, src1, src2 to
2489 * div temp1, src1, src2
2490 * mul temp2, temp1, src2
2491 * sub dest, src1, temp2
2493 if (ins
->opcode
== OP_IREM
|| ins
->opcode
== OP_IREM_UN
) {
2494 NEW_INS (cfg
, mul
, OP_IMUL
);
2495 NEW_INS (cfg
, temp
, ins
->opcode
== OP_IREM
? OP_IDIV
: OP_IDIV_UN
);
2496 ins
->opcode
= OP_ISUB
;
2498 NEW_INS (cfg
, mul
, OP_LMUL
);
2499 NEW_INS (cfg
, temp
, ins
->opcode
== OP_LREM
? OP_LDIV
: OP_LDIV_UN
);
2500 ins
->opcode
= OP_LSUB
;
2502 temp
->sreg1
= ins
->sreg1
;
2503 temp
->sreg2
= ins
->sreg2
;
2504 temp
->dreg
= mono_alloc_ireg (cfg
);
2505 mul
->sreg1
= temp
->dreg
;
2506 mul
->sreg2
= ins
->sreg2
;
2507 mul
->dreg
= mono_alloc_ireg (cfg
);
2508 ins
->sreg2
= mul
->dreg
;
2512 CASE_PPC64 (OP_LADD_IMM
)
2515 if (!ppc_is_imm16 (ins
->inst_imm
)) {
2516 NEW_INS (cfg
, temp
, OP_ICONST
);
2517 temp
->inst_c0
= ins
->inst_imm
;
2518 temp
->dreg
= mono_alloc_ireg (cfg
);
2519 ins
->sreg2
= temp
->dreg
;
2520 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2524 CASE_PPC64 (OP_LSUB_IMM
)
2526 if (!ppc_is_imm16 (-ins
->inst_imm
)) {
2527 NEW_INS (cfg
, temp
, OP_ICONST
);
2528 temp
->inst_c0
= ins
->inst_imm
;
2529 temp
->dreg
= mono_alloc_ireg (cfg
);
2530 ins
->sreg2
= temp
->dreg
;
2531 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2543 gboolean is_imm
= ((ins
->inst_imm
& 0xffff0000) && (ins
->inst_imm
& 0xffff));
2544 #ifdef __mono_ppc64__
2545 if (ins
->inst_imm
& 0xffffffff00000000ULL
)
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
);
2562 NEW_INS (cfg
, temp
, OP_ICONST
);
2563 temp
->inst_c0
= ins
->inst_imm
;
2564 temp
->dreg
= mono_alloc_ireg (cfg
);
2565 ins
->sreg2
= temp
->dreg
;
2566 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2568 case OP_COMPARE_IMM
:
2569 case OP_ICOMPARE_IMM
:
2570 CASE_PPC64 (OP_LCOMPARE_IMM
)
2572 /* Branch opts can eliminate the branch */
2573 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2574 ins
->opcode
= OP_NOP
;
2578 if (compare_opcode_is_unsigned (next
->opcode
)) {
2579 if (!ppc_is_uimm16 (ins
->inst_imm
)) {
2580 NEW_INS (cfg
, temp
, OP_ICONST
);
2581 temp
->inst_c0
= ins
->inst_imm
;
2582 temp
->dreg
= mono_alloc_ireg (cfg
);
2583 ins
->sreg2
= temp
->dreg
;
2584 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2587 if (!ppc_is_imm16 (ins
->inst_imm
)) {
2588 NEW_INS (cfg
, temp
, OP_ICONST
);
2589 temp
->inst_c0
= ins
->inst_imm
;
2590 temp
->dreg
= mono_alloc_ireg (cfg
);
2591 ins
->sreg2
= temp
->dreg
;
2592 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2598 if (ins
->inst_imm
== 1) {
2599 ins
->opcode
= OP_MOVE
;
2602 if (ins
->inst_imm
== 0) {
2603 ins
->opcode
= OP_ICONST
;
2607 imm
= mono_is_power_of_two (ins
->inst_imm
);
2609 ins
->opcode
= OP_SHL_IMM
;
2610 ins
->inst_imm
= imm
;
2613 if (!ppc_is_imm16 (ins
->inst_imm
)) {
2614 NEW_INS (cfg
, temp
, OP_ICONST
);
2615 temp
->inst_c0
= ins
->inst_imm
;
2616 temp
->dreg
= mono_alloc_ireg (cfg
);
2617 ins
->sreg2
= temp
->dreg
;
2618 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2621 case OP_LOCALLOC_IMM
:
2622 NEW_INS (cfg
, temp
, OP_ICONST
);
2623 temp
->inst_c0
= ins
->inst_imm
;
2624 temp
->dreg
= mono_alloc_ireg (cfg
);
2625 ins
->sreg1
= temp
->dreg
;
2626 ins
->opcode
= OP_LOCALLOC
;
2628 case OP_LOAD_MEMBASE
:
2629 case OP_LOADI4_MEMBASE
:
2630 CASE_PPC64 (OP_LOADI8_MEMBASE
)
2631 case OP_LOADU4_MEMBASE
:
2632 case OP_LOADI2_MEMBASE
:
2633 case OP_LOADU2_MEMBASE
:
2634 case OP_LOADI1_MEMBASE
:
2635 case OP_LOADU1_MEMBASE
:
2636 case OP_LOADR4_MEMBASE
:
2637 case OP_LOADR8_MEMBASE
:
2638 case OP_STORE_MEMBASE_REG
:
2639 CASE_PPC64 (OP_STOREI8_MEMBASE_REG
)
2640 case OP_STOREI4_MEMBASE_REG
:
2641 case OP_STOREI2_MEMBASE_REG
:
2642 case OP_STOREI1_MEMBASE_REG
:
2643 case OP_STORER4_MEMBASE_REG
:
2644 case OP_STORER8_MEMBASE_REG
:
2645 /* we can do two things: load the immed in a register
2646 * and use an indexed load, or see if the immed can be
2647 * represented as an ad_imm + a load with a smaller offset
2648 * that fits. We just do the first for now, optimize later.
2650 if (ppc_is_imm16 (ins
->inst_offset
))
2652 NEW_INS (cfg
, temp
, OP_ICONST
);
2653 temp
->inst_c0
= ins
->inst_offset
;
2654 temp
->dreg
= mono_alloc_ireg (cfg
);
2655 ins
->sreg2
= temp
->dreg
;
2656 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2658 case OP_STORE_MEMBASE_IMM
:
2659 case OP_STOREI1_MEMBASE_IMM
:
2660 case OP_STOREI2_MEMBASE_IMM
:
2661 case OP_STOREI4_MEMBASE_IMM
:
2662 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM
)
2663 NEW_INS (cfg
, temp
, OP_ICONST
);
2664 temp
->inst_c0
= ins
->inst_imm
;
2665 temp
->dreg
= mono_alloc_ireg (cfg
);
2666 ins
->sreg1
= temp
->dreg
;
2667 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2669 goto loop_start
; /* make it handle the possibly big ins->inst_offset */
2672 if (cfg
->compile_aot
) {
2673 /* Keep these in the aot case */
2676 NEW_INS (cfg
, temp
, OP_ICONST
);
2677 temp
->inst_c0
= (gulong
)ins
->inst_p0
;
2678 temp
->dreg
= mono_alloc_ireg (cfg
);
2679 ins
->inst_basereg
= temp
->dreg
;
2680 ins
->inst_offset
= 0;
2681 ins
->opcode
= ins
->opcode
== OP_R4CONST
? OP_LOADR4_MEMBASE
: OP_LOADR8_MEMBASE
;
2683 /* make it handle the possibly big ins->inst_offset
2684 * later optimize to use lis + load_membase
2690 bb
->last_ins
= last_ins
;
2691 bb
->max_vreg
= cfg
->next_vreg
;
2695 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
2697 long offset
= cfg
->arch
.fp_conv_var_offset
;
2699 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2700 #ifdef __mono_ppc64__
2702 ppc_fctidz (code
, ppc_f0
, sreg
);
2707 ppc_fctiwz (code
, ppc_f0
, sreg
);
2710 if (ppc_is_imm16 (offset
+ sub_offset
)) {
2711 ppc_stfd (code
, ppc_f0
, offset
, cfg
->frame_reg
);
2713 ppc_ldr (code
, dreg
, offset
+ sub_offset
, cfg
->frame_reg
);
2715 ppc_lwz (code
, dreg
, offset
+ sub_offset
, cfg
->frame_reg
);
2717 ppc_load (code
, dreg
, offset
);
2718 ppc_add (code
, dreg
, dreg
, cfg
->frame_reg
);
2719 ppc_stfd (code
, ppc_f0
, 0, dreg
);
2721 ppc_ldr (code
, dreg
, sub_offset
, dreg
);
2723 ppc_lwz (code
, dreg
, sub_offset
, dreg
);
2727 ppc_andid (code
, dreg
, dreg
, 0xff);
2729 ppc_andid (code
, dreg
, dreg
, 0xffff);
2730 #ifdef __mono_ppc64__
2732 ppc_clrldi (code
, dreg
, dreg
, 32);
2736 ppc_extsb (code
, dreg
, dreg
);
2738 ppc_extsh (code
, dreg
, dreg
);
2739 #ifdef __mono_ppc64__
2741 ppc_extsw (code
, dreg
, dreg
);
2749 const guchar
*target
;
2754 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2757 search_thunk_slot (void *data
, int csize
, int bsize
, void *user_data
) {
2758 #ifdef __mono_ppc64__
2759 g_assert_not_reached ();
2761 PatchData
*pdata
= (PatchData
*)user_data
;
2762 guchar
*code
= data
;
2763 guint32
*thunks
= data
;
2764 guint32
*endthunks
= (guint32
*)(code
+ bsize
);
2768 int difflow
, diffhigh
;
2770 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2771 difflow
= (char*)pdata
->code
- (char*)thunks
;
2772 diffhigh
= (char*)pdata
->code
- (char*)endthunks
;
2773 if (!((is_call_imm (thunks
) && is_call_imm (endthunks
)) || (is_call_imm (difflow
) && is_call_imm (diffhigh
))))
2776 templ
= (guchar
*)load
;
2777 ppc_load_sequence (templ
, ppc_r0
, pdata
->target
);
2779 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2780 if ((pdata
->found
== 2) || (pdata
->code
>= code
&& pdata
->code
<= code
+ csize
)) {
2781 while (thunks
< endthunks
) {
2782 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2783 if ((thunks
[0] == load
[0]) && (thunks
[1] == load
[1])) {
2784 ppc_patch (pdata
->code
, (guchar
*)thunks
);
2787 static int num_thunks = 0;
2789 if ((num_thunks % 20) == 0)
2790 g_print ("num_thunks lookup: %d\n", num_thunks);
2793 } else if ((thunks
[0] == 0) && (thunks
[1] == 0)) {
2794 /* found a free slot instead: emit thunk */
2795 code
= (guchar
*)thunks
;
2796 ppc_lis (code
, ppc_r0
, (gulong
)(pdata
->target
) >> 16);
2797 ppc_ori (code
, ppc_r0
, ppc_r0
, (gulong
)(pdata
->target
) & 0xffff);
2798 ppc_mtctr (code
, ppc_r0
);
2799 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
2800 mono_arch_flush_icache ((guchar
*)thunks
, 16);
2802 ppc_patch (pdata
->code
, (guchar
*)thunks
);
2805 static int num_thunks = 0;
2807 if ((num_thunks % 20) == 0)
2808 g_print ("num_thunks: %d\n", num_thunks);
2812 /* skip 16 bytes, the size of the thunk */
2816 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2823 handle_thunk (int absolute
, guchar
*code
, const guchar
*target
) {
2824 MonoDomain
*domain
= mono_domain_get ();
2828 pdata
.target
= target
;
2829 pdata
.absolute
= absolute
;
2832 mono_domain_lock (domain
);
2833 mono_domain_code_foreach (domain
, search_thunk_slot
, &pdata
);
2836 /* this uses the first available slot */
2838 mono_domain_code_foreach (domain
, search_thunk_slot
, &pdata
);
2840 mono_domain_unlock (domain
);
2842 if (pdata
.found
!= 1)
2843 g_print ("thunk failed for %p from %p\n", target
, code
);
2844 g_assert (pdata
.found
== 1);
2848 patch_ins (guint8
*code
, guint32 ins
)
2850 *(guint32
*)code
= GUINT32_TO_BE (ins
);
2851 mono_arch_flush_icache (code
, 4);
2855 ppc_patch_full (guchar
*code
, const guchar
*target
, gboolean is_fd
)
2857 guint32 ins
= GUINT32_FROM_BE (*(guint32
*)code
);
2858 guint32 prim
= ins
>> 26;
2861 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2863 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2864 gint diff
= target
- code
;
2867 if (diff
<= 33554431){
2868 ins
= (18 << 26) | (diff
) | (ins
& 1);
2869 patch_ins (code
, ins
);
2873 /* diff between 0 and -33554432 */
2874 if (diff
>= -33554432){
2875 ins
= (18 << 26) | (diff
& ~0xfc000000) | (ins
& 1);
2876 patch_ins (code
, ins
);
2881 if ((glong
)target
>= 0){
2882 if ((glong
)target
<= 33554431){
2883 ins
= (18 << 26) | ((gulong
) target
) | (ins
& 1) | 2;
2884 patch_ins (code
, ins
);
2888 if ((glong
)target
>= -33554432){
2889 ins
= (18 << 26) | (((gulong
)target
) & ~0xfc000000) | (ins
& 1) | 2;
2890 patch_ins (code
, ins
);
2895 handle_thunk (TRUE
, code
, target
);
2898 g_assert_not_reached ();
2906 guint32 li
= (gulong
)target
;
2907 ins
= (ins
& 0xffff0000) | (ins
& 3);
2908 ovf
= li
& 0xffff0000;
2909 if (ovf
!= 0 && ovf
!= 0xffff0000)
2910 g_assert_not_reached ();
2913 // FIXME: assert the top bits of li are 0
2915 gint diff
= target
- code
;
2916 ins
= (ins
& 0xffff0000) | (ins
& 3);
2917 ovf
= diff
& 0xffff0000;
2918 if (ovf
!= 0 && ovf
!= 0xffff0000)
2919 g_assert_not_reached ();
2923 patch_ins (code
, ins
);
2927 if (prim
== 15 || ins
== 0x4e800021 || ins
== 0x4e800020 || ins
== 0x4e800420) {
2928 #ifdef __mono_ppc64__
2929 guint32
*seq
= (guint32
*)code
;
2930 guint32
*branch_ins
;
2932 /* the trampoline code will try to patch the blrl, blr, bcctr */
2933 if (ins
== 0x4e800021 || ins
== 0x4e800020 || ins
== 0x4e800420) {
2935 if (ppc_is_load_op (seq
[-3]) || ppc_opcode (seq
[-3]) == 31) /* ld || lwz || mr */
2940 if (ppc_is_load_op (seq
[5]) || ppc_opcode (seq
[5]) == 31) /* ld || lwz || mr */
2941 branch_ins
= seq
+ 8;
2943 branch_ins
= seq
+ 6;
2946 seq
= (guint32
*)code
;
2947 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2948 g_assert (mono_ppc_is_direct_call_sequence (branch_ins
));
2950 if (ppc_is_load_op (seq
[5])) {
2951 g_assert (ppc_is_load_op (seq
[6]));
2954 guint8
*buf
= (guint8
*)&seq
[5];
2955 ppc_mr (buf
, ppc_r0
, ppc_r11
);
2960 target
= mono_get_addr_from_ftnptr ((gpointer
)target
);
2963 /* FIXME: make this thread safe */
2964 /* FIXME: we're assuming we're using r11 here */
2965 ppc_load_ptr_sequence (code
, ppc_r11
, target
);
2966 mono_arch_flush_icache ((guint8
*)seq
, 28);
2969 /* the trampoline code will try to patch the blrl, blr, bcctr */
2970 if (ins
== 0x4e800021 || ins
== 0x4e800020 || ins
== 0x4e800420) {
2973 /* this is the lis/ori/mtlr/blrl sequence */
2974 seq
= (guint32
*)code
;
2975 g_assert ((seq
[0] >> 26) == 15);
2976 g_assert ((seq
[1] >> 26) == 24);
2977 g_assert ((seq
[2] >> 26) == 31);
2978 g_assert (seq
[3] == 0x4e800021 || seq
[3] == 0x4e800020 || seq
[3] == 0x4e800420);
2979 /* FIXME: make this thread safe */
2980 ppc_lis (code
, ppc_r0
, (guint32
)(target
) >> 16);
2981 ppc_ori (code
, ppc_r0
, ppc_r0
, (guint32
)(target
) & 0xffff);
2982 mono_arch_flush_icache (code
- 8, 8);
2985 g_assert_not_reached ();
2987 // g_print ("patched with 0x%08x\n", ins);
2991 ppc_patch (guchar
*code
, const guchar
*target
)
2993 ppc_patch_full (code
, target
, FALSE
);
2997 mono_ppc_patch (guchar
*code
, const guchar
*target
)
2999 ppc_patch (code
, target
);
3003 emit_move_return_value (MonoCompile
*cfg
, MonoInst
*ins
, guint8
*code
)
3005 switch (ins
->opcode
) {
3008 case OP_FCALL_MEMBASE
:
3009 if (ins
->dreg
!= ppc_f1
)
3010 ppc_fmr (code
, ins
->dreg
, ppc_f1
);
3018 ins_native_length (MonoCompile
*cfg
, MonoInst
*ins
)
3020 return ((guint8
*)ins_get_spec (ins
->opcode
))[MONO_INST_LEN
];
3024 emit_reserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3026 long size
= cfg
->param_area
;
3028 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3029 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3034 ppc_ldptr (code
, ppc_r0
, 0, ppc_sp
);
3035 if (ppc_is_imm16 (-size
)) {
3036 ppc_stptr_update (code
, ppc_r0
, -size
, ppc_sp
);
3038 ppc_load (code
, ppc_r11
, -size
);
3039 ppc_stptr_update_indexed (code
, ppc_r0
, ppc_sp
, ppc_r11
);
3046 emit_unreserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3048 long size
= cfg
->param_area
;
3050 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3051 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3056 ppc_ldptr (code
, ppc_r0
, 0, ppc_sp
);
3057 if (ppc_is_imm16 (size
)) {
3058 ppc_stptr_update (code
, ppc_r0
, size
, ppc_sp
);
3060 ppc_load (code
, ppc_r11
, size
);
3061 ppc_stptr_update_indexed (code
, ppc_r0
, ppc_sp
, ppc_r11
);
3067 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3071 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
3073 MonoInst
*ins
, *next
;
3076 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
3077 MonoInst
*last_ins
= NULL
;
3078 guint last_offset
= 0;
3082 /* we don't align basic blocks of loops on ppc */
3084 if (cfg
->verbose_level
> 2)
3085 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
3087 cpos
= bb
->max_offset
;
3089 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
) {
3090 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3091 //g_assert (!mono_compile_aot);
3094 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3095 /* this is not thread save, but good enough */
3096 /* fixme: howto handle overflows? */
3097 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3100 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3101 offset
= code
- cfg
->native_code
;
3103 max_len
= ins_native_length (cfg
, ins
);
3105 if (offset
> (cfg
->code_size
- max_len
- 16)) {
3106 cfg
->code_size
*= 2;
3107 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
3108 code
= cfg
->native_code
+ offset
;
3110 // if (ins->cil_code)
3111 // g_print ("cil code\n");
3112 mono_debug_record_line_number (cfg
, ins
, offset
);
3114 switch (normalize_opcode (ins
->opcode
)) {
3115 case OP_RELAXED_NOP
:
3118 case OP_DUMMY_STORE
:
3119 case OP_NOT_REACHED
:
3122 case OP_SEQ_POINT
: {
3125 if (cfg
->compile_aot
)
3129 * Read from the single stepping trigger page. This will cause a
3130 * SIGSEGV when single stepping is enabled.
3131 * We do this _before_ the breakpoint, so single stepping after
3132 * a breakpoint is hit will step to the next IL offset.
3134 if (ins
->flags
& MONO_INST_SINGLE_STEP_LOC
) {
3135 ppc_load (code
, ppc_r11
, (gsize
)ss_trigger_page
);
3136 ppc_ldptr (code
, ppc_r11
, 0, ppc_r11
);
3139 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3142 * A placeholder for a possible breakpoint inserted by
3143 * mono_arch_set_breakpoint ().
3145 for (i
= 0; i
< BREAKPOINT_SIZE
/ 4; ++i
)
3150 emit_tls_access (code
, ins
->dreg
, ins
->inst_offset
);
3153 ppc_mullw (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3154 ppc_mulhw (code
, ppc_r3
, ins
->sreg1
, ins
->sreg2
);
3155 ppc_mr (code
, ppc_r4
, ppc_r0
);
3158 ppc_mullw (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3159 ppc_mulhwu (code
, ppc_r3
, ins
->sreg1
, ins
->sreg2
);
3160 ppc_mr (code
, ppc_r4
, ppc_r0
);
3162 case OP_MEMORY_BARRIER
:
3165 case OP_STOREI1_MEMBASE_REG
:
3166 if (ppc_is_imm16 (ins
->inst_offset
)) {
3167 ppc_stb (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3169 if (ppc_is_imm32 (ins
->inst_offset
)) {
3170 ppc_addis (code
, ppc_r12
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
3171 ppc_stb (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r12
);
3173 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3174 ppc_stbx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3178 case OP_STOREI2_MEMBASE_REG
:
3179 if (ppc_is_imm16 (ins
->inst_offset
)) {
3180 ppc_sth (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3182 if (ppc_is_imm32 (ins
->inst_offset
)) {
3183 ppc_addis (code
, ppc_r12
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
3184 ppc_sth (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r12
);
3186 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3187 ppc_sthx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3191 case OP_STORE_MEMBASE_REG
:
3192 if (ppc_is_imm16 (ins
->inst_offset
)) {
3193 ppc_stptr (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3195 if (ppc_is_imm32 (ins
->inst_offset
)) {
3196 ppc_addis (code
, ppc_r12
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
3197 ppc_stptr (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r12
);
3199 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3200 ppc_stptr_indexed (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3204 #ifdef __mono_ilp32__
3205 case OP_STOREI8_MEMBASE_REG
:
3206 if (ppc_is_imm16 (ins
->inst_offset
)) {
3207 ppc_str (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3209 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3210 ppc_str_indexed (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3214 case OP_STOREI1_MEMINDEX
:
3215 ppc_stbx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
3217 case OP_STOREI2_MEMINDEX
:
3218 ppc_sthx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
3220 case OP_STORE_MEMINDEX
:
3221 ppc_stptr_indexed (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
3224 g_assert_not_reached ();
3226 case OP_LOAD_MEMBASE
:
3227 if (ppc_is_imm16 (ins
->inst_offset
)) {
3228 ppc_ldptr (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3230 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3231 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3232 ppc_ldptr (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3234 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3235 ppc_ldptr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3239 case OP_LOADI4_MEMBASE
:
3240 #ifdef __mono_ppc64__
3241 if (ppc_is_imm16 (ins
->inst_offset
)) {
3242 ppc_lwa (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3244 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3245 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3246 ppc_lwa (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3248 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3249 ppc_lwax (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3254 case OP_LOADU4_MEMBASE
:
3255 if (ppc_is_imm16 (ins
->inst_offset
)) {
3256 ppc_lwz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3258 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3259 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3260 ppc_lwz (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3262 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3263 ppc_lwzx (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3267 case OP_LOADI1_MEMBASE
:
3268 case OP_LOADU1_MEMBASE
:
3269 if (ppc_is_imm16 (ins
->inst_offset
)) {
3270 ppc_lbz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3272 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3273 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3274 ppc_lbz (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3276 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3277 ppc_lbzx (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3280 if (ins
->opcode
== OP_LOADI1_MEMBASE
)
3281 ppc_extsb (code
, ins
->dreg
, ins
->dreg
);
3283 case OP_LOADU2_MEMBASE
:
3284 if (ppc_is_imm16 (ins
->inst_offset
)) {
3285 ppc_lhz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3287 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3288 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3289 ppc_lhz (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3291 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3292 ppc_lhzx (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3296 case OP_LOADI2_MEMBASE
:
3297 if (ppc_is_imm16 (ins
->inst_offset
)) {
3298 ppc_lha (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3300 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3301 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3302 ppc_lha (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3304 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3305 ppc_lhax (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3309 #ifdef __mono_ilp32__
3310 case OP_LOADI8_MEMBASE
:
3311 if (ppc_is_imm16 (ins
->inst_offset
)) {
3312 ppc_ldr (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3314 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3315 ppc_ldr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3319 case OP_LOAD_MEMINDEX
:
3320 ppc_ldptr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3322 case OP_LOADI4_MEMINDEX
:
3323 #ifdef __mono_ppc64__
3324 ppc_lwax (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3327 case OP_LOADU4_MEMINDEX
:
3328 ppc_lwzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3330 case OP_LOADU2_MEMINDEX
:
3331 ppc_lhzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3333 case OP_LOADI2_MEMINDEX
:
3334 ppc_lhax (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3336 case OP_LOADU1_MEMINDEX
:
3337 ppc_lbzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3339 case OP_LOADI1_MEMINDEX
:
3340 ppc_lbzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3341 ppc_extsb (code
, ins
->dreg
, ins
->dreg
);
3343 case OP_ICONV_TO_I1
:
3344 CASE_PPC64 (OP_LCONV_TO_I1
)
3345 ppc_extsb (code
, ins
->dreg
, ins
->sreg1
);
3347 case OP_ICONV_TO_I2
:
3348 CASE_PPC64 (OP_LCONV_TO_I2
)
3349 ppc_extsh (code
, ins
->dreg
, ins
->sreg1
);
3351 case OP_ICONV_TO_U1
:
3352 CASE_PPC64 (OP_LCONV_TO_U1
)
3353 ppc_clrlwi (code
, ins
->dreg
, ins
->sreg1
, 24);
3355 case OP_ICONV_TO_U2
:
3356 CASE_PPC64 (OP_LCONV_TO_U2
)
3357 ppc_clrlwi (code
, ins
->dreg
, ins
->sreg1
, 16);
3361 CASE_PPC64 (OP_LCOMPARE
)
3362 L
= (sizeof (mgreg_t
) == 4 || ins
->opcode
== OP_ICOMPARE
) ? 0 : 1;
3364 if (next
&& compare_opcode_is_unsigned (next
->opcode
))
3365 ppc_cmpl (code
, 0, L
, ins
->sreg1
, ins
->sreg2
);
3367 ppc_cmp (code
, 0, L
, ins
->sreg1
, ins
->sreg2
);
3369 case OP_COMPARE_IMM
:
3370 case OP_ICOMPARE_IMM
:
3371 CASE_PPC64 (OP_LCOMPARE_IMM
)
3372 L
= (sizeof (mgreg_t
) == 4 || ins
->opcode
== OP_ICOMPARE_IMM
) ? 0 : 1;
3374 if (next
&& compare_opcode_is_unsigned (next
->opcode
)) {
3375 if (ppc_is_uimm16 (ins
->inst_imm
)) {
3376 ppc_cmpli (code
, 0, L
, ins
->sreg1
, (ins
->inst_imm
& 0xffff));
3378 g_assert_not_reached ();
3381 if (ppc_is_imm16 (ins
->inst_imm
)) {
3382 ppc_cmpi (code
, 0, L
, ins
->sreg1
, (ins
->inst_imm
& 0xffff));
3384 g_assert_not_reached ();
3390 * gdb does not like encountering a trap in the debugged code. So
3391 * instead of emitting a trap, we emit a call a C function and place a
3395 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3396 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3397 (gpointer
)"mono_break");
3398 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3399 ppc_load_func (code
, ppc_r0
, 0);
3400 ppc_mtlr (code
, ppc_r0
);
3408 ppc_addco (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3411 CASE_PPC64 (OP_LADD
)
3412 ppc_add (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3416 ppc_adde (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3419 if (ppc_is_imm16 (ins
->inst_imm
)) {
3420 ppc_addic (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3422 g_assert_not_reached ();
3427 CASE_PPC64 (OP_LADD_IMM
)
3428 if (ppc_is_imm16 (ins
->inst_imm
)) {
3429 ppc_addi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3431 g_assert_not_reached ();
3435 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3437 ppc_addo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3438 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3439 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3440 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3442 case OP_IADD_OVF_UN
:
3443 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3445 ppc_addco (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3446 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3447 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3448 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3451 CASE_PPC64 (OP_LSUB_OVF
)
3452 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3454 ppc_subfo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3455 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3456 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3457 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3459 case OP_ISUB_OVF_UN
:
3460 CASE_PPC64 (OP_LSUB_OVF_UN
)
3461 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3463 ppc_subfc (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3464 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3465 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3466 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
3468 case OP_ADD_OVF_CARRY
:
3469 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3471 ppc_addeo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3472 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3473 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3474 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3476 case OP_ADD_OVF_UN_CARRY
:
3477 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3479 ppc_addeo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3480 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3481 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3482 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3484 case OP_SUB_OVF_CARRY
:
3485 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3487 ppc_subfeo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3488 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3489 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3490 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3492 case OP_SUB_OVF_UN_CARRY
:
3493 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3495 ppc_subfeo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3496 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3497 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3498 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
3502 ppc_subfco (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3505 CASE_PPC64 (OP_LSUB
)
3506 ppc_subf (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3510 ppc_subfe (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3514 CASE_PPC64 (OP_LSUB_IMM
)
3515 // we add the negated value
3516 if (ppc_is_imm16 (-ins
->inst_imm
))
3517 ppc_addi (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3519 g_assert_not_reached ();
3523 g_assert (ppc_is_imm16 (ins
->inst_imm
));
3524 ppc_subfic (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3527 ppc_subfze (code
, ins
->dreg
, ins
->sreg1
);
3530 CASE_PPC64 (OP_LAND
)
3531 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3532 ppc_and (code
, ins
->sreg1
, ins
->dreg
, ins
->sreg2
);
3536 CASE_PPC64 (OP_LAND_IMM
)
3537 if (!(ins
->inst_imm
& 0xffff0000)) {
3538 ppc_andid (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3539 } else if (!(ins
->inst_imm
& 0xffff)) {
3540 ppc_andisd (code
, ins
->sreg1
, ins
->dreg
, ((guint32
)ins
->inst_imm
>> 16));
3542 g_assert_not_reached ();
3546 CASE_PPC64 (OP_LDIV
) {
3547 guint8
*divisor_is_m1
;
3548 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3550 ppc_compare_reg_imm (code
, 0, ins
->sreg2
, -1);
3551 divisor_is_m1
= code
;
3552 ppc_bc (code
, PPC_BR_FALSE
| PPC_BR_LIKELY
, PPC_BR_EQ
, 0);
3553 ppc_lis (code
, ppc_r0
, 0x8000);
3554 #ifdef __mono_ppc64__
3555 if (ins
->opcode
== OP_LDIV
)
3556 ppc_sldi (code
, ppc_r0
, ppc_r0
, 32);
3558 ppc_compare (code
, 0, ins
->sreg1
, ppc_r0
);
3559 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
3560 ppc_patch (divisor_is_m1
, code
);
3561 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3563 if (ins
->opcode
== OP_IDIV
)
3564 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3565 #ifdef __mono_ppc64__
3567 ppc_divdod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3569 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3570 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3571 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3575 CASE_PPC64 (OP_LDIV_UN
)
3576 if (ins
->opcode
== OP_IDIV_UN
)
3577 ppc_divwuod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3578 #ifdef __mono_ppc64__
3580 ppc_divduod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3582 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3583 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3584 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3590 g_assert_not_reached ();
3593 ppc_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3597 CASE_PPC64 (OP_LOR_IMM
)
3598 if (!(ins
->inst_imm
& 0xffff0000)) {
3599 ppc_ori (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3600 } else if (!(ins
->inst_imm
& 0xffff)) {
3601 ppc_oris (code
, ins
->dreg
, ins
->sreg1
, ((guint32
)(ins
->inst_imm
) >> 16));
3603 g_assert_not_reached ();
3607 CASE_PPC64 (OP_LXOR
)
3608 ppc_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3612 CASE_PPC64 (OP_LXOR_IMM
)
3613 if (!(ins
->inst_imm
& 0xffff0000)) {
3614 ppc_xori (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3615 } else if (!(ins
->inst_imm
& 0xffff)) {
3616 ppc_xoris (code
, ins
->sreg1
, ins
->dreg
, ((guint32
)(ins
->inst_imm
) >> 16));
3618 g_assert_not_reached ();
3622 CASE_PPC64 (OP_LSHL
)
3623 ppc_shift_left (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3627 CASE_PPC64 (OP_LSHL_IMM
)
3628 ppc_shift_left_imm (code
, ins
->dreg
, ins
->sreg1
, MASK_SHIFT_IMM (ins
->inst_imm
));
3631 ppc_sraw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3634 ppc_shift_right_arith_imm (code
, ins
->dreg
, ins
->sreg1
, MASK_SHIFT_IMM (ins
->inst_imm
));
3637 if (MASK_SHIFT_IMM (ins
->inst_imm
))
3638 ppc_shift_right_imm (code
, ins
->dreg
, ins
->sreg1
, MASK_SHIFT_IMM (ins
->inst_imm
));
3640 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
3643 ppc_srw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3646 CASE_PPC64 (OP_LNOT
)
3647 ppc_not (code
, ins
->dreg
, ins
->sreg1
);
3650 CASE_PPC64 (OP_LNEG
)
3651 ppc_neg (code
, ins
->dreg
, ins
->sreg1
);
3654 CASE_PPC64 (OP_LMUL
)
3655 ppc_multiply (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3659 CASE_PPC64 (OP_LMUL_IMM
)
3660 if (ppc_is_imm16 (ins
->inst_imm
)) {
3661 ppc_mulli (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3663 g_assert_not_reached ();
3667 CASE_PPC64 (OP_LMUL_OVF
)
3668 /* we annot use mcrxr, since it's not implemented on some processors
3669 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3671 if (ins
->opcode
== OP_IMUL_OVF
)
3672 ppc_mullwo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3673 #ifdef __mono_ppc64__
3675 ppc_mulldo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3677 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3678 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3679 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3681 case OP_IMUL_OVF_UN
:
3682 CASE_PPC64 (OP_LMUL_OVF_UN
)
3683 /* we first multiply to get the high word and compare to 0
3684 * to set the flags, then the result is discarded and then
3685 * we multiply to get the lower * bits result
3687 if (ins
->opcode
== OP_IMUL_OVF_UN
)
3688 ppc_mulhwu (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3689 #ifdef __mono_ppc64__
3691 ppc_mulhdu (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3693 ppc_cmpi (code
, 0, 0, ppc_r0
, 0);
3694 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN
- CEE_BEQ
, "OverflowException");
3695 ppc_multiply (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3698 ppc_load (code
, ins
->dreg
, ins
->inst_c0
);
3701 ppc_load (code
, ins
->dreg
, ins
->inst_l
);
3704 case OP_LOAD_GOTADDR
:
3705 /* The PLT implementation depends on this */
3706 g_assert (ins
->dreg
== ppc_r30
);
3708 code
= mono_arch_emit_load_got_addr (cfg
->native_code
, code
, cfg
, NULL
);
3711 // FIXME: Fix max instruction length
3712 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_right
->inst_i1
, ins
->inst_right
->inst_p0
);
3713 /* arch_emit_got_access () patches this */
3714 ppc_load32 (code
, ppc_r0
, 0);
3715 ppc_ldptr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3718 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3719 ppc_load_sequence (code
, ins
->dreg
, 0);
3721 CASE_PPC32 (OP_ICONV_TO_I4
)
3722 CASE_PPC32 (OP_ICONV_TO_U4
)
3724 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
3727 int saved
= ins
->sreg1
;
3728 if (ins
->sreg1
== ppc_r3
) {
3729 ppc_mr (code
, ppc_r0
, ins
->sreg1
);
3732 if (ins
->sreg2
!= ppc_r3
)
3733 ppc_mr (code
, ppc_r3
, ins
->sreg2
);
3734 if (saved
!= ppc_r4
)
3735 ppc_mr (code
, ppc_r4
, saved
);
3739 ppc_fmr (code
, ins
->dreg
, ins
->sreg1
);
3741 case OP_FCONV_TO_R4
:
3742 ppc_frsp (code
, ins
->dreg
, ins
->sreg1
);
3746 MonoCallInst
*call
= (MonoCallInst
*)ins
;
3749 * Keep in sync with mono_arch_emit_epilog
3751 g_assert (!cfg
->method
->save_lmf
);
3753 * Note: we can use ppc_r11 here because it is dead anyway:
3754 * we're leaving the method.
3756 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
3757 long ret_offset
= cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
;
3758 if (ppc_is_imm16 (ret_offset
)) {
3759 ppc_ldptr (code
, ppc_r0
, ret_offset
, cfg
->frame_reg
);
3761 ppc_load (code
, ppc_r11
, ret_offset
);
3762 ppc_ldptr_indexed (code
, ppc_r0
, cfg
->frame_reg
, ppc_r11
);
3764 ppc_mtlr (code
, ppc_r0
);
3767 if (ppc_is_imm16 (cfg
->stack_usage
)) {
3768 ppc_addi (code
, ppc_r11
, cfg
->frame_reg
, cfg
->stack_usage
);
3770 /* cfg->stack_usage is an int, so we can use
3771 * an addis/addi sequence here even in 64-bit. */
3772 ppc_addis (code
, ppc_r11
, cfg
->frame_reg
, ppc_ha(cfg
->stack_usage
));
3773 ppc_addi (code
, ppc_r11
, ppc_r11
, cfg
->stack_usage
);
3775 if (!cfg
->method
->save_lmf
) {
3777 for (i
= 31; i
>= 13; --i
) {
3778 if (cfg
->used_int_regs
& (1 << i
)) {
3779 pos
+= sizeof (gpointer
);
3780 ppc_ldptr (code
, i
, -pos
, ppc_r11
);
3784 /* FIXME restore from MonoLMF: though this can't happen yet */
3787 /* Copy arguments on the stack to our argument area */
3788 if (call
->stack_usage
) {
3789 code
= emit_memcpy (code
, call
->stack_usage
, ppc_r11
, PPC_STACK_PARAM_OFFSET
, ppc_sp
, PPC_STACK_PARAM_OFFSET
);
3790 /* r11 was clobbered */
3791 g_assert (cfg
->frame_reg
== ppc_sp
);
3792 if (ppc_is_imm16 (cfg
->stack_usage
)) {
3793 ppc_addi (code
, ppc_r11
, cfg
->frame_reg
, cfg
->stack_usage
);
3795 /* cfg->stack_usage is an int, so we can use
3796 * an addis/addi sequence here even in 64-bit. */
3797 ppc_addis (code
, ppc_r11
, cfg
->frame_reg
, ppc_ha(cfg
->stack_usage
));
3798 ppc_addi (code
, ppc_r11
, ppc_r11
, cfg
->stack_usage
);
3802 ppc_mr (code
, ppc_sp
, ppc_r11
);
3803 mono_add_patch_info (cfg
, (guint8
*) code
- cfg
->native_code
, MONO_PATCH_INFO_METHOD_JUMP
, ins
->inst_p0
);
3804 if (cfg
->compile_aot
) {
3805 /* arch_emit_got_access () patches this */
3806 ppc_load32 (code
, ppc_r0
, 0);
3807 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3808 ppc_ldptr_indexed (code
, ppc_r11
, ppc_r30
, ppc_r0
);
3809 ppc_ldptr (code
, ppc_r0
, 0, ppc_r11
);
3811 ppc_ldptr_indexed (code
, ppc_r0
, ppc_r30
, ppc_r0
);
3813 ppc_mtctr (code
, ppc_r0
);
3814 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
3821 /* ensure ins->sreg1 is not NULL */
3822 ppc_ldptr (code
, ppc_r0
, 0, ins
->sreg1
);
3825 long cookie_offset
= cfg
->sig_cookie
+ cfg
->stack_usage
;
3826 if (ppc_is_imm16 (cookie_offset
)) {
3827 ppc_addi (code
, ppc_r0
, cfg
->frame_reg
, cookie_offset
);
3829 ppc_load (code
, ppc_r0
, cookie_offset
);
3830 ppc_add (code
, ppc_r0
, cfg
->frame_reg
, ppc_r0
);
3832 ppc_stptr (code
, ppc_r0
, 0, ins
->sreg1
);
3841 call
= (MonoCallInst
*)ins
;
3842 if (ins
->flags
& MONO_INST_HAS_METHOD
)
3843 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
3845 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
3846 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3847 ppc_load_func (code
, ppc_r0
, 0);
3848 ppc_mtlr (code
, ppc_r0
);
3853 /* FIXME: this should be handled somewhere else in the new jit */
3854 code
= emit_move_return_value (cfg
, ins
, code
);
3860 case OP_VOIDCALL_REG
:
3862 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3863 ppc_ldptr (code
, ppc_r0
, 0, ins
->sreg1
);
3864 /* FIXME: if we know that this is a method, we
3865 can omit this load */
3866 ppc_ldptr (code
, ppc_r2
, 8, ins
->sreg1
);
3867 ppc_mtlr (code
, ppc_r0
);
3869 ppc_mtlr (code
, ins
->sreg1
);
3872 /* FIXME: this should be handled somewhere else in the new jit */
3873 code
= emit_move_return_value (cfg
, ins
, code
);
3875 case OP_FCALL_MEMBASE
:
3876 case OP_LCALL_MEMBASE
:
3877 case OP_VCALL_MEMBASE
:
3878 case OP_VCALL2_MEMBASE
:
3879 case OP_VOIDCALL_MEMBASE
:
3880 case OP_CALL_MEMBASE
:
3881 if (cfg
->compile_aot
&& ins
->sreg1
== ppc_r11
) {
3882 /* The trampolines clobber this */
3883 ppc_mr (code
, ppc_r29
, ins
->sreg1
);
3884 ppc_ldptr (code
, ppc_r0
, ins
->inst_offset
, ppc_r29
);
3886 ppc_ldptr (code
, ppc_r0
, ins
->inst_offset
, ins
->sreg1
);
3888 ppc_mtlr (code
, ppc_r0
);
3890 /* FIXME: this should be handled somewhere else in the new jit */
3891 code
= emit_move_return_value (cfg
, ins
, code
);
3894 guint8
* zero_loop_jump
, * zero_loop_start
;
3895 /* keep alignment */
3896 int alloca_waste
= PPC_STACK_PARAM_OFFSET
+ cfg
->param_area
+ 31;
3897 int area_offset
= alloca_waste
;
3899 ppc_addi (code
, ppc_r11
, ins
->sreg1
, alloca_waste
+ 31);
3900 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3901 ppc_clear_right_imm (code
, ppc_r11
, ppc_r11
, 4);
3902 /* use ctr to store the number of words to 0 if needed */
3903 if (ins
->flags
& MONO_INST_INIT
) {
3904 /* we zero 4 bytes at a time:
3905 * we add 7 instead of 3 so that we set the counter to
3906 * at least 1, otherwise the bdnz instruction will make
3907 * it negative and iterate billions of times.
3909 ppc_addi (code
, ppc_r0
, ins
->sreg1
, 7);
3910 ppc_shift_right_arith_imm (code
, ppc_r0
, ppc_r0
, 2);
3911 ppc_mtctr (code
, ppc_r0
);
3913 ppc_ldptr (code
, ppc_r0
, 0, ppc_sp
);
3914 ppc_neg (code
, ppc_r11
, ppc_r11
);
3915 ppc_stptr_update_indexed (code
, ppc_r0
, ppc_sp
, ppc_r11
);
3917 /* FIXME: make this loop work in 8 byte
3918 increments on PPC64 */
3919 if (ins
->flags
& MONO_INST_INIT
) {
3920 /* adjust the dest reg by -4 so we can use stwu */
3921 /* we actually adjust -8 because we let the loop
3924 ppc_addi (code
, ins
->dreg
, ppc_sp
, (area_offset
- 8));
3925 ppc_li (code
, ppc_r11
, 0);
3926 zero_loop_start
= code
;
3927 ppc_stwu (code
, ppc_r11
, 4, ins
->dreg
);
3928 zero_loop_jump
= code
;
3929 ppc_bc (code
, PPC_BR_DEC_CTR_NONZERO
, 0, 0);
3930 ppc_patch (zero_loop_jump
, zero_loop_start
);
3932 ppc_addi (code
, ins
->dreg
, ppc_sp
, area_offset
);
3937 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3938 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3939 (gpointer
)"mono_arch_throw_exception");
3940 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3941 ppc_load_func (code
, ppc_r0
, 0);
3942 ppc_mtlr (code
, ppc_r0
);
3951 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3952 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3953 (gpointer
)"mono_arch_rethrow_exception");
3954 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3955 ppc_load_func (code
, ppc_r0
, 0);
3956 ppc_mtlr (code
, ppc_r0
);
3963 case OP_START_HANDLER
: {
3964 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3965 g_assert (spvar
->inst_basereg
!= ppc_sp
);
3966 code
= emit_reserve_param_area (cfg
, code
);
3967 ppc_mflr (code
, ppc_r0
);
3968 if (ppc_is_imm16 (spvar
->inst_offset
)) {
3969 ppc_stptr (code
, ppc_r0
, spvar
->inst_offset
, spvar
->inst_basereg
);
3971 ppc_load (code
, ppc_r11
, spvar
->inst_offset
);
3972 ppc_stptr_indexed (code
, ppc_r0
, ppc_r11
, spvar
->inst_basereg
);
3976 case OP_ENDFILTER
: {
3977 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3978 g_assert (spvar
->inst_basereg
!= ppc_sp
);
3979 code
= emit_unreserve_param_area (cfg
, code
);
3980 if (ins
->sreg1
!= ppc_r3
)
3981 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3982 if (ppc_is_imm16 (spvar
->inst_offset
)) {
3983 ppc_ldptr (code
, ppc_r0
, spvar
->inst_offset
, spvar
->inst_basereg
);
3985 ppc_load (code
, ppc_r11
, spvar
->inst_offset
);
3986 ppc_ldptr_indexed (code
, ppc_r0
, spvar
->inst_basereg
, ppc_r11
);
3988 ppc_mtlr (code
, ppc_r0
);
3992 case OP_ENDFINALLY
: {
3993 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3994 g_assert (spvar
->inst_basereg
!= ppc_sp
);
3995 code
= emit_unreserve_param_area (cfg
, code
);
3996 ppc_ldptr (code
, ppc_r0
, spvar
->inst_offset
, spvar
->inst_basereg
);
3997 ppc_mtlr (code
, ppc_r0
);
4001 case OP_CALL_HANDLER
:
4002 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
4004 mono_cfg_add_try_hole (cfg
, ins
->inst_eh_block
, code
, bb
);
4007 ins
->inst_c0
= code
- cfg
->native_code
;
4010 /*if (ins->inst_target_bb->native_offset) {
4012 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4014 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
4019 ppc_mtctr (code
, ins
->sreg1
);
4020 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
4024 CASE_PPC64 (OP_LCEQ
)
4025 ppc_li (code
, ins
->dreg
, 0);
4026 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 2);
4027 ppc_li (code
, ins
->dreg
, 1);
4033 CASE_PPC64 (OP_LCLT
)
4034 CASE_PPC64 (OP_LCLT_UN
)
4035 ppc_li (code
, ins
->dreg
, 1);
4036 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
4037 ppc_li (code
, ins
->dreg
, 0);
4043 CASE_PPC64 (OP_LCGT
)
4044 CASE_PPC64 (OP_LCGT_UN
)
4045 ppc_li (code
, ins
->dreg
, 1);
4046 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
4047 ppc_li (code
, ins
->dreg
, 0);
4049 case OP_COND_EXC_EQ
:
4050 case OP_COND_EXC_NE_UN
:
4051 case OP_COND_EXC_LT
:
4052 case OP_COND_EXC_LT_UN
:
4053 case OP_COND_EXC_GT
:
4054 case OP_COND_EXC_GT_UN
:
4055 case OP_COND_EXC_GE
:
4056 case OP_COND_EXC_GE_UN
:
4057 case OP_COND_EXC_LE
:
4058 case OP_COND_EXC_LE_UN
:
4059 EMIT_COND_SYSTEM_EXCEPTION (ins
->opcode
- OP_COND_EXC_EQ
, ins
->inst_p1
);
4061 case OP_COND_EXC_IEQ
:
4062 case OP_COND_EXC_INE_UN
:
4063 case OP_COND_EXC_ILT
:
4064 case OP_COND_EXC_ILT_UN
:
4065 case OP_COND_EXC_IGT
:
4066 case OP_COND_EXC_IGT_UN
:
4067 case OP_COND_EXC_IGE
:
4068 case OP_COND_EXC_IGE_UN
:
4069 case OP_COND_EXC_ILE
:
4070 case OP_COND_EXC_ILE_UN
:
4071 EMIT_COND_SYSTEM_EXCEPTION (ins
->opcode
- OP_COND_EXC_IEQ
, ins
->inst_p1
);
4083 EMIT_COND_BRANCH (ins
, ins
->opcode
- OP_IBEQ
);
4086 /* floating point opcodes */
4088 g_assert (cfg
->compile_aot
);
4090 /* FIXME: Optimize this */
4092 ppc_mflr (code
, ppc_r11
);
4094 *(double*)code
= *(double*)ins
->inst_p0
;
4096 ppc_lfd (code
, ins
->dreg
, 8, ppc_r11
);
4099 g_assert_not_reached ();
4101 case OP_STORER8_MEMBASE_REG
:
4102 if (ppc_is_imm16 (ins
->inst_offset
)) {
4103 ppc_stfd (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
4105 if (ppc_is_imm32 (ins
->inst_offset
)) {
4106 ppc_addis (code
, ppc_r12
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4107 ppc_stfd (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r12
);
4109 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4110 ppc_stfdx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
4114 case OP_LOADR8_MEMBASE
:
4115 if (ppc_is_imm16 (ins
->inst_offset
)) {
4116 ppc_lfd (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
4118 if (ppc_is_imm32 (ins
->inst_offset
)) {
4119 ppc_addis (code
, ppc_r12
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4120 ppc_lfd (code
, ins
->dreg
, ins
->inst_offset
, ppc_r12
);
4122 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4123 ppc_lfdx (code
, ins
->dreg
, ins
->inst_destbasereg
, ppc_r0
);
4127 case OP_STORER4_MEMBASE_REG
:
4128 ppc_frsp (code
, ins
->sreg1
, ins
->sreg1
);
4129 if (ppc_is_imm16 (ins
->inst_offset
)) {
4130 ppc_stfs (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
4132 if (ppc_is_imm32 (ins
->inst_offset
)) {
4133 ppc_addis (code
, ppc_r12
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4134 ppc_stfs (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r12
);
4136 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4137 ppc_stfsx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
4141 case OP_LOADR4_MEMBASE
:
4142 if (ppc_is_imm16 (ins
->inst_offset
)) {
4143 ppc_lfs (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
4145 if (ppc_is_imm32 (ins
->inst_offset
)) {
4146 ppc_addis (code
, ppc_r12
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4147 ppc_lfs (code
, ins
->dreg
, ins
->inst_offset
, ppc_r12
);
4149 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4150 ppc_lfsx (code
, ins
->dreg
, ins
->inst_destbasereg
, ppc_r0
);
4154 case OP_LOADR4_MEMINDEX
:
4155 ppc_lfsx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
4157 case OP_LOADR8_MEMINDEX
:
4158 ppc_lfdx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
4160 case OP_STORER4_MEMINDEX
:
4161 ppc_frsp (code
, ins
->sreg1
, ins
->sreg1
);
4162 ppc_stfsx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
4164 case OP_STORER8_MEMINDEX
:
4165 ppc_stfdx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
4168 case CEE_CONV_R4
: /* FIXME: change precision */
4170 g_assert_not_reached ();
4171 case OP_FCONV_TO_I1
:
4172 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
4174 case OP_FCONV_TO_U1
:
4175 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
4177 case OP_FCONV_TO_I2
:
4178 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
4180 case OP_FCONV_TO_U2
:
4181 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
4183 case OP_FCONV_TO_I4
:
4185 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
4187 case OP_FCONV_TO_U4
:
4189 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
4191 case OP_LCONV_TO_R_UN
:
4192 g_assert_not_reached ();
4193 /* Implemented as helper calls */
4195 case OP_LCONV_TO_OVF_I4_2
:
4196 case OP_LCONV_TO_OVF_I
: {
4197 #ifdef __mono_ppc64__
4200 guint8
*negative_branch
, *msword_positive_branch
, *msword_negative_branch
, *ovf_ex_target
;
4201 // Check if its negative
4202 ppc_cmpi (code
, 0, 0, ins
->sreg1
, 0);
4203 negative_branch
= code
;
4204 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 0);
4205 // Its positive msword == 0
4206 ppc_cmpi (code
, 0, 0, ins
->sreg2
, 0);
4207 msword_positive_branch
= code
;
4208 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_EQ
, 0);
4210 ovf_ex_target
= code
;
4211 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS
, 0, "OverflowException");
4213 ppc_patch (negative_branch
, code
);
4214 ppc_cmpi (code
, 0, 0, ins
->sreg2
, -1);
4215 msword_negative_branch
= code
;
4216 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4217 ppc_patch (msword_negative_branch
, ovf_ex_target
);
4219 ppc_patch (msword_positive_branch
, code
);
4220 if (ins
->dreg
!= ins
->sreg1
)
4221 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
4226 ppc_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
4229 ppc_fadd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4232 ppc_fsub (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4235 ppc_fmul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4238 ppc_fdiv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4241 ppc_fneg (code
, ins
->dreg
, ins
->sreg1
);
4245 g_assert_not_reached ();
4248 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
4251 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
4252 ppc_li (code
, ins
->dreg
, 0);
4253 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 2);
4254 ppc_li (code
, ins
->dreg
, 1);
4257 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
4258 ppc_li (code
, ins
->dreg
, 1);
4259 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
4260 ppc_li (code
, ins
->dreg
, 0);
4263 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
4264 ppc_li (code
, ins
->dreg
, 1);
4265 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 3);
4266 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
4267 ppc_li (code
, ins
->dreg
, 0);
4270 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
4271 ppc_li (code
, ins
->dreg
, 1);
4272 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
4273 ppc_li (code
, ins
->dreg
, 0);
4276 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
4277 ppc_li (code
, ins
->dreg
, 1);
4278 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 3);
4279 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
4280 ppc_li (code
, ins
->dreg
, 0);
4283 EMIT_COND_BRANCH (ins
, CEE_BEQ
- CEE_BEQ
);
4286 EMIT_COND_BRANCH (ins
, CEE_BNE_UN
- CEE_BEQ
);
4289 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4290 EMIT_COND_BRANCH (ins
, CEE_BLT
- CEE_BEQ
);
4293 EMIT_COND_BRANCH_FLAGS (ins
, PPC_BR_TRUE
, PPC_BR_SO
);
4294 EMIT_COND_BRANCH (ins
, CEE_BLT_UN
- CEE_BEQ
);
4297 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4298 EMIT_COND_BRANCH (ins
, CEE_BGT
- CEE_BEQ
);
4301 EMIT_COND_BRANCH_FLAGS (ins
, PPC_BR_TRUE
, PPC_BR_SO
);
4302 EMIT_COND_BRANCH (ins
, CEE_BGT_UN
- CEE_BEQ
);
4305 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4306 EMIT_COND_BRANCH (ins
, CEE_BGE
- CEE_BEQ
);
4309 EMIT_COND_BRANCH (ins
, CEE_BGE_UN
- CEE_BEQ
);
4312 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4313 EMIT_COND_BRANCH (ins
, CEE_BLE
- CEE_BEQ
);
4316 EMIT_COND_BRANCH (ins
, CEE_BLE_UN
- CEE_BEQ
);
4319 g_assert_not_reached ();
4320 case OP_CHECK_FINITE
: {
4321 ppc_rlwinm (code
, ins
->sreg1
, ins
->sreg1
, 0, 1, 31);
4322 ppc_addis (code
, ins
->sreg1
, ins
->sreg1
, -32752);
4323 ppc_rlwinmd (code
, ins
->sreg1
, ins
->sreg1
, 1, 31, 31);
4324 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ
- CEE_BEQ
, "ArithmeticException");
4327 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_c1
, ins
->inst_p0
);
4328 #ifdef __mono_ppc64__
4329 ppc_load_sequence (code
, ins
->dreg
, (guint64
)0x0f0f0f0f0f0f0f0fLL
);
4331 ppc_load_sequence (code
, ins
->dreg
, (gulong
)0x0f0f0f0fL
);
4336 #ifdef __mono_ppc64__
4337 case OP_ICONV_TO_I4
:
4339 ppc_extsw (code
, ins
->dreg
, ins
->sreg1
);
4341 case OP_ICONV_TO_U4
:
4343 ppc_clrldi (code
, ins
->dreg
, ins
->sreg1
, 32);
4345 case OP_ICONV_TO_R4
:
4346 case OP_ICONV_TO_R8
:
4347 case OP_LCONV_TO_R4
:
4348 case OP_LCONV_TO_R8
: {
4350 if (ins
->opcode
== OP_ICONV_TO_R4
|| ins
->opcode
== OP_ICONV_TO_R8
) {
4351 ppc_extsw (code
, ppc_r0
, ins
->sreg1
);
4356 if (cpu_hw_caps
& PPC_MOVE_FPR_GPR
) {
4357 ppc_mffgpr (code
, ins
->dreg
, tmp
);
4359 ppc_str (code
, tmp
, -8, ppc_r1
);
4360 ppc_lfd (code
, ins
->dreg
, -8, ppc_r1
);
4362 ppc_fcfid (code
, ins
->dreg
, ins
->dreg
);
4363 if (ins
->opcode
== OP_ICONV_TO_R4
|| ins
->opcode
== OP_LCONV_TO_R4
)
4364 ppc_frsp (code
, ins
->dreg
, ins
->dreg
);
4368 ppc_srad (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4371 ppc_srd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4374 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4376 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
4377 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1 << 13)); /* CA */
4378 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, ins
->inst_p1
);
4380 case OP_COND_EXC_OV
:
4381 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
4382 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1 << 14)); /* OV */
4383 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, ins
->inst_p1
);
4395 EMIT_COND_BRANCH (ins
, ins
->opcode
- OP_LBEQ
);
4397 case OP_FCONV_TO_I8
:
4398 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 8, TRUE
);
4400 case OP_FCONV_TO_U8
:
4401 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 8, FALSE
);
4403 case OP_STOREI4_MEMBASE_REG
:
4404 if (ppc_is_imm16 (ins
->inst_offset
)) {
4405 ppc_stw (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
4407 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4408 ppc_stwx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
4411 case OP_STOREI4_MEMINDEX
:
4412 ppc_stwx (code
, ins
->sreg1
, ins
->sreg2
, ins
->inst_destbasereg
);
4415 ppc_srawi (code
, ins
->dreg
, ins
->sreg1
, (ins
->inst_imm
& 0x1f));
4417 case OP_ISHR_UN_IMM
:
4418 if (ins
->inst_imm
& 0x1f)
4419 ppc_srwi (code
, ins
->dreg
, ins
->sreg1
, (ins
->inst_imm
& 0x1f));
4421 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
4423 case OP_ATOMIC_ADD_NEW_I4
:
4424 case OP_ATOMIC_ADD_NEW_I8
: {
4425 guint8
*loop
= code
, *branch
;
4426 g_assert (ins
->inst_offset
== 0);
4427 if (ins
->opcode
== OP_ATOMIC_ADD_NEW_I4
)
4428 ppc_lwarx (code
, ppc_r0
, 0, ins
->inst_basereg
);
4430 ppc_ldarx (code
, ppc_r0
, 0, ins
->inst_basereg
);
4431 ppc_add (code
, ppc_r0
, ppc_r0
, ins
->sreg2
);
4432 if (ins
->opcode
== OP_ATOMIC_ADD_NEW_I4
)
4433 ppc_stwcxd (code
, ppc_r0
, 0, ins
->inst_basereg
);
4435 ppc_stdcxd (code
, ppc_r0
, 0, ins
->inst_basereg
);
4437 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4438 ppc_patch (branch
, loop
);
4439 ppc_mr (code
, ins
->dreg
, ppc_r0
);
4443 case OP_ICONV_TO_R4
:
4444 case OP_ICONV_TO_R8
: {
4445 if (cpu_hw_caps
& PPC_ISA_64
) {
4446 ppc_srawi(code
, ppc_r0
, ins
->sreg1
, 31);
4447 ppc_stw (code
, ppc_r0
, -8, ppc_r1
);
4448 ppc_stw (code
, ins
->sreg1
, -4, ppc_r1
);
4449 ppc_lfd (code
, ins
->dreg
, -8, ppc_r1
);
4450 ppc_fcfid (code
, ins
->dreg
, ins
->dreg
);
4451 if (ins
->opcode
== OP_ICONV_TO_R4
)
4452 ppc_frsp (code
, ins
->dreg
, ins
->dreg
);
4457 case OP_ATOMIC_CAS_I4
:
4458 CASE_PPC64 (OP_ATOMIC_CAS_I8
) {
4459 int location
= ins
->sreg1
;
4460 int value
= ins
->sreg2
;
4461 int comparand
= ins
->sreg3
;
4462 guint8
*start
, *not_equal
, *lost_reservation
;
4465 if (ins
->opcode
== OP_ATOMIC_CAS_I4
)
4466 ppc_lwarx (code
, ppc_r0
, 0, location
);
4467 #ifdef __mono_ppc64__
4469 ppc_ldarx (code
, ppc_r0
, 0, location
);
4471 ppc_cmp (code
, 0, ins
->opcode
== OP_ATOMIC_CAS_I4
? 0 : 1, ppc_r0
, comparand
);
4474 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4475 if (ins
->opcode
== OP_ATOMIC_CAS_I4
)
4476 ppc_stwcxd (code
, value
, 0, location
);
4477 #ifdef __mono_ppc64__
4479 ppc_stdcxd (code
, value
, 0, location
);
4482 lost_reservation
= code
;
4483 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4484 ppc_patch (lost_reservation
, start
);
4486 ppc_patch (not_equal
, code
);
4487 ppc_mr (code
, ins
->dreg
, ppc_r0
);
4492 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4493 g_assert_not_reached ();
4496 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4497 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4498 mono_inst_name (ins
->opcode
), max_len
, (glong
)(code
- cfg
->native_code
- offset
));
4499 g_assert_not_reached ();
4505 last_offset
= offset
;
4508 cfg
->code_len
= code
- cfg
->native_code
;
4510 #endif /* !DISABLE_JIT */
4513 mono_arch_register_lowlevel_calls (void)
4515 /* The signature doesn't matter */
4516 mono_register_jit_icall (mono_ppc_throw_exception
, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE
);
4519 #ifdef __mono_ppc64__
4520 #define patch_load_sequence(ip,val) do {\
4521 guint16 *__load = (guint16*)(ip); \
4522 g_assert (sizeof (val) == sizeof (gsize)); \
4523 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4524 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4525 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4526 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4529 #define patch_load_sequence(ip,val) do {\
4530 guint16 *__lis_ori = (guint16*)(ip); \
4531 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4532 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4538 mono_arch_patch_code (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, MonoCodeManager
*dyn_code_mp
, gboolean run_cctors
)
4540 MonoJumpInfo
*patch_info
;
4541 gboolean compile_aot
= !run_cctors
;
4543 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
4544 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4545 unsigned char *target
;
4546 gboolean is_fd
= FALSE
;
4548 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
);
4551 switch (patch_info
->type
) {
4552 case MONO_PATCH_INFO_BB
:
4553 case MONO_PATCH_INFO_LABEL
:
4556 /* No need to patch these */
4561 switch (patch_info
->type
) {
4562 case MONO_PATCH_INFO_IP
:
4563 patch_load_sequence (ip
, ip
);
4565 case MONO_PATCH_INFO_METHOD_REL
:
4566 g_assert_not_reached ();
4567 *((gpointer
*)(ip
)) = code
+ patch_info
->data
.offset
;
4569 case MONO_PATCH_INFO_SWITCH
: {
4570 gpointer
*table
= (gpointer
*)patch_info
->data
.table
->table
;
4573 patch_load_sequence (ip
, table
);
4575 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
4576 table
[i
] = (glong
)patch_info
->data
.table
->table
[i
] + code
;
4578 /* we put into the table the absolute address, no need for ppc_patch in this case */
4581 case MONO_PATCH_INFO_METHODCONST
:
4582 case MONO_PATCH_INFO_CLASS
:
4583 case MONO_PATCH_INFO_IMAGE
:
4584 case MONO_PATCH_INFO_FIELD
:
4585 case MONO_PATCH_INFO_VTABLE
:
4586 case MONO_PATCH_INFO_IID
:
4587 case MONO_PATCH_INFO_SFLDA
:
4588 case MONO_PATCH_INFO_LDSTR
:
4589 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
4590 case MONO_PATCH_INFO_LDTOKEN
:
4591 /* from OP_AOTCONST : lis + ori */
4592 patch_load_sequence (ip
, target
);
4594 case MONO_PATCH_INFO_R4
:
4595 case MONO_PATCH_INFO_R8
:
4596 g_assert_not_reached ();
4597 *((gconstpointer
*)(ip
+ 2)) = patch_info
->data
.target
;
4599 case MONO_PATCH_INFO_EXC_NAME
:
4600 g_assert_not_reached ();
4601 *((gconstpointer
*)(ip
+ 1)) = patch_info
->data
.name
;
4603 case MONO_PATCH_INFO_NONE
:
4604 case MONO_PATCH_INFO_BB_OVF
:
4605 case MONO_PATCH_INFO_EXC_OVF
:
4606 /* everything is dealt with at epilog output time */
4608 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4609 case MONO_PATCH_INFO_INTERNAL_METHOD
:
4610 case MONO_PATCH_INFO_ABS
:
4611 case MONO_PATCH_INFO_CLASS_INIT
:
4612 case MONO_PATCH_INFO_RGCTX_FETCH
:
4619 ppc_patch_full (ip
, target
, is_fd
);
4624 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4625 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4626 * the instruction offset immediate for all the registers.
4629 save_registers (MonoCompile
*cfg
, guint8
* code
, int pos
, int base_reg
, gboolean save_lmf
, guint32 used_int_regs
, int cfa_offset
)
4633 for (i
= 13; i
<= 31; i
++) {
4634 if (used_int_regs
& (1 << i
)) {
4635 ppc_str (code
, i
, pos
, base_reg
);
4636 mono_emit_unwind_op_offset (cfg
, code
, i
, pos
- cfa_offset
);
4637 pos
+= sizeof (mgreg_t
);
4641 /* pos is the start of the MonoLMF structure */
4642 int offset
= pos
+ G_STRUCT_OFFSET (MonoLMF
, iregs
);
4643 for (i
= 13; i
<= 31; i
++) {
4644 ppc_str (code
, i
, offset
, base_reg
);
4645 mono_emit_unwind_op_offset (cfg
, code
, i
, offset
- cfa_offset
);
4646 offset
+= sizeof (mgreg_t
);
4648 offset
= pos
+ G_STRUCT_OFFSET (MonoLMF
, fregs
);
4649 for (i
= 14; i
< 32; i
++) {
4650 ppc_stfd (code
, i
, offset
, base_reg
);
4651 offset
+= sizeof (gdouble
);
4658 * Stack frame layout:
4660 * ------------------- sp
4661 * MonoLMF structure or saved registers
4662 * -------------------
4664 * -------------------
4666 * -------------------
4667 * optional 8 bytes for tracing
4668 * -------------------
4669 * param area size is cfg->param_area
4670 * -------------------
4671 * linkage area size is PPC_STACK_PARAM_OFFSET
4672 * ------------------- sp
4676 mono_arch_emit_prolog (MonoCompile
*cfg
)
4678 MonoMethod
*method
= cfg
->method
;
4680 MonoMethodSignature
*sig
;
4682 long alloc_size
, pos
, max_offset
, cfa_offset
;
4688 int tailcall_struct_index
;
4690 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
4693 sig
= mono_method_signature (method
);
4694 cfg
->code_size
= 512 + sig
->param_count
* 32;
4695 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
4699 /* We currently emit unwind info for aot, but don't use it */
4700 mono_emit_unwind_op_def_cfa (cfg
, code
, ppc_r1
, 0);
4702 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
4703 ppc_mflr (code
, ppc_r0
);
4704 ppc_str (code
, ppc_r0
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
4705 mono_emit_unwind_op_offset (cfg
, code
, ppc_lr
, PPC_RET_ADDR_OFFSET
);
4708 alloc_size
= cfg
->stack_offset
;
4711 if (!method
->save_lmf
) {
4712 for (i
= 31; i
>= 13; --i
) {
4713 if (cfg
->used_int_regs
& (1 << i
)) {
4714 pos
+= sizeof (mgreg_t
);
4718 pos
+= sizeof (MonoLMF
);
4722 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4723 if (alloc_size
& (MONO_ARCH_FRAME_ALIGNMENT
- 1)) {
4724 alloc_size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
4725 alloc_size
&= ~(MONO_ARCH_FRAME_ALIGNMENT
- 1);
4728 cfg
->stack_usage
= alloc_size
;
4729 g_assert ((alloc_size
& (MONO_ARCH_FRAME_ALIGNMENT
-1)) == 0);
4731 if (ppc_is_imm16 (-alloc_size
)) {
4732 ppc_str_update (code
, ppc_sp
, -alloc_size
, ppc_sp
);
4733 cfa_offset
= alloc_size
;
4734 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, alloc_size
);
4735 code
= save_registers (cfg
, code
, alloc_size
- pos
, ppc_sp
, method
->save_lmf
, cfg
->used_int_regs
, cfa_offset
);
4738 ppc_addi (code
, ppc_r11
, ppc_sp
, -pos
);
4739 ppc_load (code
, ppc_r0
, -alloc_size
);
4740 ppc_str_update_indexed (code
, ppc_sp
, ppc_sp
, ppc_r0
);
4741 cfa_offset
= alloc_size
;
4742 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, alloc_size
);
4743 code
= save_registers (cfg
, code
, 0, ppc_r11
, method
->save_lmf
, cfg
->used_int_regs
, cfa_offset
);
4746 if (cfg
->frame_reg
!= ppc_sp
) {
4747 ppc_mr (code
, cfg
->frame_reg
, ppc_sp
);
4748 mono_emit_unwind_op_def_cfa_reg (cfg
, code
, cfg
->frame_reg
);
4751 /* store runtime generic context */
4752 if (cfg
->rgctx_var
) {
4753 g_assert (cfg
->rgctx_var
->opcode
== OP_REGOFFSET
&&
4754 (cfg
->rgctx_var
->inst_basereg
== ppc_r1
|| cfg
->rgctx_var
->inst_basereg
== ppc_r31
));
4756 ppc_stptr (code
, MONO_ARCH_RGCTX_REG
, cfg
->rgctx_var
->inst_offset
, cfg
->rgctx_var
->inst_basereg
);
4759 /* compute max_offset in order to use short forward jumps
4760 * we always do it on ppc because the immediate displacement
4761 * for jumps is too small
4764 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4766 bb
->max_offset
= max_offset
;
4768 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
)
4771 MONO_BB_FOR_EACH_INS (bb
, ins
)
4772 max_offset
+= ins_native_length (cfg
, ins
);
4775 /* load arguments allocated to register from the stack */
4778 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
);
4780 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4781 ArgInfo
*ainfo
= &cinfo
->ret
;
4783 inst
= cfg
->vret_addr
;
4786 if (ppc_is_imm16 (inst
->inst_offset
)) {
4787 ppc_stptr (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4789 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4790 ppc_stptr_indexed (code
, ainfo
->reg
, ppc_r11
, inst
->inst_basereg
);
4794 tailcall_struct_index
= 0;
4795 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4796 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4797 inst
= cfg
->args
[pos
];
4799 if (cfg
->verbose_level
> 2)
4800 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->regtype
);
4801 if (inst
->opcode
== OP_REGVAR
) {
4802 if (ainfo
->regtype
== RegTypeGeneral
)
4803 ppc_mr (code
, inst
->dreg
, ainfo
->reg
);
4804 else if (ainfo
->regtype
== RegTypeFP
)
4805 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
4806 else if (ainfo
->regtype
== RegTypeBase
) {
4807 ppc_ldr (code
, ppc_r11
, 0, ppc_sp
);
4808 ppc_ldptr (code
, inst
->dreg
, ainfo
->offset
, ppc_r11
);
4810 g_assert_not_reached ();
4812 if (cfg
->verbose_level
> 2)
4813 g_print ("Argument %ld assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
4815 /* the argument should be put on the stack: FIXME handle size != word */
4816 if (ainfo
->regtype
== RegTypeGeneral
) {
4817 switch (ainfo
->size
) {
4819 if (ppc_is_imm16 (inst
->inst_offset
)) {
4820 ppc_stb (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_stb (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r11
);
4826 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4827 ppc_stbx (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r11
);
4832 if (ppc_is_imm16 (inst
->inst_offset
)) {
4833 ppc_sth (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4835 if (ppc_is_imm32 (inst
->inst_offset
)) {
4836 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4837 ppc_sth (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r11
);
4839 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4840 ppc_sthx (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r11
);
4844 #ifdef __mono_ppc64__
4846 if (ppc_is_imm16 (inst
->inst_offset
)) {
4847 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4849 if (ppc_is_imm32 (inst
->inst_offset
)) {
4850 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4851 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r11
);
4853 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4854 ppc_stwx (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r11
);
4859 if (ppc_is_imm16 (inst
->inst_offset
)) {
4860 ppc_str (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4862 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4863 ppc_str_indexed (code
, ainfo
->reg
, ppc_r11
, inst
->inst_basereg
);
4868 if (ppc_is_imm16 (inst
->inst_offset
+ 4)) {
4869 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4870 ppc_stw (code
, ainfo
->reg
+ 1, inst
->inst_offset
+ 4, inst
->inst_basereg
);
4872 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4873 ppc_addi (code
, ppc_r11
, ppc_r11
, inst
->inst_offset
);
4874 ppc_stw (code
, ainfo
->reg
, 0, ppc_r11
);
4875 ppc_stw (code
, ainfo
->reg
+ 1, 4, ppc_r11
);
4880 if (ppc_is_imm16 (inst
->inst_offset
)) {
4881 ppc_stptr (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4883 if (ppc_is_imm32 (inst
->inst_offset
)) {
4884 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4885 ppc_stptr (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r11
);
4887 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4888 ppc_stptr_indexed (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r11
);
4893 } else if (ainfo
->regtype
== RegTypeBase
) {
4894 g_assert (ppc_is_imm16 (ainfo
->offset
));
4895 /* load the previous stack pointer in r11 */
4896 ppc_ldr (code
, ppc_r11
, 0, ppc_sp
);
4897 ppc_ldptr (code
, ppc_r0
, ainfo
->offset
, ppc_r11
);
4898 switch (ainfo
->size
) {
4900 if (ppc_is_imm16 (inst
->inst_offset
)) {
4901 ppc_stb (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_stb (code
, ppc_r0
, inst
->inst_offset
, ppc_r11
);
4907 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4908 ppc_stbx (code
, ppc_r0
, inst
->inst_basereg
, ppc_r11
);
4913 if (ppc_is_imm16 (inst
->inst_offset
)) {
4914 ppc_sth (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4916 if (ppc_is_imm32 (inst
->inst_offset
)) {
4917 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4918 ppc_sth (code
, ppc_r0
, inst
->inst_offset
, ppc_r11
);
4920 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4921 ppc_sthx (code
, ppc_r0
, inst
->inst_basereg
, ppc_r11
);
4925 #ifdef __mono_ppc64__
4927 if (ppc_is_imm16 (inst
->inst_offset
)) {
4928 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4930 if (ppc_is_imm32 (inst
->inst_offset
)) {
4931 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4932 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, ppc_r11
);
4934 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4935 ppc_stwx (code
, ppc_r0
, inst
->inst_basereg
, ppc_r11
);
4940 if (ppc_is_imm16 (inst
->inst_offset
)) {
4941 ppc_str (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4943 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4944 ppc_str_indexed (code
, ppc_r0
, ppc_r11
, inst
->inst_basereg
);
4949 g_assert (ppc_is_imm16 (ainfo
->offset
+ 4));
4950 if (ppc_is_imm16 (inst
->inst_offset
+ 4)) {
4951 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4952 ppc_lwz (code
, ppc_r0
, ainfo
->offset
+ 4, ppc_r11
);
4953 ppc_stw (code
, ppc_r0
, inst
->inst_offset
+ 4, inst
->inst_basereg
);
4955 /* use r12 to load the 2nd half of the long before we clobber r11. */
4956 ppc_lwz (code
, ppc_r12
, ainfo
->offset
+ 4, ppc_r11
);
4957 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4958 ppc_addi (code
, ppc_r11
, ppc_r11
, inst
->inst_offset
);
4959 ppc_stw (code
, ppc_r0
, 0, ppc_r11
);
4960 ppc_stw (code
, ppc_r12
, 4, ppc_r11
);
4965 if (ppc_is_imm16 (inst
->inst_offset
)) {
4966 ppc_stptr (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4968 if (ppc_is_imm32 (inst
->inst_offset
)) {
4969 ppc_addis (code
, ppc_r11
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4970 ppc_stptr (code
, ppc_r0
, inst
->inst_offset
, ppc_r11
);
4972 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
4973 ppc_stptr_indexed (code
, ppc_r0
, inst
->inst_basereg
, ppc_r11
);
4978 } else if (ainfo
->regtype
== RegTypeFP
) {
4979 g_assert (ppc_is_imm16 (inst
->inst_offset
));
4980 if (ainfo
->size
== 8)
4981 ppc_stfd (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4982 else if (ainfo
->size
== 4)
4983 ppc_stfs (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4985 g_assert_not_reached ();
4986 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
4987 int doffset
= inst
->inst_offset
;
4991 g_assert (ppc_is_imm16 (inst
->inst_offset
));
4992 g_assert (ppc_is_imm16 (inst
->inst_offset
+ ainfo
->vtregs
* sizeof (gpointer
)));
4993 /* FIXME: what if there is no class? */
4994 if (sig
->pinvoke
&& mono_class_from_mono_type (inst
->inst_vtype
))
4995 size
= mono_class_native_size (mono_class_from_mono_type (inst
->inst_vtype
), NULL
);
4996 for (cur_reg
= 0; cur_reg
< ainfo
->vtregs
; ++cur_reg
) {
4999 * Darwin handles 1 and 2 byte
5000 * structs specially by
5001 * loading h/b into the arg
5002 * register. Only done for
5006 ppc_sth (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5008 ppc_stb (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5012 #ifdef __mono_ppc64__
5014 g_assert (cur_reg
== 0);
5015 ppc_sldi (code
, ppc_r0
, ainfo
->reg
,
5016 (sizeof (gpointer
) - ainfo
->bytes
) * 8);
5017 ppc_stptr (code
, ppc_r0
, doffset
, inst
->inst_basereg
);
5021 ppc_stptr (code
, ainfo
->reg
+ cur_reg
, doffset
,
5022 inst
->inst_basereg
);
5025 soffset
+= sizeof (gpointer
);
5026 doffset
+= sizeof (gpointer
);
5028 if (ainfo
->vtsize
) {
5029 /* FIXME: we need to do the shifting here, too */
5032 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5033 ppc_ldr (code
, ppc_r11
, 0, ppc_sp
);
5034 if ((size
& MONO_PPC_32_64_CASE (3, 7)) != 0) {
5035 code
= emit_memcpy (code
, size
- soffset
,
5036 inst
->inst_basereg
, doffset
,
5037 ppc_r11
, ainfo
->offset
+ soffset
);
5039 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (gpointer
),
5040 inst
->inst_basereg
, doffset
,
5041 ppc_r11
, ainfo
->offset
+ soffset
);
5044 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
5045 /* if it was originally a RegTypeBase */
5046 if (ainfo
->offset
) {
5047 /* load the previous stack pointer in r11 */
5048 ppc_ldr (code
, ppc_r11
, 0, ppc_sp
);
5049 ppc_ldptr (code
, ppc_r11
, ainfo
->offset
, ppc_r11
);
5051 ppc_mr (code
, ppc_r11
, ainfo
->reg
);
5054 if (cfg
->tailcall_valuetype_addrs
) {
5055 MonoInst
*addr
= cfg
->tailcall_valuetype_addrs
[tailcall_struct_index
];
5057 g_assert (ppc_is_imm16 (addr
->inst_offset
));
5058 ppc_stptr (code
, ppc_r11
, addr
->inst_offset
, addr
->inst_basereg
);
5060 tailcall_struct_index
++;
5063 g_assert (ppc_is_imm16 (inst
->inst_offset
));
5064 code
= emit_memcpy (code
, ainfo
->vtsize
, inst
->inst_basereg
, inst
->inst_offset
, ppc_r11
, 0);
5065 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5067 g_assert_not_reached ();
5072 if (method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
5073 if (cfg
->compile_aot
)
5074 /* AOT code is only used in the root domain */
5075 ppc_load_ptr (code
, ppc_r3
, 0);
5077 ppc_load_ptr (code
, ppc_r3
, cfg
->domain
);
5078 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
, (gpointer
)"mono_jit_thread_attach");
5079 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
5080 ppc_load_func (code
, ppc_r0
, 0);
5081 ppc_mtlr (code
, ppc_r0
);
5088 if (method
->save_lmf
) {
5089 if (lmf_pthread_key
!= -1) {
5090 emit_tls_access (code
, ppc_r3
, lmf_pthread_key
);
5091 if (tls_mode
!= TLS_MODE_NPTL
&& G_STRUCT_OFFSET (MonoJitTlsData
, lmf
))
5092 ppc_addi (code
, ppc_r3
, ppc_r3
, G_STRUCT_OFFSET (MonoJitTlsData
, lmf
));
5094 if (cfg
->compile_aot
) {
5095 /* Compute the got address which is needed by the PLT entry */
5096 code
= mono_arch_emit_load_got_addr (cfg
->native_code
, code
, cfg
, NULL
);
5098 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
5099 (gpointer
)"mono_get_lmf_addr");
5100 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
5101 ppc_load_func (code
, ppc_r0
, 0);
5102 ppc_mtlr (code
, ppc_r0
);
5108 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5109 /* lmf_offset is the offset from the previous stack pointer,
5110 * alloc_size is the total stack space allocated, so the offset
5111 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5112 * The pointer to the struct is put in ppc_r11 (new_lmf).
5113 * The callee-saved registers are already in the MonoLMF structure
5115 ppc_addi (code
, ppc_r11
, ppc_sp
, alloc_size
- lmf_offset
);
5116 /* ppc_r3 is the result from mono_get_lmf_addr () */
5117 ppc_stptr (code
, ppc_r3
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
), ppc_r11
);
5118 /* new_lmf->previous_lmf = *lmf_addr */
5119 ppc_ldptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r3
);
5120 ppc_stptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r11
);
5121 /* *(lmf_addr) = r11 */
5122 ppc_stptr (code
, ppc_r11
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r3
);
5123 /* save method info */
5124 if (cfg
->compile_aot
)
5126 ppc_load (code
, ppc_r0
, 0);
5128 ppc_load_ptr (code
, ppc_r0
, method
);
5129 ppc_stptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, method
), ppc_r11
);
5130 ppc_stptr (code
, ppc_sp
, G_STRUCT_OFFSET(MonoLMF
, ebp
), ppc_r11
);
5131 /* save the current IP */
5132 if (cfg
->compile_aot
) {
5134 ppc_mflr (code
, ppc_r0
);
5136 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
5137 #ifdef __mono_ppc64__
5138 ppc_load_sequence (code
, ppc_r0
, (guint64
)0x0101010101010101LL
);
5140 ppc_load_sequence (code
, ppc_r0
, (gulong
)0x01010101L
);
5143 ppc_stptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, eip
), ppc_r11
);
5147 code
= mono_arch_instrument_prolog (cfg
, mono_trace_enter_method
, code
, TRUE
);
5149 cfg
->code_len
= code
- cfg
->native_code
;
5150 g_assert (cfg
->code_len
<= cfg
->code_size
);
5157 mono_arch_emit_epilog (MonoCompile
*cfg
)
5159 MonoMethod
*method
= cfg
->method
;
5161 int max_epilog_size
= 16 + 20*4;
5164 if (cfg
->method
->save_lmf
)
5165 max_epilog_size
+= 128;
5167 if (mono_jit_trace_calls
!= NULL
)
5168 max_epilog_size
+= 50;
5170 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
5171 max_epilog_size
+= 50;
5173 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5174 cfg
->code_size
*= 2;
5175 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5176 cfg
->stat_code_reallocs
++;
5180 * Keep in sync with OP_JMP
5182 code
= cfg
->native_code
+ cfg
->code_len
;
5184 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
5185 code
= mono_arch_instrument_epilog (cfg
, mono_trace_leave_method
, code
, TRUE
);
5189 if (method
->save_lmf
) {
5191 pos
+= sizeof (MonoLMF
);
5193 /* save the frame reg in r8 */
5194 ppc_mr (code
, ppc_r8
, cfg
->frame_reg
);
5195 ppc_addi (code
, ppc_r11
, cfg
->frame_reg
, cfg
->stack_usage
- lmf_offset
);
5196 /* r5 = previous_lmf */
5197 ppc_ldptr (code
, ppc_r5
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r11
);
5199 ppc_ldptr (code
, ppc_r6
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
), ppc_r11
);
5200 /* *(lmf_addr) = previous_lmf */
5201 ppc_stptr (code
, ppc_r5
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r6
);
5202 /* FIXME: speedup: there is no actual need to restore the registers if
5203 * we didn't actually change them (idea from Zoltan).
5206 ppc_ldr_multiple (code
, ppc_r13
, G_STRUCT_OFFSET(MonoLMF
, iregs
), ppc_r11
);
5208 /*for (i = 14; i < 32; i++) {
5209 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5211 g_assert (ppc_is_imm16 (cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
));
5212 /* use the saved copy of the frame reg in r8 */
5213 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
5214 ppc_ldr (code
, ppc_r0
, cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
, ppc_r8
);
5215 ppc_mtlr (code
, ppc_r0
);
5217 ppc_addic (code
, ppc_sp
, ppc_r8
, cfg
->stack_usage
);
5219 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
5220 long return_offset
= cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
;
5221 if (ppc_is_imm16 (return_offset
)) {
5222 ppc_ldr (code
, ppc_r0
, return_offset
, cfg
->frame_reg
);
5224 ppc_load (code
, ppc_r11
, return_offset
);
5225 ppc_ldr_indexed (code
, ppc_r0
, cfg
->frame_reg
, ppc_r11
);
5227 ppc_mtlr (code
, ppc_r0
);
5229 if (ppc_is_imm16 (cfg
->stack_usage
)) {
5230 int offset
= cfg
->stack_usage
;
5231 for (i
= 13; i
<= 31; i
++) {
5232 if (cfg
->used_int_regs
& (1 << i
))
5233 offset
-= sizeof (mgreg_t
);
5235 if (cfg
->frame_reg
!= ppc_sp
)
5236 ppc_mr (code
, ppc_r11
, cfg
->frame_reg
);
5237 /* note r31 (possibly the frame register) is restored last */
5238 for (i
= 13; i
<= 31; i
++) {
5239 if (cfg
->used_int_regs
& (1 << i
)) {
5240 ppc_ldr (code
, i
, offset
, cfg
->frame_reg
);
5241 offset
+= sizeof (mgreg_t
);
5244 if (cfg
->frame_reg
!= ppc_sp
)
5245 ppc_addi (code
, ppc_sp
, ppc_r11
, cfg
->stack_usage
);
5247 ppc_addi (code
, ppc_sp
, ppc_sp
, cfg
->stack_usage
);
5249 ppc_load32 (code
, ppc_r11
, cfg
->stack_usage
);
5250 if (cfg
->used_int_regs
) {
5251 ppc_add (code
, ppc_r11
, cfg
->frame_reg
, ppc_r11
);
5252 for (i
= 31; i
>= 13; --i
) {
5253 if (cfg
->used_int_regs
& (1 << i
)) {
5254 pos
+= sizeof (mgreg_t
);
5255 ppc_ldr (code
, i
, -pos
, ppc_r11
);
5258 ppc_mr (code
, ppc_sp
, ppc_r11
);
5260 ppc_add (code
, ppc_sp
, cfg
->frame_reg
, ppc_r11
);
5267 cfg
->code_len
= code
- cfg
->native_code
;
5269 g_assert (cfg
->code_len
< cfg
->code_size
);
5272 #endif /* ifndef DISABLE_JIT */
5274 /* remove once throw_exception_by_name is eliminated */
5276 exception_id_by_name (const char *name
)
5278 if (strcmp (name
, "IndexOutOfRangeException") == 0)
5279 return MONO_EXC_INDEX_OUT_OF_RANGE
;
5280 if (strcmp (name
, "OverflowException") == 0)
5281 return MONO_EXC_OVERFLOW
;
5282 if (strcmp (name
, "ArithmeticException") == 0)
5283 return MONO_EXC_ARITHMETIC
;
5284 if (strcmp (name
, "DivideByZeroException") == 0)
5285 return MONO_EXC_DIVIDE_BY_ZERO
;
5286 if (strcmp (name
, "InvalidCastException") == 0)
5287 return MONO_EXC_INVALID_CAST
;
5288 if (strcmp (name
, "NullReferenceException") == 0)
5289 return MONO_EXC_NULL_REF
;
5290 if (strcmp (name
, "ArrayTypeMismatchException") == 0)
5291 return MONO_EXC_ARRAY_TYPE_MISMATCH
;
5292 if (strcmp (name
, "ArgumentException") == 0)
5293 return MONO_EXC_ARGUMENT
;
5294 g_error ("Unknown intrinsic exception %s\n", name
);
5300 mono_arch_emit_exceptions (MonoCompile
*cfg
)
5302 MonoJumpInfo
*patch_info
;
5305 guint8
* exc_throw_pos
[MONO_EXC_INTRINS_NUM
];
5306 guint8 exc_throw_found
[MONO_EXC_INTRINS_NUM
];
5307 int max_epilog_size
= 50;
5309 for (i
= 0; i
< MONO_EXC_INTRINS_NUM
; i
++) {
5310 exc_throw_pos
[i
] = NULL
;
5311 exc_throw_found
[i
] = 0;
5314 /* count the number of exception infos */
5317 * make sure we have enough space for exceptions
5319 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5320 if (patch_info
->type
== MONO_PATCH_INFO_EXC
) {
5321 i
= exception_id_by_name (patch_info
->data
.target
);
5322 if (!exc_throw_found
[i
]) {
5323 max_epilog_size
+= (2 * PPC_LOAD_SEQUENCE_LENGTH
) + 5 * 4;
5324 exc_throw_found
[i
] = TRUE
;
5326 } else if (patch_info
->type
== MONO_PATCH_INFO_BB_OVF
)
5327 max_epilog_size
+= 12;
5328 else if (patch_info
->type
== MONO_PATCH_INFO_EXC_OVF
) {
5329 MonoOvfJump
*ovfj
= (MonoOvfJump
*)patch_info
->data
.target
;
5330 i
= exception_id_by_name (ovfj
->data
.exception
);
5331 if (!exc_throw_found
[i
]) {
5332 max_epilog_size
+= (2 * PPC_LOAD_SEQUENCE_LENGTH
) + 5 * 4;
5333 exc_throw_found
[i
] = TRUE
;
5335 max_epilog_size
+= 8;
5339 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16)) {
5340 cfg
->code_size
*= 2;
5341 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
5342 cfg
->stat_code_reallocs
++;
5345 code
= cfg
->native_code
+ cfg
->code_len
;
5347 /* add code to raise exceptions */
5348 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5349 switch (patch_info
->type
) {
5350 case MONO_PATCH_INFO_BB_OVF
: {
5351 MonoOvfJump
*ovfj
= (MonoOvfJump
*)patch_info
->data
.target
;
5352 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
5353 /* patch the initial jump */
5354 ppc_patch (ip
, code
);
5355 ppc_bc (code
, ovfj
->b0_cond
, ovfj
->b1_cond
, 2);
5357 ppc_patch (code
- 4, ip
+ 4); /* jump back after the initiali branch */
5358 /* jump back to the true target */
5360 ip
= ovfj
->data
.bb
->native_offset
+ cfg
->native_code
;
5361 ppc_patch (code
- 4, ip
);
5362 patch_info
->type
= MONO_PATCH_INFO_NONE
;
5365 case MONO_PATCH_INFO_EXC_OVF
: {
5366 MonoOvfJump
*ovfj
= (MonoOvfJump
*)patch_info
->data
.target
;
5367 MonoJumpInfo
*newji
;
5368 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
5369 unsigned char *bcl
= code
;
5370 /* patch the initial jump: we arrived here with a call */
5371 ppc_patch (ip
, code
);
5372 ppc_bc (code
, ovfj
->b0_cond
, ovfj
->b1_cond
, 0);
5374 ppc_patch (code
- 4, ip
+ 4); /* jump back after the initiali branch */
5375 /* patch the conditional jump to the right handler */
5376 /* make it processed next */
5377 newji
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfo
));
5378 newji
->type
= MONO_PATCH_INFO_EXC
;
5379 newji
->ip
.i
= bcl
- cfg
->native_code
;
5380 newji
->data
.target
= ovfj
->data
.exception
;
5381 newji
->next
= patch_info
->next
;
5382 patch_info
->next
= newji
;
5383 patch_info
->type
= MONO_PATCH_INFO_NONE
;
5386 case MONO_PATCH_INFO_EXC
: {
5387 MonoClass
*exc_class
;
5389 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
5390 i
= exception_id_by_name (patch_info
->data
.target
);
5391 if (exc_throw_pos
[i
] && !(ip
> exc_throw_pos
[i
] && ip
- exc_throw_pos
[i
] > 50000)) {
5392 ppc_patch (ip
, exc_throw_pos
[i
]);
5393 patch_info
->type
= MONO_PATCH_INFO_NONE
;
5396 exc_throw_pos
[i
] = code
;
5399 exc_class
= mono_class_from_name (mono_defaults
.corlib
, "System", patch_info
->data
.name
);
5400 g_assert (exc_class
);
5402 ppc_patch (ip
, code
);
5403 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5404 ppc_load (code
, ppc_r3
, exc_class
->type_token
);
5405 /* we got here from a conditional call, so the calling ip is set in lr */
5406 ppc_mflr (code
, ppc_r4
);
5407 patch_info
->type
= MONO_PATCH_INFO_INTERNAL_METHOD
;
5408 patch_info
->data
.name
= "mono_arch_throw_corlib_exception";
5409 patch_info
->ip
.i
= code
- cfg
->native_code
;
5410 if (FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) {
5411 ppc_load_func (code
, ppc_r0
, 0);
5412 ppc_mtctr (code
, ppc_r0
);
5413 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5425 cfg
->code_len
= code
- cfg
->native_code
;
5427 g_assert (cfg
->code_len
<= cfg
->code_size
);
5433 try_offset_access (void *value
, guint32 idx
)
5435 register void* me
__asm__ ("r2");
5436 void ***p
= (void***)((char*)me
+ 284);
5437 int idx1
= idx
/ 32;
5438 int idx2
= idx
% 32;
5441 if (value
!= p
[idx1
][idx2
])
5448 setup_tls_access (void)
5452 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5453 size_t conf_size
= 0;
5456 /* FIXME for darwin */
5457 guint32
*ins
, *code
;
5458 guint32 cmplwi_1023
, li_0x48
, blr_ins
;
5462 tls_mode
= TLS_MODE_FAILED
;
5465 if (tls_mode
== TLS_MODE_FAILED
)
5467 if (g_getenv ("MONO_NO_TLS")) {
5468 tls_mode
= TLS_MODE_FAILED
;
5472 if (tls_mode
== TLS_MODE_DETECT
) {
5473 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5474 tls_mode
= TLS_MODE_DARWIN_G4
;
5475 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5476 conf_size
= confstr ( _CS_GNU_LIBPTHREAD_VERSION
, confbuf
, sizeof(confbuf
));
5477 if ((conf_size
> 4) && (strncmp (confbuf
, "NPTL", 4) == 0))
5478 tls_mode
= TLS_MODE_NPTL
;
5479 #elif !defined(TARGET_PS3)
5480 ins
= (guint32
*)pthread_getspecific
;
5481 /* uncond branch to the real method */
5482 if ((*ins
>> 26) == 18) {
5484 val
= (*ins
& ~3) << 6;
5488 ins
= (guint32
*)(long)val
;
5490 ins
= (guint32
*) ((char*)ins
+ val
);
5493 code
= &cmplwi_1023
;
5494 ppc_cmpli (code
, 0, 0, ppc_r3
, 1023);
5496 ppc_li (code
, ppc_r4
, 0x48);
5499 if (*ins
== cmplwi_1023
) {
5500 int found_lwz_284
= 0;
5501 for (ptk
= 0; ptk
< 20; ++ptk
) {
5503 if (!*ins
|| *ins
== blr_ins
)
5505 if ((guint16
)*ins
== 284 && (*ins
>> 26) == 32) {
5510 if (!found_lwz_284
) {
5511 tls_mode
= TLS_MODE_FAILED
;
5514 tls_mode
= TLS_MODE_LTHREADS
;
5515 } else if (*ins
== li_0x48
) {
5517 /* uncond branch to the real method */
5518 if ((*ins
>> 26) == 18) {
5520 val
= (*ins
& ~3) << 6;
5524 ins
= (guint32
*)(long)val
;
5526 ins
= (guint32
*) ((char*)ins
+ val
);
5528 code
= (guint32
*)&val
;
5529 ppc_li (code
, ppc_r0
, 0x7FF2);
5530 if (ins
[1] == val
) {
5531 /* Darwin on G4, implement */
5532 tls_mode
= TLS_MODE_FAILED
;
5535 code
= (guint32
*)&val
;
5536 ppc_mfspr (code
, ppc_r3
, 104);
5537 if (ins
[1] != val
) {
5538 tls_mode
= TLS_MODE_FAILED
;
5541 tls_mode
= TLS_MODE_DARWIN_G5
;
5544 tls_mode
= TLS_MODE_FAILED
;
5548 tls_mode
= TLS_MODE_FAILED
;
5554 if (tls_mode
== TLS_MODE_DETECT
)
5555 tls_mode
= TLS_MODE_FAILED
;
5556 if (tls_mode
== TLS_MODE_FAILED
)
5558 if ((monodomain_key
== -1) && (tls_mode
== TLS_MODE_NPTL
)) {
5559 monodomain_key
= mono_domain_get_tls_offset();
5561 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5562 mono_domain_get_tls_offset returning -1) then use keyed access. */
5563 if (monodomain_key
== -1) {
5564 ptk
= mono_domain_get_tls_key ();
5566 ptk
= mono_pthread_key_for_tls (ptk
);
5568 monodomain_key
= ptk
;
5573 if ((lmf_pthread_key
== -1) && (tls_mode
== TLS_MODE_NPTL
)) {
5574 lmf_pthread_key
= mono_get_lmf_addr_tls_offset();
5576 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5577 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5578 if (lmf_pthread_key
== -1) {
5579 ptk
= mono_pthread_key_for_tls (mono_jit_tls_id
);
5581 /*g_print ("MonoLMF at: %d\n", ptk);*/
5582 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5583 init_tls_failed = 1;
5586 lmf_pthread_key
= ptk
;
5593 mono_arch_setup_jit_tls_data (MonoJitTlsData
*tls
)
5595 setup_tls_access ();
5599 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
5603 #ifdef MONO_ARCH_HAVE_IMT
5605 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5607 #define LOADSTORE_SIZE 4
5608 #define JUMP_IMM_SIZE 12
5609 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5610 #define ENABLE_WRONG_METHOD_CHECK 0
5613 * LOCKING: called with the domain lock held
5616 mono_arch_build_imt_thunk (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
,
5617 gpointer fail_tramp
)
5621 guint8
*code
, *start
;
5623 for (i
= 0; i
< count
; ++i
) {
5624 MonoIMTCheckItem
*item
= imt_entries
[i
];
5625 if (item
->is_equals
) {
5626 if (item
->check_target_idx
) {
5627 if (!item
->compare_done
)
5628 item
->chunk_size
+= CMP_SIZE
;
5629 if (item
->has_target_code
)
5630 item
->chunk_size
+= BR_SIZE
+ JUMP_IMM32_SIZE
;
5632 item
->chunk_size
+= LOADSTORE_SIZE
+ BR_SIZE
+ JUMP_IMM_SIZE
;
5635 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ JUMP_IMM32_SIZE
* 2;
5636 if (!item
->has_target_code
)
5637 item
->chunk_size
+= LOADSTORE_SIZE
;
5639 item
->chunk_size
+= LOADSTORE_SIZE
+ JUMP_IMM_SIZE
;
5640 #if ENABLE_WRONG_METHOD_CHECK
5641 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ 4;
5646 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
;
5647 imt_entries
[item
->check_target_idx
]->compare_done
= TRUE
;
5649 size
+= item
->chunk_size
;
5651 /* the initial load of the vtable address */
5652 size
+= PPC_LOAD_SEQUENCE_LENGTH
+ LOADSTORE_SIZE
;
5654 code
= mono_method_alloc_generic_virtual_thunk (domain
, size
);
5656 code
= mono_domain_code_reserve (domain
, size
);
5661 * We need to save and restore r11 because it might be
5662 * used by the caller as the vtable register, so
5663 * clobbering it will trip up the magic trampoline.
5665 * FIXME: Get rid of this by making sure that r11 is
5666 * not used as the vtable register in interface calls.
5668 ppc_stptr (code
, ppc_r11
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
5669 ppc_load (code
, ppc_r11
, (gsize
)(& (vtable
->vtable
[0])));
5671 for (i
= 0; i
< count
; ++i
) {
5672 MonoIMTCheckItem
*item
= imt_entries
[i
];
5673 item
->code_target
= code
;
5674 if (item
->is_equals
) {
5675 if (item
->check_target_idx
) {
5676 if (!item
->compare_done
) {
5677 ppc_load (code
, ppc_r0
, (gsize
)item
->key
);
5678 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5680 item
->jmp_code
= code
;
5681 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5682 if (item
->has_target_code
) {
5683 ppc_load_ptr (code
, ppc_r0
, item
->value
.target_code
);
5685 ppc_ldptr (code
, ppc_r0
, (sizeof (gpointer
) * item
->value
.vtable_slot
), ppc_r11
);
5686 ppc_ldptr (code
, ppc_r11
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
5688 ppc_mtctr (code
, ppc_r0
);
5689 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5692 ppc_load (code
, ppc_r0
, (gulong
)item
->key
);
5693 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5694 item
->jmp_code
= code
;
5695 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5696 if (item
->has_target_code
) {
5697 ppc_load_ptr (code
, ppc_r0
, item
->value
.target_code
);
5700 ppc_load_ptr (code
, ppc_r0
, & (vtable
->vtable
[item
->value
.vtable_slot
]));
5701 ppc_ldptr_indexed (code
, ppc_r0
, 0, ppc_r0
);
5703 ppc_mtctr (code
, ppc_r0
);
5704 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5705 ppc_patch (item
->jmp_code
, code
);
5706 ppc_load_ptr (code
, ppc_r0
, fail_tramp
);
5707 ppc_mtctr (code
, ppc_r0
);
5708 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5709 item
->jmp_code
= NULL
;
5711 /* enable the commented code to assert on wrong method */
5712 #if ENABLE_WRONG_METHOD_CHECK
5713 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5714 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5715 item
->jmp_code
= code
;
5716 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5718 ppc_ldptr (code
, ppc_r0
, (sizeof (gpointer
) * item
->value
.vtable_slot
), ppc_r11
);
5719 ppc_ldptr (code
, ppc_r11
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
5720 ppc_mtctr (code
, ppc_r0
);
5721 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5722 #if ENABLE_WRONG_METHOD_CHECK
5723 ppc_patch (item
->jmp_code
, code
);
5725 item
->jmp_code
= NULL
;
5730 ppc_load (code
, ppc_r0
, (gulong
)item
->key
);
5731 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5732 item
->jmp_code
= code
;
5733 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_LT
, 0);
5736 /* patch the branches to get to the target items */
5737 for (i
= 0; i
< count
; ++i
) {
5738 MonoIMTCheckItem
*item
= imt_entries
[i
];
5739 if (item
->jmp_code
) {
5740 if (item
->check_target_idx
) {
5741 ppc_patch (item
->jmp_code
, imt_entries
[item
->check_target_idx
]->code_target
);
5747 mono_stats
.imt_thunks_size
+= code
- start
;
5748 g_assert (code
- start
<= size
);
5749 mono_arch_flush_icache (start
, size
);
5754 mono_arch_find_imt_method (mgreg_t
*regs
, guint8
*code
)
5756 mgreg_t
*r
= (mgreg_t
*)regs
;
5758 return (MonoMethod
*)(gsize
) r
[MONO_ARCH_IMT_REG
];
5763 mono_arch_find_static_call_vtable (mgreg_t
*regs
, guint8
*code
)
5765 mgreg_t
*r
= (mgreg_t
*)regs
;
5767 return (MonoVTable
*)(gsize
) r
[MONO_ARCH_RGCTX_REG
];
5771 mono_arch_get_cie_program (void)
5775 mono_add_unwind_op_def_cfa (l
, (guint8
*)NULL
, (guint8
*)NULL
, ppc_r1
, 0);
5781 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5788 mono_arch_print_tree (MonoInst
*tree
, int arity
)
5793 MonoInst
* mono_arch_get_domain_intrinsic (MonoCompile
* cfg
)
5797 setup_tls_access ();
5798 if (monodomain_key
== -1)
5801 MONO_INST_NEW (cfg
, ins
, OP_TLS_GET
);
5802 ins
->inst_offset
= monodomain_key
;
5807 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5810 return (mgreg_t
)MONO_CONTEXT_GET_SP (ctx
);
5812 g_assert (reg
>= ppc_r13
);
5814 return ctx
->regs
[reg
- ppc_r13
];
5818 mono_arch_get_patch_offset (guint8
*code
)
5824 * mono_aot_emit_load_got_addr:
5826 * Emit code to load the got address.
5827 * On PPC, the result is placed into r30.
5830 mono_arch_emit_load_got_addr (guint8
*start
, guint8
*code
, MonoCompile
*cfg
, MonoJumpInfo
**ji
)
5833 ppc_mflr (code
, ppc_r30
);
5835 mono_add_patch_info (cfg
, code
- start
, MONO_PATCH_INFO_GOT_OFFSET
, NULL
);
5837 *ji
= mono_patch_info_list_prepend (*ji
, code
- start
, MONO_PATCH_INFO_GOT_OFFSET
, NULL
);
5838 /* arch_emit_got_address () patches this */
5839 #if defined(TARGET_POWERPC64)
5845 ppc_load32 (code
, ppc_r0
, 0);
5846 ppc_add (code
, ppc_r30
, ppc_r30
, ppc_r0
);
5853 * mono_ppc_emit_load_aotconst:
5855 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5856 * TARGET from the mscorlib GOT in full-aot code.
5857 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5861 mono_arch_emit_load_aotconst (guint8
*start
, guint8
*code
, MonoJumpInfo
**ji
, int tramp_type
, gconstpointer target
)
5863 /* Load the mscorlib got address */
5864 ppc_ldptr (code
, ppc_r11
, sizeof (gpointer
), ppc_r30
);
5865 *ji
= mono_patch_info_list_prepend (*ji
, code
- start
, tramp_type
, target
);
5866 /* arch_emit_got_access () patches this */
5867 ppc_load32 (code
, ppc_r0
, 0);
5868 ppc_ldptr_indexed (code
, ppc_r11
, ppc_r11
, ppc_r0
);
5873 /* Soft Debug support */
5874 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5881 * mono_arch_set_breakpoint:
5883 * See mini-amd64.c for docs.
5886 mono_arch_set_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5889 guint8
*orig_code
= code
;
5891 ppc_load_sequence (code
, ppc_r11
, (gsize
)bp_trigger_page
);
5892 ppc_ldptr (code
, ppc_r11
, 0, ppc_r11
);
5894 g_assert (code
- orig_code
== BREAKPOINT_SIZE
);
5896 mono_arch_flush_icache (orig_code
, code
- orig_code
);
5900 * mono_arch_clear_breakpoint:
5902 * See mini-amd64.c for docs.
5905 mono_arch_clear_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5910 for (i
= 0; i
< BREAKPOINT_SIZE
/ 4; ++i
)
5913 mono_arch_flush_icache (ip
, code
- ip
);
5917 * mono_arch_is_breakpoint_event:
5919 * See mini-amd64.c for docs.
5922 mono_arch_is_breakpoint_event (void *info
, void *sigctx
)
5924 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5925 /* Sometimes the address is off by 4 */
5926 if (sinfo
->si_addr
>= bp_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)bp_trigger_page
+ 128)
5933 * mono_arch_get_ip_for_breakpoint:
5935 * See mini-amd64.c for docs.
5938 mono_arch_get_ip_for_breakpoint (MonoJitInfo
*ji
, MonoContext
*ctx
)
5940 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
5942 /* ip points at the ldptr instruction */
5943 ip
-= PPC_LOAD_SEQUENCE_LENGTH
;
5949 * mono_arch_skip_breakpoint:
5951 * See mini-amd64.c for docs.
5954 mono_arch_skip_breakpoint (MonoContext
*ctx
)
5956 /* skip the ldptr */
5957 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
5965 * mono_arch_start_single_stepping:
5967 * See mini-amd64.c for docs.
5970 mono_arch_start_single_stepping (void)
5972 mono_mprotect (ss_trigger_page
, mono_pagesize (), 0);
5976 * mono_arch_stop_single_stepping:
5978 * See mini-amd64.c for docs.
5981 mono_arch_stop_single_stepping (void)
5983 mono_mprotect (ss_trigger_page
, mono_pagesize (), MONO_MMAP_READ
);
5987 * mono_arch_is_single_step_event:
5989 * See mini-amd64.c for docs.
5992 mono_arch_is_single_step_event (void *info
, void *sigctx
)
5994 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5995 /* Sometimes the address is off by 4 */
5996 if (sinfo
->si_addr
>= ss_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)ss_trigger_page
+ 128)
6003 * mono_arch_get_ip_for_single_step:
6005 * See mini-amd64.c for docs.
6008 mono_arch_get_ip_for_single_step (MonoJitInfo
*ji
, MonoContext
*ctx
)
6010 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
6012 /* ip points after the ldptr instruction */
6017 * mono_arch_skip_single_step:
6019 * See mini-amd64.c for docs.
6022 mono_arch_skip_single_step (MonoContext
*ctx
)
6024 /* skip the ldptr */
6025 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
6029 * mono_arch_create_seq_point_info:
6031 * See mini-amd64.c for docs.
6034 mono_arch_get_seq_point_info (MonoDomain
*domain
, guint8
*code
)