3 * PowerPC backend for the Mono code generator
6 * Paolo Molaro (lupus@ximian.com)
7 * Dietmar Maurer (dietmar@ximian.com)
8 * Andreas Faerber <andreas.faerber@web.de>
10 * (C) 2003 Ximian, Inc.
11 * (C) 2007-2008 Andreas Faerber
16 #include <mono/metadata/abi-details.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/utils/mono-proclib.h>
20 #include <mono/utils/mono-mmap.h>
21 #include <mono/utils/mono-hwcap.h>
22 #include <mono/utils/unlocked.h>
25 #ifdef TARGET_POWERPC64
26 #include "cpu-ppc64.h"
31 #include "aot-runtime.h"
32 #include "mini-runtime.h"
34 #include <sys/sysctl.h>
40 #include <sys/systemcfg.h>
43 static GENERATE_TRY_GET_CLASS_WITH_CACHE (math
, "System", "Math")
44 static GENERATE_TRY_GET_CLASS_WITH_CACHE (mathf
, "System", "MathF")
46 #define FORCE_INDIR_CALL 1
57 /* cpu_hw_caps contains the flags defined below */
58 static int cpu_hw_caps
= 0;
59 static int cachelinesize
= 0;
60 static int cachelineinc
= 0;
62 PPC_ICACHE_SNOOP
= 1 << 0,
63 PPC_MULTIPLE_LS_UNITS
= 1 << 1,
64 PPC_SMP_CAPABLE
= 1 << 2,
67 PPC_MOVE_FPR_GPR
= 1 << 5,
68 PPC_ISA_2_03
= 1 << 6,
72 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
74 /* This mutex protects architecture specific caches */
75 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
76 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
77 static mono_mutex_t mini_arch_mutex
;
80 * The code generated for sequence points reads from this location, which is
81 * made read-only when single stepping is enabled.
83 static gpointer ss_trigger_page
;
85 /* Enabled breakpoints read from this trigger page */
86 static gpointer bp_trigger_page
;
88 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
90 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
91 inst->type = STACK_R8; \
93 inst->inst_p0 = (void*)(addr); \
94 mono_bblock_add_inst (cfg->cbb, inst); \
98 mono_arch_regname (int reg
) {
99 static const char rnames
[][4] = {
100 "r0", "sp", "r2", "r3", "r4",
101 "r5", "r6", "r7", "r8", "r9",
102 "r10", "r11", "r12", "r13", "r14",
103 "r15", "r16", "r17", "r18", "r19",
104 "r20", "r21", "r22", "r23", "r24",
105 "r25", "r26", "r27", "r28", "r29",
108 if (reg
>= 0 && reg
< 32)
114 mono_arch_fregname (int reg
) {
115 static const char rnames
[][4] = {
116 "f0", "f1", "f2", "f3", "f4",
117 "f5", "f6", "f7", "f8", "f9",
118 "f10", "f11", "f12", "f13", "f14",
119 "f15", "f16", "f17", "f18", "f19",
120 "f20", "f21", "f22", "f23", "f24",
121 "f25", "f26", "f27", "f28", "f29",
124 if (reg
>= 0 && reg
< 32)
129 /* this function overwrites r0, r11, r12 */
131 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
133 /* unrolled, use the counter in big */
134 if (size
> sizeof (target_mgreg_t
) * 5) {
135 long shifted
= size
/ TARGET_SIZEOF_VOID_P
;
136 guint8
*copy_loop_start
, *copy_loop_jump
;
138 ppc_load (code
, ppc_r0
, shifted
);
139 ppc_mtctr (code
, ppc_r0
);
140 //g_assert (sreg == ppc_r12);
141 ppc_addi (code
, ppc_r11
, dreg
, (doffset
- sizeof (target_mgreg_t
)));
142 ppc_addi (code
, ppc_r12
, sreg
, (soffset
- sizeof (target_mgreg_t
)));
143 copy_loop_start
= code
;
144 ppc_ldptr_update (code
, ppc_r0
, (unsigned int)sizeof (target_mgreg_t
), ppc_r12
);
145 ppc_stptr_update (code
, ppc_r0
, (unsigned int)sizeof (target_mgreg_t
), ppc_r11
);
146 copy_loop_jump
= code
;
147 ppc_bc (code
, PPC_BR_DEC_CTR_NONZERO
, 0, 0);
148 ppc_patch (copy_loop_jump
, copy_loop_start
);
149 size
-= shifted
* sizeof (target_mgreg_t
);
150 doffset
= soffset
= 0;
153 #ifdef __mono_ppc64__
154 /* the hardware has multiple load/store units and the move is long
155 enough to use more then one register, then use load/load/store/store
156 to execute 2 instructions per cycle. */
157 if ((cpu_hw_caps
& PPC_MULTIPLE_LS_UNITS
) && (dreg
!= ppc_r11
) && (sreg
!= ppc_r11
)) {
159 ppc_ldptr (code
, ppc_r0
, soffset
, sreg
);
160 ppc_ldptr (code
, ppc_r11
, soffset
+8, sreg
);
161 ppc_stptr (code
, ppc_r0
, doffset
, dreg
);
162 ppc_stptr (code
, ppc_r11
, doffset
+8, dreg
);
169 ppc_ldr (code
, ppc_r0
, soffset
, sreg
);
170 ppc_str (code
, ppc_r0
, doffset
, dreg
);
176 if ((cpu_hw_caps
& PPC_MULTIPLE_LS_UNITS
) && (dreg
!= ppc_r11
) && (sreg
!= ppc_r11
)) {
178 ppc_lwz (code
, ppc_r0
, soffset
, sreg
);
179 ppc_lwz (code
, ppc_r11
, soffset
+4, sreg
);
180 ppc_stw (code
, ppc_r0
, doffset
, dreg
);
181 ppc_stw (code
, ppc_r11
, doffset
+4, dreg
);
189 ppc_lwz (code
, ppc_r0
, soffset
, sreg
);
190 ppc_stw (code
, ppc_r0
, doffset
, dreg
);
196 ppc_lhz (code
, ppc_r0
, soffset
, sreg
);
197 ppc_sth (code
, ppc_r0
, doffset
, dreg
);
203 ppc_lbz (code
, ppc_r0
, soffset
, sreg
);
204 ppc_stb (code
, ppc_r0
, doffset
, dreg
);
213 * mono_arch_get_argument_info:
214 * @csig: a method signature
215 * @param_count: the number of parameters to consider
216 * @arg_info: an array to store the result infos
218 * Gathers information on parameters such as size, alignment and
219 * padding. arg_info should be large enought to hold param_count + 1 entries.
221 * Returns the size of the activation frame.
224 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
226 #ifdef __mono_ppc64__
230 int k
, frame_size
= 0;
231 int size
, align
, pad
;
234 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
235 frame_size
+= sizeof (target_mgreg_t
);
239 arg_info
[0].offset
= offset
;
242 frame_size
+= sizeof (target_mgreg_t
);
246 arg_info
[0].size
= frame_size
;
248 for (k
= 0; k
< param_count
; k
++) {
251 size
= mono_type_native_stack_size (csig
->params
[k
], (guint32
*)&align
);
253 size
= mini_type_stack_size (csig
->params
[k
], &align
);
255 /* ignore alignment for now */
258 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
259 arg_info
[k
].pad
= pad
;
261 arg_info
[k
+ 1].pad
= 0;
262 arg_info
[k
+ 1].size
= size
;
264 arg_info
[k
+ 1].offset
= offset
;
268 align
= MONO_ARCH_FRAME_ALIGNMENT
;
269 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
270 arg_info
[k
].pad
= pad
;
276 #ifdef __mono_ppc64__
278 is_load_sequence (guint32
*seq
)
280 return ppc_opcode (seq
[0]) == 15 && /* lis */
281 ppc_opcode (seq
[1]) == 24 && /* ori */
282 ppc_opcode (seq
[2]) == 30 && /* sldi */
283 ppc_opcode (seq
[3]) == 25 && /* oris */
284 ppc_opcode (seq
[4]) == 24; /* ori */
287 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
288 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
292 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
294 /* code must point to the blrl */
296 mono_ppc_is_direct_call_sequence (guint32
*code
)
298 #ifdef __mono_ppc64__
299 g_assert(*code
== 0x4e800021 || *code
== 0x4e800020 || *code
== 0x4e800420);
301 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
302 if (ppc_opcode (code
[-1]) == 31) { /* mtlr */
303 if (ppc_is_load_op (code
[-2]) && ppc_is_load_op (code
[-3])) { /* ld/ld */
304 if (!is_load_sequence (&code
[-8]))
306 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
307 return (ppc_load_get_dest (code
[-2]) == ppc_r2
&& ppc_load_get_off (code
[-2]) == sizeof (target_mgreg_t
)) ||
308 (ppc_load_get_dest (code
[-3]) == ppc_r2
&& ppc_load_get_off (code
[-3]) == sizeof (target_mgreg_t
));
310 if (ppc_opcode (code
[-2]) == 24 && ppc_opcode (code
[-3]) == 31) /* mr/nop */
311 return is_load_sequence (&code
[-8]);
313 return is_load_sequence (&code
[-6]);
317 g_assert(*code
== 0x4e800021);
319 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
320 return ppc_opcode (code
[-1]) == 31 &&
321 ppc_opcode (code
[-2]) == 24 &&
322 ppc_opcode (code
[-3]) == 15;
326 #define MAX_ARCH_DELEGATE_PARAMS 7
329 get_delegate_invoke_impl (MonoTrampInfo
**info
, gboolean has_target
, guint32 param_count
, gboolean aot
)
331 guint8
*code
, *start
;
334 int size
= MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE
;
336 start
= code
= mono_global_codeman_reserve (size
);
338 code
= mono_ppc_create_pre_code_ftnptr (code
);
340 /* Replace the this argument with the target */
341 ppc_ldptr (code
, ppc_r0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
), ppc_r3
);
342 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
343 /* it's a function descriptor */
344 /* Can't use ldptr as it doesn't work with r0 */
345 ppc_ldptr_indexed (code
, ppc_r0
, 0, ppc_r0
);
347 ppc_mtctr (code
, ppc_r0
);
348 ppc_ldptr (code
, ppc_r3
, MONO_STRUCT_OFFSET (MonoDelegate
, target
), ppc_r3
);
349 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
351 g_assert ((code
- start
) <= size
);
353 mono_arch_flush_icache (start
, size
);
354 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE
, NULL
));
358 size
= MONO_PPC_32_64_CASE (32, 32) + param_count
* 4 + PPC_FTNPTR_SIZE
;
359 start
= code
= mono_global_codeman_reserve (size
);
361 code
= mono_ppc_create_pre_code_ftnptr (code
);
363 ppc_ldptr (code
, ppc_r0
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
), ppc_r3
);
364 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
365 /* it's a function descriptor */
366 ppc_ldptr_indexed (code
, ppc_r0
, 0, ppc_r0
);
368 ppc_mtctr (code
, ppc_r0
);
369 /* slide down the arguments */
370 for (i
= 0; i
< param_count
; ++i
) {
371 ppc_mr (code
, (ppc_r3
+ i
), (ppc_r3
+ i
+ 1));
373 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
375 g_assert ((code
- start
) <= size
);
377 mono_arch_flush_icache (start
, size
);
378 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE
, NULL
));
382 *info
= mono_tramp_info_create ("delegate_invoke_impl_has_target", start
, code
- start
, NULL
, NULL
);
384 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", param_count
);
385 *info
= mono_tramp_info_create (name
, start
, code
- start
, NULL
, NULL
);
393 mono_arch_get_delegate_invoke_impls (void)
399 get_delegate_invoke_impl (&info
, TRUE
, 0, TRUE
);
400 res
= g_slist_prepend (res
, info
);
402 for (i
= 0; i
<= MAX_ARCH_DELEGATE_PARAMS
; ++i
) {
403 get_delegate_invoke_impl (&info
, FALSE
, i
, TRUE
);
404 res
= g_slist_prepend (res
, info
);
411 mono_arch_get_delegate_invoke_impl (MonoMethodSignature
*sig
, gboolean has_target
)
413 guint8
*code
, *start
;
415 /* FIXME: Support more cases */
416 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
420 static guint8
* cached
= NULL
;
425 if (mono_ee_features
.use_aot_trampolines
) {
426 start
= mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
429 start
= get_delegate_invoke_impl (&info
, TRUE
, 0, FALSE
);
430 mono_tramp_info_register (info
, NULL
);
432 mono_memory_barrier ();
436 static guint8
* cache
[MAX_ARCH_DELEGATE_PARAMS
+ 1] = {NULL
};
439 if (sig
->param_count
> MAX_ARCH_DELEGATE_PARAMS
)
441 for (i
= 0; i
< sig
->param_count
; ++i
)
442 if (!mono_is_regsize_var (sig
->params
[i
]))
446 code
= cache
[sig
->param_count
];
450 if (mono_ee_features
.use_aot_trampolines
) {
451 char *name
= g_strdup_printf ("delegate_invoke_impl_target_%d", sig
->param_count
);
452 start
= mono_aot_get_trampoline (name
);
456 start
= get_delegate_invoke_impl (&info
, FALSE
, sig
->param_count
, FALSE
);
457 mono_tramp_info_register (info
, NULL
);
460 mono_memory_barrier ();
462 cache
[sig
->param_count
] = start
;
468 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
, int offset
, gboolean load_imt_reg
)
474 mono_arch_get_this_arg_from_call (host_mgreg_t
*r
, guint8
*code
)
476 return (gpointer
)(gsize
)r
[ppc_r3
];
484 #define MAX_AUX_ENTRIES 128
486 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
487 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
489 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
491 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
492 #define ISA_64 0x40000000
494 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
495 #define ISA_MOVE_FPR_GPR 0x00000200
497 * Initialize the cpu to execute managed code.
500 mono_arch_cpu_init (void)
505 * Initialize architecture specific code.
508 mono_arch_init (void)
510 #if defined(MONO_CROSS_COMPILE)
511 #elif defined(__APPLE__)
513 size_t len
= sizeof (cachelinesize
);
516 mib
[1] = HW_CACHELINE
;
518 if (sysctl (mib
, 2, &cachelinesize
, &len
, NULL
, 0) == -1) {
522 cachelineinc
= cachelinesize
;
524 #elif defined(__linux__)
525 AuxVec vec
[MAX_AUX_ENTRIES
];
526 int i
, vec_entries
= 0;
527 /* sadly this will work only with 2.6 kernels... */
528 FILE* f
= fopen ("/proc/self/auxv", "rb");
531 vec_entries
= fread (&vec
, sizeof (AuxVec
), MAX_AUX_ENTRIES
, f
);
535 for (i
= 0; i
< vec_entries
; i
++) {
536 int type
= vec
[i
].type
;
538 if (type
== 19) { /* AT_DCACHEBSIZE */
539 cachelinesize
= vec
[i
].value
;
543 #elif defined(G_COMPILER_CODEWARRIOR)
547 /* FIXME: use block instead? */
548 cachelinesize
= _system_configuration
.icache_line
;
549 cachelineinc
= _system_configuration
.icache_line
;
551 //#error Need a way to get cache line size
554 if (mono_hwcap_ppc_has_icache_snoop
)
555 cpu_hw_caps
|= PPC_ICACHE_SNOOP
;
557 if (mono_hwcap_ppc_is_isa_2x
)
558 cpu_hw_caps
|= PPC_ISA_2X
;
560 if (mono_hwcap_ppc_is_isa_2_03
)
561 cpu_hw_caps
|= PPC_ISA_2_03
;
563 if (mono_hwcap_ppc_is_isa_64
)
564 cpu_hw_caps
|= PPC_ISA_64
;
566 if (mono_hwcap_ppc_has_move_fpr_gpr
)
567 cpu_hw_caps
|= PPC_MOVE_FPR_GPR
;
569 if (mono_hwcap_ppc_has_multiple_ls_units
)
570 cpu_hw_caps
|= PPC_MULTIPLE_LS_UNITS
;
576 cachelineinc
= cachelinesize
;
578 if (mono_cpu_count () > 1)
579 cpu_hw_caps
|= PPC_SMP_CAPABLE
;
581 mono_os_mutex_init_recursive (&mini_arch_mutex
);
583 ss_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
, MONO_MEM_ACCOUNT_OTHER
);
584 bp_trigger_page
= mono_valloc (NULL
, mono_pagesize (), MONO_MMAP_READ
|MONO_MMAP_32BIT
, MONO_MEM_ACCOUNT_OTHER
);
585 mono_mprotect (bp_trigger_page
, mono_pagesize (), 0);
587 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception
);
589 // FIXME: Fix partial sharing for power and remove this
590 mono_set_partial_sharing_supported (FALSE
);
594 * Cleanup architecture specific code.
597 mono_arch_cleanup (void)
599 mono_os_mutex_destroy (&mini_arch_mutex
);
603 mono_arch_have_fast_tls (void)
609 * This function returns the optimizations supported on this cpu.
612 mono_arch_cpu_optimizations (guint32
*exclude_mask
)
616 /* no ppc-specific optimizations yet */
622 * This function test for all SIMD functions supported.
624 * Returns a bitmask corresponding to all supported versions.
628 mono_arch_cpu_enumerate_simd_versions (void)
630 /* SIMD is currently unimplemented */
634 #ifdef __mono_ppc64__
635 #define CASE_PPC32(c)
636 #define CASE_PPC64(c) case c:
638 #define CASE_PPC32(c) case c:
639 #define CASE_PPC64(c)
643 is_regsize_var (MonoType
*t
) {
646 t
= mini_get_underlying_type (t
);
650 CASE_PPC64 (MONO_TYPE_I8
)
651 CASE_PPC64 (MONO_TYPE_U8
)
655 case MONO_TYPE_FNPTR
:
657 case MONO_TYPE_OBJECT
:
658 case MONO_TYPE_STRING
:
659 case MONO_TYPE_CLASS
:
660 case MONO_TYPE_SZARRAY
:
661 case MONO_TYPE_ARRAY
:
663 case MONO_TYPE_GENERICINST
:
664 if (!mono_type_generic_inst_is_valuetype (t
))
667 case MONO_TYPE_VALUETYPE
:
675 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
680 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
681 MonoInst
*ins
= cfg
->varinfo
[i
];
682 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
685 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
688 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
691 /* we can only allocate 32 bit values */
692 if (is_regsize_var (ins
->inst_vtype
)) {
693 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
694 g_assert (i
== vmv
->idx
);
695 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
701 #endif /* ifndef DISABLE_JIT */
704 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
708 if (cfg
->frame_reg
!= ppc_sp
)
710 /* ppc_r13 is used by the system on PPC EABI */
711 for (i
= 14; i
< top
; ++i
) {
713 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
714 * since the trampolines can clobber r12.
716 if (!(cfg
->compile_aot
&& i
== 29))
717 regs
= g_list_prepend (regs
, GUINT_TO_POINTER (i
));
724 * mono_arch_regalloc_cost:
726 * Return the cost, in number of memory references, of the action of
727 * allocating the variable VMV into a register during global register
731 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
738 mono_arch_flush_icache (guint8
*code
, gint size
)
740 #ifdef MONO_CROSS_COMPILE
744 guint8
*endp
, *start
;
748 start
= (guint8
*)((gsize
)start
& ~(cachelinesize
- 1));
749 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
750 #if defined(G_COMPILER_CODEWARRIOR)
751 if (cpu_hw_caps
& PPC_SMP_CAPABLE
) {
752 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
756 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
762 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
773 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
774 * The sync is required to insure that the store queue is completely empty.
775 * While the icbi performs no cache operations, icbi/isync is required to
776 * kill local prefetch.
778 if (cpu_hw_caps
& PPC_ICACHE_SNOOP
) {
780 asm ("icbi 0,%0;" : : "r"(code
) : "memory");
784 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
785 if (cpu_hw_caps
& PPC_SMP_CAPABLE
) {
786 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
787 asm ("dcbf 0,%0;" : : "r"(p
) : "memory");
790 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
791 asm ("dcbst 0,%0;" : : "r"(p
) : "memory");
796 for (p
= start
; p
< endp
; p
+= cachelineinc
) {
797 /* for ISA2.0+ implementations we should not need any extra sync between the
798 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
799 * So I am not sure which chip had this problem but its not an issue on
800 * of the ISA V2 chips.
802 if (cpu_hw_caps
& PPC_ISA_2X
)
803 asm ("icbi 0,%0;" : : "r"(p
) : "memory");
805 asm ("icbi 0,%0; sync;" : : "r"(p
) : "memory");
807 if (!(cpu_hw_caps
& PPC_ISA_2X
))
815 mono_arch_flush_register_windows (void)
820 #define ALWAYS_ON_STACK(s) s
821 #define FP_ALSO_IN_REG(s) s
823 #ifdef __mono_ppc64__
824 #define ALWAYS_ON_STACK(s) s
825 #define FP_ALSO_IN_REG(s) s
827 #define ALWAYS_ON_STACK(s)
828 #define FP_ALSO_IN_REG(s)
830 #define ALIGN_DOUBLES
839 RegTypeFPStructByVal
, // For the v2 ABI, floats should be passed in FRs instead of GRs. Only valid for ABI v2!
844 guint32 vtsize
; /* in param area */
846 guint8 vtregs
; /* number of registers used to pass a RegTypeStructByVal/RegTypeFPStructByVal */
847 guint8 regtype
: 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
848 guint8 size
: 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal/RegTypeFPStructByVal */
849 guint8 bytes
: 4; /* size in bytes - only valid for
850 RegTypeStructByVal/RegTypeFPStructByVal if the struct fits
851 in one word, otherwise it's 0*/
860 gboolean vtype_retaddr
;
868 #if PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS
870 // Test if a structure is completely composed of either float XOR double fields and has fewer than
871 // PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTER members.
872 // If this is true the structure can be returned directly via float registers instead of by a hidden parameter
873 // pointing to where the return value should be stored.
874 // This is as per the ELF ABI v2.
877 is_float_struct_returnable_via_regs (MonoType
*type
, int* member_cnt
, int* member_size
)
879 int local_member_cnt
, local_member_size
;
881 member_cnt
= &local_member_cnt
;
884 member_size
= &local_member_size
;
887 gboolean is_all_floats
= mini_type_is_hfa(type
, member_cnt
, member_size
);
888 return is_all_floats
&& (*member_cnt
<= PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTERS
);
892 #define is_float_struct_returnable_via_regs(a,b,c) (FALSE)
896 #if PPC_RETURN_SMALL_STRUCTS_IN_REGS
898 // Test if a structure is smaller in size than 2 doublewords (PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS) and is
899 // completely composed of fields all of basic types.
900 // If this is true the structure can be returned directly via registers r3/r4 instead of by a hidden parameter
901 // pointing to where the return value should be stored.
902 // This is as per the ELF ABI v2.
905 is_struct_returnable_via_regs (MonoClass
*klass
, gboolean is_pinvoke
)
907 gboolean has_a_field
= FALSE
;
910 gpointer iter
= NULL
;
913 size
= mono_type_native_stack_size (m_class_get_byval_arg (klass
), 0);
915 size
= mini_type_stack_size (m_class_get_byval_arg (klass
), 0);
918 if (size
> PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS
)
920 while ((f
= mono_class_get_fields_internal (klass
, &iter
))) {
921 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
922 // TBD: Is there a better way to check for the basic types?
923 if (f
->type
->byref
) {
925 } else if ((f
->type
->type
>= MONO_TYPE_BOOLEAN
) && (f
->type
->type
<= MONO_TYPE_R8
)) {
927 } else if (MONO_TYPE_ISSTRUCT (f
->type
)) {
928 MonoClass
*klass
= mono_class_from_mono_type_internal (f
->type
);
929 if (is_struct_returnable_via_regs(klass
, is_pinvoke
)) {
944 #define is_struct_returnable_via_regs(a,b) (FALSE)
949 add_general (guint
*gr
, guint
*stack_size
, ArgInfo
*ainfo
, gboolean simple
)
951 #ifdef __mono_ppc64__
956 if (*gr
>= 3 + PPC_NUM_REG_ARGS
) {
957 ainfo
->offset
= PPC_STACK_PARAM_OFFSET
+ *stack_size
;
958 ainfo
->reg
= ppc_sp
; /* in the caller */
959 ainfo
->regtype
= RegTypeBase
;
960 *stack_size
+= sizeof (target_mgreg_t
);
962 ALWAYS_ON_STACK (*stack_size
+= sizeof (target_mgreg_t
));
966 if (*gr
>= 3 + PPC_NUM_REG_ARGS
- 1) {
968 //*stack_size += (*stack_size % 8);
970 ainfo
->offset
= PPC_STACK_PARAM_OFFSET
+ *stack_size
;
971 ainfo
->reg
= ppc_sp
; /* in the caller */
972 ainfo
->regtype
= RegTypeBase
;
979 ALWAYS_ON_STACK (*stack_size
+= 8);
987 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
989 has_only_a_r48_field (MonoClass
*klass
)
993 gboolean have_field
= FALSE
;
995 while ((f
= mono_class_get_fields_internal (klass
, &iter
))) {
996 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
999 if (!f
->type
->byref
&& (f
->type
->type
== MONO_TYPE_R4
|| f
->type
->type
== MONO_TYPE_R8
))
1010 get_call_info (MonoMethodSignature
*sig
)
1012 guint i
, fr
, gr
, pstart
;
1013 int n
= sig
->hasthis
+ sig
->param_count
;
1014 MonoType
*simpletype
;
1015 guint32 stack_size
= 0;
1016 CallInfo
*cinfo
= g_malloc0 (sizeof (CallInfo
) + sizeof (ArgInfo
) * n
);
1017 gboolean is_pinvoke
= sig
->pinvoke
;
1019 fr
= PPC_FIRST_FPARG_REG
;
1020 gr
= PPC_FIRST_ARG_REG
;
1022 if (mini_type_is_vtype (sig
->ret
)) {
1023 cinfo
->vtype_retaddr
= TRUE
;
1029 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1030 * the first argument, allowing 'this' to be always passed in the first arg reg.
1031 * Also do this if the first argument is a reference type, since virtual calls
1032 * are sometimes made using calli without sig->hasthis set, like in the delegate
1035 if (cinfo
->vtype_retaddr
&& !is_pinvoke
&& (sig
->hasthis
|| (sig
->param_count
> 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig
->params
[0]))))) {
1037 add_general (&gr
, &stack_size
, cinfo
->args
+ 0, TRUE
);
1040 add_general (&gr
, &stack_size
, &cinfo
->args
[sig
->hasthis
+ 0], TRUE
);
1044 add_general (&gr
, &stack_size
, &cinfo
->ret
, TRUE
);
1045 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1046 cinfo
->vret_arg_index
= 1;
1050 add_general (&gr
, &stack_size
, cinfo
->args
+ 0, TRUE
);
1054 if (cinfo
->vtype_retaddr
) {
1055 add_general (&gr
, &stack_size
, &cinfo
->ret
, TRUE
);
1056 cinfo
->struct_ret
= cinfo
->ret
.reg
;
1060 DEBUG(printf("params: %d\n", sig
->param_count
));
1061 for (i
= pstart
; i
< sig
->param_count
; ++i
) {
1062 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1063 /* Prevent implicit arguments and sig_cookie from
1064 being passed in registers */
1065 gr
= PPC_LAST_ARG_REG
+ 1;
1066 /* FIXME: don't we have to set fr, too? */
1067 /* Emit the signature cookie just before the implicit arguments */
1068 add_general (&gr
, &stack_size
, &cinfo
->sig_cookie
, TRUE
);
1070 DEBUG(printf("param %d: ", i
));
1071 if (sig
->params
[i
]->byref
) {
1072 DEBUG(printf("byref\n"));
1073 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1077 simpletype
= mini_get_underlying_type (sig
->params
[i
]);
1078 switch (simpletype
->type
) {
1079 case MONO_TYPE_BOOLEAN
:
1082 cinfo
->args
[n
].size
= 1;
1083 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1086 case MONO_TYPE_CHAR
:
1089 cinfo
->args
[n
].size
= 2;
1090 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1095 cinfo
->args
[n
].size
= 4;
1096 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1102 case MONO_TYPE_FNPTR
:
1103 case MONO_TYPE_CLASS
:
1104 case MONO_TYPE_OBJECT
:
1105 case MONO_TYPE_STRING
:
1106 case MONO_TYPE_SZARRAY
:
1107 case MONO_TYPE_ARRAY
:
1108 cinfo
->args
[n
].size
= sizeof (target_mgreg_t
);
1109 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1112 case MONO_TYPE_GENERICINST
:
1113 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1114 cinfo
->args
[n
].size
= sizeof (target_mgreg_t
);
1115 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1120 case MONO_TYPE_VALUETYPE
:
1121 case MONO_TYPE_TYPEDBYREF
: {
1123 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->params
[i
]);
1124 if (simpletype
->type
== MONO_TYPE_TYPEDBYREF
)
1125 size
= MONO_ABI_SIZEOF (MonoTypedRef
);
1126 else if (is_pinvoke
)
1127 size
= mono_class_native_size (klass
, NULL
);
1129 size
= mono_class_value_size (klass
, NULL
);
1131 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1132 if ((size
== 4 || size
== 8) && has_only_a_r48_field (klass
)) {
1133 cinfo
->args
[n
].size
= size
;
1135 /* It was 7, now it is 8 in LinuxPPC */
1136 if (fr
<= PPC_LAST_FPARG_REG
) {
1137 cinfo
->args
[n
].regtype
= RegTypeFP
;
1138 cinfo
->args
[n
].reg
= fr
;
1140 FP_ALSO_IN_REG (gr
++);
1141 #if !defined(__mono_ppc64__)
1143 FP_ALSO_IN_REG (gr
++);
1145 ALWAYS_ON_STACK (stack_size
+= size
);
1147 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
1148 cinfo
->args
[n
].regtype
= RegTypeBase
;
1149 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
1156 DEBUG(printf ("load %d bytes struct\n",
1157 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
)));
1159 #if PPC_PASS_STRUCTS_BY_VALUE
1161 int align_size
= size
;
1163 int rest
= PPC_LAST_ARG_REG
- gr
+ 1;
1166 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1169 gboolean is_all_floats
= is_float_struct_returnable_via_regs (sig
->params
[i
], &mbr_cnt
, &mbr_size
);
1171 if (is_all_floats
) {
1172 rest
= PPC_LAST_FPARG_REG
- fr
+ 1;
1174 // Pass small (<= 8 member) structures entirely made up of either float or double members
1175 // in FR registers. There have to be at least mbr_cnt registers left.
1176 if (is_all_floats
&&
1177 (rest
>= mbr_cnt
)) {
1179 n_in_regs
= MIN (rest
, nregs
);
1180 cinfo
->args
[n
].regtype
= RegTypeFPStructByVal
;
1181 cinfo
->args
[n
].vtregs
= n_in_regs
;
1182 cinfo
->args
[n
].size
= mbr_size
;
1183 cinfo
->args
[n
].vtsize
= nregs
- n_in_regs
;
1184 cinfo
->args
[n
].reg
= fr
;
1186 if (mbr_size
== 4) {
1188 FP_ALSO_IN_REG (gr
+= (n_in_regs
+1)/2);
1191 FP_ALSO_IN_REG (gr
+= (n_in_regs
));
1196 align_size
+= (sizeof (target_mgreg_t
) - 1);
1197 align_size
&= ~(sizeof (target_mgreg_t
) - 1);
1198 nregs
= (align_size
+ sizeof (target_mgreg_t
) -1 ) / sizeof (target_mgreg_t
);
1199 n_in_regs
= MIN (rest
, nregs
);
1203 /* FIXME: check this */
1204 if (size
>= 3 && size
% 4 != 0)
1207 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
1208 cinfo
->args
[n
].vtregs
= n_in_regs
;
1209 cinfo
->args
[n
].size
= n_in_regs
;
1210 cinfo
->args
[n
].vtsize
= nregs
- n_in_regs
;
1211 cinfo
->args
[n
].reg
= gr
;
1215 #ifdef __mono_ppc64__
1216 if (nregs
== 1 && is_pinvoke
)
1217 cinfo
->args
[n
].bytes
= size
;
1220 cinfo
->args
[n
].bytes
= 0;
1221 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
1222 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1223 stack_size
+= nregs
* sizeof (target_mgreg_t
);
1226 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
1227 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
1228 cinfo
->args
[n
].vtsize
= size
;
1235 cinfo
->args
[n
].size
= 8;
1236 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, SIZEOF_REGISTER
== 8);
1240 cinfo
->args
[n
].size
= 4;
1242 /* It was 7, now it is 8 in LinuxPPC */
1243 if (fr
<= PPC_LAST_FPARG_REG
1244 // For non-native vararg calls the parms must go in storage
1245 && !(!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
))
1247 cinfo
->args
[n
].regtype
= RegTypeFP
;
1248 cinfo
->args
[n
].reg
= fr
;
1250 FP_ALSO_IN_REG (gr
++);
1251 ALWAYS_ON_STACK (stack_size
+= SIZEOF_REGISTER
);
1253 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
+ MONO_PPC_32_64_CASE (0, 4);
1254 cinfo
->args
[n
].regtype
= RegTypeBase
;
1255 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
1256 stack_size
+= SIZEOF_REGISTER
;
1261 cinfo
->args
[n
].size
= 8;
1262 /* It was 7, now it is 8 in LinuxPPC */
1263 if (fr
<= PPC_LAST_FPARG_REG
1264 // For non-native vararg calls the parms must go in storage
1265 && !(!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
))
1267 cinfo
->args
[n
].regtype
= RegTypeFP
;
1268 cinfo
->args
[n
].reg
= fr
;
1270 FP_ALSO_IN_REG (gr
+= sizeof (double) / SIZEOF_REGISTER
);
1271 ALWAYS_ON_STACK (stack_size
+= 8);
1273 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
1274 cinfo
->args
[n
].regtype
= RegTypeBase
;
1275 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
1281 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
1286 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
)) {
1287 /* Prevent implicit arguments and sig_cookie from
1288 being passed in registers */
1289 gr
= PPC_LAST_ARG_REG
+ 1;
1290 /* Emit the signature cookie just before the implicit arguments */
1291 add_general (&gr
, &stack_size
, &cinfo
->sig_cookie
, TRUE
);
1295 simpletype
= mini_get_underlying_type (sig
->ret
);
1296 switch (simpletype
->type
) {
1297 case MONO_TYPE_BOOLEAN
:
1302 case MONO_TYPE_CHAR
:
1308 case MONO_TYPE_FNPTR
:
1309 case MONO_TYPE_CLASS
:
1310 case MONO_TYPE_OBJECT
:
1311 case MONO_TYPE_SZARRAY
:
1312 case MONO_TYPE_ARRAY
:
1313 case MONO_TYPE_STRING
:
1314 cinfo
->ret
.reg
= ppc_r3
;
1318 cinfo
->ret
.reg
= ppc_r3
;
1322 cinfo
->ret
.reg
= ppc_f1
;
1323 cinfo
->ret
.regtype
= RegTypeFP
;
1325 case MONO_TYPE_GENERICINST
:
1326 if (!mono_type_generic_inst_is_valuetype (simpletype
)) {
1327 cinfo
->ret
.reg
= ppc_r3
;
1331 case MONO_TYPE_VALUETYPE
:
1333 case MONO_TYPE_TYPEDBYREF
:
1334 case MONO_TYPE_VOID
:
1337 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
1341 /* align stack size to 16 */
1342 DEBUG (printf (" stack size: %d (%d)\n", (stack_size
+ 15) & ~15, stack_size
));
1343 stack_size
= (stack_size
+ 15) & ~15;
1345 cinfo
->stack_usage
= stack_size
;
1352 mono_arch_tailcall_supported (MonoCompile
*cfg
, MonoMethodSignature
*caller_sig
, MonoMethodSignature
*callee_sig
, gboolean virtual_
)
1354 CallInfo
*caller_info
= get_call_info (caller_sig
);
1355 CallInfo
*callee_info
= get_call_info (callee_sig
);
1357 gboolean res
= IS_SUPPORTED_TAILCALL (callee_info
->stack_usage
<= caller_info
->stack_usage
)
1358 && IS_SUPPORTED_TAILCALL (memcmp (&callee_info
->ret
, &caller_info
->ret
, sizeof (caller_info
->ret
)) == 0);
1360 // FIXME ABIs vary as to if this local is in the parameter area or not,
1361 // so this check might not be needed.
1362 for (int i
= 0; res
&& i
< callee_info
->nargs
; ++i
) {
1363 res
= IS_SUPPORTED_TAILCALL (callee_info
->args
[i
].regtype
!= RegTypeStructByAddr
);
1364 /* An address on the callee's stack is passed as the argument */
1367 g_free (caller_info
);
1368 g_free (callee_info
);
1376 * Set var information according to the calling convention. ppc version.
1377 * The locals var stuff should most likely be split in another method.
1380 mono_arch_allocate_vars (MonoCompile
*m
)
1382 MonoMethodSignature
*sig
;
1383 MonoMethodHeader
*header
;
1385 int i
, offset
, size
, align
, curinst
;
1386 int frame_reg
= ppc_sp
;
1388 guint32 locals_stack_size
, locals_stack_align
;
1390 m
->flags
|= MONO_CFG_HAS_SPILLUP
;
1392 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1393 * call convs needs to be handled this way.
1395 if (m
->flags
& MONO_CFG_HAS_VARARGS
)
1396 m
->param_area
= MAX (m
->param_area
, sizeof (target_mgreg_t
)*8);
1397 /* gtk-sharp and other broken code will dllimport vararg functions even with
1398 * non-varargs signatures. Since there is little hope people will get this right
1399 * we assume they won't.
1401 if (m
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
)
1402 m
->param_area
= MAX (m
->param_area
, sizeof (target_mgreg_t
)*8);
1407 * We use the frame register also for any method that has
1408 * exception clauses. This way, when the handlers are called,
1409 * the code will reference local variables using the frame reg instead of
1410 * the stack pointer: if we had to restore the stack pointer, we'd
1411 * corrupt the method frames that are already on the stack (since
1412 * filters get called before stack unwinding happens) when the filter
1413 * code would call any method (this also applies to finally etc.).
1415 if ((m
->flags
& MONO_CFG_HAS_ALLOCA
) || header
->num_clauses
)
1416 frame_reg
= ppc_r31
;
1417 m
->frame_reg
= frame_reg
;
1418 if (frame_reg
!= ppc_sp
) {
1419 m
->used_int_regs
|= 1 << frame_reg
;
1422 sig
= mono_method_signature_internal (m
->method
);
1426 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1427 m
->ret
->opcode
= OP_REGVAR
;
1428 m
->ret
->inst_c0
= m
->ret
->dreg
= ppc_r3
;
1430 /* FIXME: handle long values? */
1431 switch (mini_get_underlying_type (sig
->ret
)->type
) {
1432 case MONO_TYPE_VOID
:
1436 m
->ret
->opcode
= OP_REGVAR
;
1437 m
->ret
->inst_c0
= m
->ret
->dreg
= ppc_f1
;
1440 m
->ret
->opcode
= OP_REGVAR
;
1441 m
->ret
->inst_c0
= m
->ret
->dreg
= ppc_r3
;
1445 /* local vars are at a positive offset from the stack pointer */
1447 * also note that if the function uses alloca, we use ppc_r31
1448 * to point at the local variables.
1450 offset
= PPC_MINIMAL_STACK_SIZE
; /* linkage area */
1451 /* align the offset to 16 bytes: not sure this is needed here */
1453 //offset &= ~(16 - 1);
1455 /* add parameter area size for called functions */
1456 offset
+= m
->param_area
;
1458 offset
&= ~(16 - 1);
1460 /* the MonoLMF structure is stored just below the stack pointer */
1461 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1462 offset
+= sizeof(gpointer
) - 1;
1463 offset
&= ~(sizeof(gpointer
) - 1);
1465 m
->vret_addr
->opcode
= OP_REGOFFSET
;
1466 m
->vret_addr
->inst_basereg
= frame_reg
;
1467 m
->vret_addr
->inst_offset
= offset
;
1469 if (G_UNLIKELY (m
->verbose_level
> 1)) {
1470 printf ("vret_addr =");
1471 mono_print_ins (m
->vret_addr
);
1474 offset
+= sizeof(gpointer
);
1477 offsets
= mono_allocate_stack_slots (m
, FALSE
, &locals_stack_size
, &locals_stack_align
);
1478 if (locals_stack_align
) {
1479 offset
+= (locals_stack_align
- 1);
1480 offset
&= ~(locals_stack_align
- 1);
1482 for (i
= m
->locals_start
; i
< m
->num_varinfo
; i
++) {
1483 if (offsets
[i
] != -1) {
1484 MonoInst
*inst
= m
->varinfo
[i
];
1485 inst
->opcode
= OP_REGOFFSET
;
1486 inst
->inst_basereg
= frame_reg
;
1487 inst
->inst_offset
= offset
+ offsets
[i
];
1489 g_print ("allocating local %d (%s) to %d\n",
1490 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1494 offset
+= locals_stack_size
;
1498 inst
= m
->args
[curinst
];
1499 if (inst
->opcode
!= OP_REGVAR
) {
1500 inst
->opcode
= OP_REGOFFSET
;
1501 inst
->inst_basereg
= frame_reg
;
1502 offset
+= sizeof (target_mgreg_t
) - 1;
1503 offset
&= ~(sizeof (target_mgreg_t
) - 1);
1504 inst
->inst_offset
= offset
;
1505 offset
+= sizeof (target_mgreg_t
);
1510 for (i
= 0; i
< sig
->param_count
; ++i
) {
1511 inst
= m
->args
[curinst
];
1512 if (inst
->opcode
!= OP_REGVAR
) {
1513 inst
->opcode
= OP_REGOFFSET
;
1514 inst
->inst_basereg
= frame_reg
;
1516 size
= mono_type_native_stack_size (sig
->params
[i
], (guint32
*)&align
);
1517 inst
->backend
.is_pinvoke
= 1;
1519 size
= mono_type_size (sig
->params
[i
], &align
);
1521 if (MONO_TYPE_ISSTRUCT (sig
->params
[i
]) && size
< sizeof (target_mgreg_t
))
1522 size
= align
= sizeof (target_mgreg_t
);
1524 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1525 * they are saved using std in the prolog.
1527 align
= sizeof (target_mgreg_t
);
1528 offset
+= align
- 1;
1529 offset
&= ~(align
- 1);
1530 inst
->inst_offset
= offset
;
1536 /* some storage for fp conversions */
1539 m
->arch
.fp_conv_var_offset
= offset
;
1542 /* align the offset to 16 bytes */
1544 offset
&= ~(16 - 1);
1547 m
->stack_offset
= offset
;
1549 if (sig
->call_convention
== MONO_CALL_VARARG
) {
1550 CallInfo
*cinfo
= get_call_info (m
->method
->signature
);
1552 m
->sig_cookie
= cinfo
->sig_cookie
.offset
;
1559 mono_arch_create_vars (MonoCompile
*cfg
)
1561 MonoMethodSignature
*sig
= mono_method_signature_internal (cfg
->method
);
1563 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1564 cfg
->vret_addr
= mono_compile_create_var (cfg
, mono_get_int_type (), OP_ARG
);
1568 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1569 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1573 emit_sig_cookie (MonoCompile
*cfg
, MonoCallInst
*call
, CallInfo
*cinfo
)
1575 int sig_reg
= mono_alloc_ireg (cfg
);
1577 /* FIXME: Add support for signature tokens to AOT */
1578 cfg
->disable_aot
= TRUE
;
1580 MONO_EMIT_NEW_ICONST (cfg
, sig_reg
, (gulong
)call
->signature
);
1581 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
,
1582 ppc_r1
, cinfo
->sig_cookie
.offset
, sig_reg
);
1586 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
1589 MonoMethodSignature
*sig
;
1593 sig
= call
->signature
;
1594 n
= sig
->param_count
+ sig
->hasthis
;
1596 cinfo
= get_call_info (sig
);
1598 for (i
= 0; i
< n
; ++i
) {
1599 ArgInfo
*ainfo
= cinfo
->args
+ i
;
1602 if (i
>= sig
->hasthis
)
1603 t
= sig
->params
[i
- sig
->hasthis
];
1605 t
= mono_get_int_type ();
1606 t
= mini_get_underlying_type (t
);
1608 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (i
== sig
->sentinelpos
))
1609 emit_sig_cookie (cfg
, call
, cinfo
);
1611 in
= call
->args
[i
];
1613 if (ainfo
->regtype
== RegTypeGeneral
) {
1614 #ifndef __mono_ppc64__
1615 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1616 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1617 ins
->dreg
= mono_alloc_ireg (cfg
);
1618 ins
->sreg1
= MONO_LVREG_LS (in
->dreg
);
1619 MONO_ADD_INS (cfg
->cbb
, ins
);
1620 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
+ 1, FALSE
);
1622 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1623 ins
->dreg
= mono_alloc_ireg (cfg
);
1624 ins
->sreg1
= MONO_LVREG_MS (in
->dreg
);
1625 MONO_ADD_INS (cfg
->cbb
, ins
);
1626 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1630 MONO_INST_NEW (cfg
, ins
, OP_MOVE
);
1631 ins
->dreg
= mono_alloc_ireg (cfg
);
1632 ins
->sreg1
= in
->dreg
;
1633 MONO_ADD_INS (cfg
->cbb
, ins
);
1635 mono_call_inst_add_outarg_reg (cfg
, call
, ins
->dreg
, ainfo
->reg
, FALSE
);
1637 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
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
);
1646 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
1647 /* this is further handled in mono_arch_emit_outarg_vt () */
1648 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1649 ins
->opcode
= OP_OUTARG_VT
;
1650 ins
->sreg1
= in
->dreg
;
1651 ins
->klass
= in
->klass
;
1652 ins
->inst_p0
= call
;
1653 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1654 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1655 MONO_ADD_INS (cfg
->cbb
, ins
);
1656 } else if (ainfo
->regtype
== RegTypeFPStructByVal
) {
1657 /* this is further handled in mono_arch_emit_outarg_vt () */
1658 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1659 ins
->opcode
= OP_OUTARG_VT
;
1660 ins
->sreg1
= in
->dreg
;
1661 ins
->klass
= in
->klass
;
1662 ins
->inst_p0
= call
;
1663 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1664 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1665 MONO_ADD_INS (cfg
->cbb
, ins
);
1666 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1667 } else if (ainfo
->regtype
== RegTypeBase
) {
1668 if (!t
->byref
&& ((t
->type
== MONO_TYPE_I8
) || (t
->type
== MONO_TYPE_U8
))) {
1669 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1670 } else if (!t
->byref
&& ((t
->type
== MONO_TYPE_R4
) || (t
->type
== MONO_TYPE_R8
))) {
1671 if (t
->type
== MONO_TYPE_R8
)
1672 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1674 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1676 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, in
->dreg
);
1678 } else if (ainfo
->regtype
== RegTypeFP
) {
1679 if (t
->type
== MONO_TYPE_VALUETYPE
) {
1680 /* this is further handled in mono_arch_emit_outarg_vt () */
1681 MONO_INST_NEW (cfg
, ins
, OP_OUTARG_VT
);
1682 ins
->opcode
= OP_OUTARG_VT
;
1683 ins
->sreg1
= in
->dreg
;
1684 ins
->klass
= in
->klass
;
1685 ins
->inst_p0
= call
;
1686 ins
->inst_p1
= mono_mempool_alloc (cfg
->mempool
, sizeof (ArgInfo
));
1687 memcpy (ins
->inst_p1
, ainfo
, sizeof (ArgInfo
));
1688 MONO_ADD_INS (cfg
->cbb
, ins
);
1690 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1692 int dreg
= mono_alloc_freg (cfg
);
1694 if (ainfo
->size
== 4) {
1695 MONO_EMIT_NEW_UNALU (cfg
, OP_FCONV_TO_R4
, dreg
, in
->dreg
);
1697 MONO_INST_NEW (cfg
, ins
, OP_FMOVE
);
1699 ins
->sreg1
= in
->dreg
;
1700 MONO_ADD_INS (cfg
->cbb
, ins
);
1703 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1704 cfg
->flags
|= MONO_CFG_HAS_FPOUT
;
1707 g_assert_not_reached ();
1711 /* Emit the signature cookie in the case that there is no
1712 additional argument */
1713 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== sig
->sentinelpos
))
1714 emit_sig_cookie (cfg
, call
, cinfo
);
1716 if (cinfo
->struct_ret
) {
1719 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
1720 vtarg
->sreg1
= call
->vret_var
->dreg
;
1721 vtarg
->dreg
= mono_alloc_preg (cfg
);
1722 MONO_ADD_INS (cfg
->cbb
, vtarg
);
1724 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
, cinfo
->struct_ret
, FALSE
);
1727 call
->stack_usage
= cinfo
->stack_usage
;
1728 cfg
->param_area
= MAX (PPC_MINIMAL_PARAM_AREA_SIZE
, MAX (cfg
->param_area
, cinfo
->stack_usage
));
1729 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
1737 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
1739 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p0
;
1740 ArgInfo
*ainfo
= ins
->inst_p1
;
1741 int ovf_size
= ainfo
->vtsize
;
1742 int doffset
= ainfo
->offset
;
1743 int i
, soffset
, dreg
;
1745 if (ainfo
->regtype
== RegTypeStructByVal
) {
1752 * Darwin pinvokes needs some special handling for 1
1753 * and 2 byte arguments
1755 g_assert (ins
->klass
);
1756 if (call
->signature
->pinvoke
)
1757 size
= mono_class_native_size (ins
->klass
, NULL
);
1758 if (size
== 2 || size
== 1) {
1759 int tmpr
= mono_alloc_ireg (cfg
);
1761 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI1_MEMBASE
, tmpr
, src
->dreg
, soffset
);
1763 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI2_MEMBASE
, tmpr
, src
->dreg
, soffset
);
1764 dreg
= mono_alloc_ireg (cfg
);
1765 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, dreg
, tmpr
);
1766 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, FALSE
);
1769 for (i
= 0; i
< ainfo
->vtregs
; ++i
) {
1770 dreg
= mono_alloc_ireg (cfg
);
1771 #if G_BYTE_ORDER == G_BIG_ENDIAN
1772 int antipadding
= 0;
1775 antipadding
= sizeof (target_mgreg_t
) - ainfo
->bytes
;
1777 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1779 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_UN_IMM
, dreg
, dreg
, antipadding
* 8);
1781 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, dreg
, src
->dreg
, soffset
);
1783 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+ i
, FALSE
);
1784 soffset
+= sizeof (target_mgreg_t
);
1787 mini_emit_memcpy (cfg
, ppc_r1
, doffset
+ soffset
, src
->dreg
, soffset
, ovf_size
* sizeof (target_mgreg_t
), TARGET_SIZEOF_VOID_P
);
1788 } else if (ainfo
->regtype
== RegTypeFPStructByVal
) {
1790 for (i
= 0; i
< ainfo
->vtregs
; ++i
) {
1791 int tmpr
= mono_alloc_freg (cfg
);
1792 if (ainfo
->size
== 4)
1793 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, soffset
);
1795 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, soffset
);
1796 dreg
= mono_alloc_freg (cfg
);
1797 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1798 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
+i
, TRUE
);
1799 soffset
+= ainfo
->size
;
1802 mini_emit_memcpy (cfg
, ppc_r1
, doffset
+ soffset
, src
->dreg
, soffset
, ovf_size
* sizeof (target_mgreg_t
), TARGET_SIZEOF_VOID_P
);
1803 } else if (ainfo
->regtype
== RegTypeFP
) {
1804 int tmpr
= mono_alloc_freg (cfg
);
1805 if (ainfo
->size
== 4)
1806 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR4_MEMBASE
, tmpr
, src
->dreg
, 0);
1808 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmpr
, src
->dreg
, 0);
1809 dreg
= mono_alloc_freg (cfg
);
1810 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, dreg
, tmpr
);
1811 mono_call_inst_add_outarg_reg (cfg
, call
, dreg
, ainfo
->reg
, TRUE
);
1813 MonoInst
*vtcopy
= mono_compile_create_var (cfg
, m_class_get_byval_arg (src
->klass
), OP_LOCAL
);
1817 /* FIXME: alignment? */
1818 if (call
->signature
->pinvoke
) {
1819 size
= mono_type_native_stack_size (m_class_get_byval_arg (src
->klass
), NULL
);
1820 vtcopy
->backend
.is_pinvoke
= 1;
1822 size
= mini_type_stack_size (m_class_get_byval_arg (src
->klass
), NULL
);
1825 g_assert (ovf_size
> 0);
1827 EMIT_NEW_VARLOADA (cfg
, load
, vtcopy
, vtcopy
->inst_vtype
);
1828 mini_emit_memcpy (cfg
, load
->dreg
, 0, src
->dreg
, 0, size
, TARGET_SIZEOF_VOID_P
);
1831 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, ppc_r1
, ainfo
->offset
, load
->dreg
);
1833 mono_call_inst_add_outarg_reg (cfg
, call
, load
->dreg
, ainfo
->reg
, FALSE
);
1838 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
1840 MonoType
*ret
= mini_get_underlying_type (mono_method_signature_internal (method
)->ret
);
1842 #ifndef __mono_ppc64__
1843 if (ret
->type
== MONO_TYPE_I8
|| ret
->type
== MONO_TYPE_U8
) {
1846 MONO_INST_NEW (cfg
, ins
, OP_SETLRET
);
1847 ins
->sreg1
= MONO_LVREG_LS (val
->dreg
);
1848 ins
->sreg2
= MONO_LVREG_MS (val
->dreg
);
1849 MONO_ADD_INS (cfg
->cbb
, ins
);
1853 if (ret
->type
== MONO_TYPE_R8
|| ret
->type
== MONO_TYPE_R4
) {
1854 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, cfg
->ret
->dreg
, val
->dreg
);
1858 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, cfg
->ret
->dreg
, val
->dreg
);
1862 mono_arch_is_inst_imm (int opcode
, int imm_opcode
, gint64 imm
)
1867 #endif /* DISABLE_JIT */
1870 * Conditional branches have a small offset, so if it is likely overflowed,
1871 * we do a branch to the end of the method (uncond branches have much larger
1872 * offsets) where we perform the conditional and jump back unconditionally.
1873 * It's slightly slower, since we add two uncond branches, but it's very simple
1874 * with the current patch implementation and such large methods are likely not
1875 * going to be perf critical anyway.
1880 const char *exception
;
1887 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1888 if (0 && ins->inst_true_bb->native_offset) { \
1889 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1891 int br_disp = ins->inst_true_bb->max_offset - offset; \
1892 if (!ppc_is_imm16 (br_disp + 8 * 1024) || !ppc_is_imm16 (br_disp - 8 * 1024)) { \
1893 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1894 ovfj->data.bb = ins->inst_true_bb; \
1895 ovfj->ip_offset = 0; \
1896 ovfj->b0_cond = (b0); \
1897 ovfj->b1_cond = (b1); \
1898 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1901 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1902 ppc_bc (code, (b0), (b1), 0); \
1906 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1908 /* emit an exception if condition is fail
1910 * We assign the extra code used to throw the implicit exceptions
1911 * to cfg->bb_exit as far as the big branch handling is concerned
1913 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1915 int br_disp = cfg->bb_exit->max_offset - offset; \
1916 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1917 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1918 ovfj->data.exception = (exc_name); \
1919 ovfj->ip_offset = code - cfg->native_code; \
1920 ovfj->b0_cond = (b0); \
1921 ovfj->b1_cond = (b1); \
1922 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1924 cfg->bb_exit->max_offset += 24; \
1926 mono_add_patch_info (cfg, code - cfg->native_code, \
1927 MONO_PATCH_INFO_EXC, exc_name); \
1928 ppc_bcl (code, (b0), (b1), 0); \
1932 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1935 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1940 normalize_opcode (int opcode
)
1943 #ifndef MONO_ARCH_ILP32
1944 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE
, OP_LOADI8_MEMBASE
):
1945 return OP_LOAD_MEMBASE
;
1946 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX
, OP_LOADI8_MEMINDEX
):
1947 return OP_LOAD_MEMINDEX
;
1948 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG
, OP_STOREI8_MEMBASE_REG
):
1949 return OP_STORE_MEMBASE_REG
;
1950 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM
, OP_STOREI8_MEMBASE_IMM
):
1951 return OP_STORE_MEMBASE_IMM
;
1952 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX
, OP_STOREI8_MEMINDEX
):
1953 return OP_STORE_MEMINDEX
;
1955 case MONO_PPC_32_64_CASE (OP_ISHR_IMM
, OP_LSHR_IMM
):
1957 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM
, OP_LSHR_UN_IMM
):
1958 return OP_SHR_UN_IMM
;
1965 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1967 MonoInst
*ins
, *n
, *last_ins
= NULL
;
1969 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
1970 switch (normalize_opcode (ins
->opcode
)) {
1972 /* remove unnecessary multiplication with 1 */
1973 if (ins
->inst_imm
== 1) {
1974 if (ins
->dreg
!= ins
->sreg1
) {
1975 ins
->opcode
= OP_MOVE
;
1977 MONO_DELETE_INS (bb
, ins
);
1981 int power2
= mono_is_power_of_two (ins
->inst_imm
);
1983 ins
->opcode
= OP_SHL_IMM
;
1984 ins
->inst_imm
= power2
;
1988 case OP_LOAD_MEMBASE
:
1990 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1991 * OP_LOAD_MEMBASE offset(basereg), reg
1993 if (last_ins
&& normalize_opcode (last_ins
->opcode
) == OP_STORE_MEMBASE_REG
&&
1994 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1995 ins
->inst_offset
== last_ins
->inst_offset
) {
1996 if (ins
->dreg
== last_ins
->sreg1
) {
1997 MONO_DELETE_INS (bb
, ins
);
2000 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2001 ins
->opcode
= OP_MOVE
;
2002 ins
->sreg1
= last_ins
->sreg1
;
2006 * Note: reg1 must be different from the basereg in the second load
2007 * OP_LOAD_MEMBASE offset(basereg), reg1
2008 * OP_LOAD_MEMBASE offset(basereg), reg2
2010 * OP_LOAD_MEMBASE offset(basereg), reg1
2011 * OP_MOVE reg1, reg2
2013 } else if (last_ins
&& normalize_opcode (last_ins
->opcode
) == OP_LOAD_MEMBASE
&&
2014 ins
->inst_basereg
!= last_ins
->dreg
&&
2015 ins
->inst_basereg
== last_ins
->inst_basereg
&&
2016 ins
->inst_offset
== last_ins
->inst_offset
) {
2018 if (ins
->dreg
== last_ins
->dreg
) {
2019 MONO_DELETE_INS (bb
, ins
);
2022 ins
->opcode
= OP_MOVE
;
2023 ins
->sreg1
= last_ins
->dreg
;
2026 //g_assert_not_reached ();
2030 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2031 * OP_LOAD_MEMBASE offset(basereg), reg
2033 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2034 * OP_ICONST reg, imm
2036 } else if (last_ins
&& normalize_opcode (last_ins
->opcode
) == OP_STORE_MEMBASE_IMM
&&
2037 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2038 ins
->inst_offset
== last_ins
->inst_offset
) {
2039 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2040 ins
->opcode
= OP_ICONST
;
2041 ins
->inst_c0
= last_ins
->inst_imm
;
2042 g_assert_not_reached (); // check this rule
2046 case OP_LOADU1_MEMBASE
:
2047 case OP_LOADI1_MEMBASE
:
2048 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
2049 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2050 ins
->inst_offset
== last_ins
->inst_offset
) {
2051 ins
->opcode
= (ins
->opcode
== OP_LOADI1_MEMBASE
) ? OP_ICONV_TO_I1
: OP_ICONV_TO_U1
;
2052 ins
->sreg1
= last_ins
->sreg1
;
2055 case OP_LOADU2_MEMBASE
:
2056 case OP_LOADI2_MEMBASE
:
2057 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
2058 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2059 ins
->inst_offset
== last_ins
->inst_offset
) {
2060 ins
->opcode
= (ins
->opcode
== OP_LOADI2_MEMBASE
) ? OP_ICONV_TO_I2
: OP_ICONV_TO_U2
;
2061 ins
->sreg1
= last_ins
->sreg1
;
2064 #ifdef __mono_ppc64__
2065 case OP_LOADU4_MEMBASE
:
2066 case OP_LOADI4_MEMBASE
:
2067 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
) &&
2068 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
2069 ins
->inst_offset
== last_ins
->inst_offset
) {
2070 ins
->opcode
= (ins
->opcode
== OP_LOADI4_MEMBASE
) ? OP_ICONV_TO_I4
: OP_ICONV_TO_U4
;
2071 ins
->sreg1
= last_ins
->sreg1
;
2076 ins
->opcode
= OP_MOVE
;
2080 if (ins
->dreg
== ins
->sreg1
) {
2081 MONO_DELETE_INS (bb
, ins
);
2085 * OP_MOVE sreg, dreg
2086 * OP_MOVE dreg, sreg
2088 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
2089 ins
->sreg1
== last_ins
->dreg
&&
2090 ins
->dreg
== last_ins
->sreg1
) {
2091 MONO_DELETE_INS (bb
, ins
);
2099 bb
->last_ins
= last_ins
;
2103 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2105 switch (ins
->opcode
) {
2106 case OP_ICONV_TO_R_UN
: {
2107 // This value is OK as-is for both big and little endian because of how it is stored
2108 static const guint64 adjust_val
= 0x4330000000000000ULL
;
2109 int msw_reg
= mono_alloc_ireg (cfg
);
2110 int adj_reg
= mono_alloc_freg (cfg
);
2111 int tmp_reg
= mono_alloc_freg (cfg
);
2112 int basereg
= ppc_sp
;
2114 MONO_EMIT_NEW_ICONST (cfg
, msw_reg
, 0x43300000);
2115 if (!ppc_is_imm16 (offset
+ 4)) {
2116 basereg
= mono_alloc_ireg (cfg
);
2117 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, basereg
, cfg
->frame_reg
, offset
);
2119 #if G_BYTE_ORDER == G_BIG_ENDIAN
2120 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
, msw_reg
);
2121 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
+ 4, ins
->sreg1
);
2123 // For little endian the words are reversed
2124 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
+ 4, msw_reg
);
2125 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
, ins
->sreg1
);
2127 MONO_EMIT_NEW_LOAD_R8 (cfg
, adj_reg
, &adjust_val
);
2128 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmp_reg
, basereg
, offset
);
2129 MONO_EMIT_NEW_BIALU (cfg
, OP_FSUB
, ins
->dreg
, tmp_reg
, adj_reg
);
2130 ins
->opcode
= OP_NOP
;
2133 #ifndef __mono_ppc64__
2134 case OP_ICONV_TO_R4
:
2135 case OP_ICONV_TO_R8
: {
2136 /* If we have a PPC_FEATURE_64 machine we can avoid
2137 this and use the fcfid instruction. Otherwise
2138 on an old 32-bit chip and we have to do this the
2140 if (!(cpu_hw_caps
& PPC_ISA_64
)) {
2141 /* FIXME: change precision for CEE_CONV_R4 */
2142 static const guint64 adjust_val
= 0x4330000080000000ULL
;
2143 int msw_reg
= mono_alloc_ireg (cfg
);
2144 int xored
= mono_alloc_ireg (cfg
);
2145 int adj_reg
= mono_alloc_freg (cfg
);
2146 int tmp_reg
= mono_alloc_freg (cfg
);
2147 int basereg
= ppc_sp
;
2149 if (!ppc_is_imm16 (offset
+ 4)) {
2150 basereg
= mono_alloc_ireg (cfg
);
2151 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, basereg
, cfg
->frame_reg
, offset
);
2153 MONO_EMIT_NEW_ICONST (cfg
, msw_reg
, 0x43300000);
2154 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
, msw_reg
);
2155 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, xored
, ins
->sreg1
, 0x80000000);
2156 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, basereg
, offset
+ 4, xored
);
2157 MONO_EMIT_NEW_LOAD_R8 (cfg
, adj_reg
, (gpointer
)&adjust_val
);
2158 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADR8_MEMBASE
, tmp_reg
, basereg
, offset
);
2159 MONO_EMIT_NEW_BIALU (cfg
, OP_FSUB
, ins
->dreg
, tmp_reg
, adj_reg
);
2160 if (ins
->opcode
== OP_ICONV_TO_R4
)
2161 MONO_EMIT_NEW_UNALU (cfg
, OP_FCONV_TO_R4
, ins
->dreg
, ins
->dreg
);
2162 ins
->opcode
= OP_NOP
;
2168 int msw_reg
= mono_alloc_ireg (cfg
);
2169 int basereg
= ppc_sp
;
2171 if (!ppc_is_imm16 (offset
+ 4)) {
2172 basereg
= mono_alloc_ireg (cfg
);
2173 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IADD_IMM
, basereg
, cfg
->frame_reg
, offset
);
2175 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, basereg
, offset
, ins
->sreg1
);
2176 #if G_BYTE_ORDER == G_BIG_ENDIAN
2177 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, msw_reg
, basereg
, offset
);
2179 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, msw_reg
, basereg
, offset
+4);
2181 MONO_EMIT_NEW_UNALU (cfg
, OP_PPC_CHECK_FINITE
, -1, msw_reg
);
2182 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, ins
->dreg
, ins
->sreg1
);
2183 ins
->opcode
= OP_NOP
;
2186 #ifdef __mono_ppc64__
2188 case OP_IADD_OVF_UN
:
2190 int shifted1_reg
= mono_alloc_ireg (cfg
);
2191 int shifted2_reg
= mono_alloc_ireg (cfg
);
2192 int result_shifted_reg
= mono_alloc_ireg (cfg
);
2194 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHL_IMM
, shifted1_reg
, ins
->sreg1
, 32);
2195 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHL_IMM
, shifted2_reg
, ins
->sreg2
, 32);
2196 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, result_shifted_reg
, shifted1_reg
, shifted2_reg
);
2197 if (ins
->opcode
== OP_IADD_OVF_UN
)
2198 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_UN_IMM
, ins
->dreg
, result_shifted_reg
, 32);
2200 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, ins
->dreg
, result_shifted_reg
, 32);
2201 ins
->opcode
= OP_NOP
;
2211 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*ins
)
2213 switch (ins
->opcode
) {
2215 /* ADC sets the condition code */
2216 MONO_EMIT_NEW_BIALU (cfg
, OP_ADDCC
, MONO_LVREG_LS (ins
->dreg
), MONO_LVREG_LS (ins
->sreg1
), MONO_LVREG_LS (ins
->sreg2
));
2217 MONO_EMIT_NEW_BIALU (cfg
, OP_ADD_OVF_CARRY
, MONO_LVREG_MS (ins
->dreg
), MONO_LVREG_MS (ins
->sreg1
), MONO_LVREG_MS (ins
->sreg2
));
2220 case OP_LADD_OVF_UN
:
2221 /* ADC sets the condition code */
2222 MONO_EMIT_NEW_BIALU (cfg
, OP_ADDCC
, MONO_LVREG_LS (ins
->dreg
), MONO_LVREG_LS (ins
->sreg1
), MONO_LVREG_LS (ins
->sreg2
));
2223 MONO_EMIT_NEW_BIALU (cfg
, OP_ADD_OVF_UN_CARRY
, MONO_LVREG_MS (ins
->dreg
), MONO_LVREG_MS (ins
->sreg1
), MONO_LVREG_MS (ins
->sreg2
));
2227 /* SBB sets the condition code */
2228 MONO_EMIT_NEW_BIALU (cfg
, OP_SUBCC
, MONO_LVREG_LS (ins
->dreg
), MONO_LVREG_LS (ins
->sreg1
), MONO_LVREG_LS (ins
->sreg2
));
2229 MONO_EMIT_NEW_BIALU (cfg
, OP_SUB_OVF_CARRY
, MONO_LVREG_MS (ins
->dreg
), MONO_LVREG_MS (ins
->sreg1
), MONO_LVREG_MS (ins
->sreg2
));
2232 case OP_LSUB_OVF_UN
:
2233 /* SBB sets the condition code */
2234 MONO_EMIT_NEW_BIALU (cfg
, OP_SUBCC
, MONO_LVREG_LS (ins
->dreg
), MONO_LVREG_LS (ins
->sreg1
), MONO_LVREG_LS (ins
->sreg2
));
2235 MONO_EMIT_NEW_BIALU (cfg
, OP_SUB_OVF_UN_CARRY
, MONO_LVREG_MS (ins
->dreg
), MONO_LVREG_MS (ins
->sreg1
), MONO_LVREG_MS (ins
->sreg2
));
2239 /* From gcc generated code */
2240 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_PPC_SUBFIC
, MONO_LVREG_LS (ins
->dreg
), MONO_LVREG_LS (ins
->sreg1
), 0);
2241 MONO_EMIT_NEW_UNALU (cfg
, OP_PPC_SUBFZE
, MONO_LVREG_MS (ins
->dreg
), MONO_LVREG_MS (ins
->sreg1
));
2250 * the branch_b0_table should maintain the order of these
2264 branch_b0_table
[] = {
2279 branch_b1_table
[] = {
2293 #define NEW_INS(cfg,dest,op) do { \
2294 MONO_INST_NEW((cfg), (dest), (op)); \
2295 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2299 map_to_reg_reg_op (int op
)
2308 case OP_COMPARE_IMM
:
2310 case OP_ICOMPARE_IMM
:
2312 case OP_LCOMPARE_IMM
:
2330 case OP_LOAD_MEMBASE
:
2331 return OP_LOAD_MEMINDEX
;
2332 case OP_LOADI4_MEMBASE
:
2333 return OP_LOADI4_MEMINDEX
;
2334 case OP_LOADU4_MEMBASE
:
2335 return OP_LOADU4_MEMINDEX
;
2336 case OP_LOADI8_MEMBASE
:
2337 return OP_LOADI8_MEMINDEX
;
2338 case OP_LOADU1_MEMBASE
:
2339 return OP_LOADU1_MEMINDEX
;
2340 case OP_LOADI2_MEMBASE
:
2341 return OP_LOADI2_MEMINDEX
;
2342 case OP_LOADU2_MEMBASE
:
2343 return OP_LOADU2_MEMINDEX
;
2344 case OP_LOADI1_MEMBASE
:
2345 return OP_LOADI1_MEMINDEX
;
2346 case OP_LOADR4_MEMBASE
:
2347 return OP_LOADR4_MEMINDEX
;
2348 case OP_LOADR8_MEMBASE
:
2349 return OP_LOADR8_MEMINDEX
;
2350 case OP_STOREI1_MEMBASE_REG
:
2351 return OP_STOREI1_MEMINDEX
;
2352 case OP_STOREI2_MEMBASE_REG
:
2353 return OP_STOREI2_MEMINDEX
;
2354 case OP_STOREI4_MEMBASE_REG
:
2355 return OP_STOREI4_MEMINDEX
;
2356 case OP_STOREI8_MEMBASE_REG
:
2357 return OP_STOREI8_MEMINDEX
;
2358 case OP_STORE_MEMBASE_REG
:
2359 return OP_STORE_MEMINDEX
;
2360 case OP_STORER4_MEMBASE_REG
:
2361 return OP_STORER4_MEMINDEX
;
2362 case OP_STORER8_MEMBASE_REG
:
2363 return OP_STORER8_MEMINDEX
;
2364 case OP_STORE_MEMBASE_IMM
:
2365 return OP_STORE_MEMBASE_REG
;
2366 case OP_STOREI1_MEMBASE_IMM
:
2367 return OP_STOREI1_MEMBASE_REG
;
2368 case OP_STOREI2_MEMBASE_IMM
:
2369 return OP_STOREI2_MEMBASE_REG
;
2370 case OP_STOREI4_MEMBASE_IMM
:
2371 return OP_STOREI4_MEMBASE_REG
;
2372 case OP_STOREI8_MEMBASE_IMM
:
2373 return OP_STOREI8_MEMBASE_REG
;
2375 if (mono_op_imm_to_op (op
) == -1)
2376 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op
));
2377 return mono_op_imm_to_op (op
);
2380 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2382 #define compare_opcode_is_unsigned(opcode) \
2383 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2384 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2385 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2386 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2387 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2388 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2389 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2390 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2393 * Remove from the instruction list the instructions that can't be
2394 * represented with very simple instructions with no register
2398 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2400 MonoInst
*ins
, *next
, *temp
, *last_ins
= NULL
;
2403 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2405 switch (ins
->opcode
) {
2406 case OP_IDIV_UN_IMM
:
2409 case OP_IREM_UN_IMM
:
2410 CASE_PPC64 (OP_LREM_IMM
) {
2411 NEW_INS (cfg
, temp
, OP_ICONST
);
2412 temp
->inst_c0
= ins
->inst_imm
;
2413 temp
->dreg
= mono_alloc_ireg (cfg
);
2414 ins
->sreg2
= temp
->dreg
;
2415 if (ins
->opcode
== OP_IDIV_IMM
)
2416 ins
->opcode
= OP_IDIV
;
2417 else if (ins
->opcode
== OP_IREM_IMM
)
2418 ins
->opcode
= OP_IREM
;
2419 else if (ins
->opcode
== OP_IDIV_UN_IMM
)
2420 ins
->opcode
= OP_IDIV_UN
;
2421 else if (ins
->opcode
== OP_IREM_UN_IMM
)
2422 ins
->opcode
= OP_IREM_UN
;
2423 else if (ins
->opcode
== OP_LREM_IMM
)
2424 ins
->opcode
= OP_LREM
;
2426 /* handle rem separately */
2431 CASE_PPC64 (OP_LREM
)
2432 CASE_PPC64 (OP_LREM_UN
) {
2434 /* we change a rem dest, src1, src2 to
2435 * div temp1, src1, src2
2436 * mul temp2, temp1, src2
2437 * sub dest, src1, temp2
2439 if (ins
->opcode
== OP_IREM
|| ins
->opcode
== OP_IREM_UN
) {
2440 NEW_INS (cfg
, mul
, OP_IMUL
);
2441 NEW_INS (cfg
, temp
, ins
->opcode
== OP_IREM
? OP_IDIV
: OP_IDIV_UN
);
2442 ins
->opcode
= OP_ISUB
;
2444 NEW_INS (cfg
, mul
, OP_LMUL
);
2445 NEW_INS (cfg
, temp
, ins
->opcode
== OP_LREM
? OP_LDIV
: OP_LDIV_UN
);
2446 ins
->opcode
= OP_LSUB
;
2448 temp
->sreg1
= ins
->sreg1
;
2449 temp
->sreg2
= ins
->sreg2
;
2450 temp
->dreg
= mono_alloc_ireg (cfg
);
2451 mul
->sreg1
= temp
->dreg
;
2452 mul
->sreg2
= ins
->sreg2
;
2453 mul
->dreg
= mono_alloc_ireg (cfg
);
2454 ins
->sreg2
= mul
->dreg
;
2458 CASE_PPC64 (OP_LADD_IMM
)
2461 if (!ppc_is_imm16 (ins
->inst_imm
)) {
2462 NEW_INS (cfg
, temp
, OP_ICONST
);
2463 temp
->inst_c0
= ins
->inst_imm
;
2464 temp
->dreg
= mono_alloc_ireg (cfg
);
2465 ins
->sreg2
= temp
->dreg
;
2466 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2470 CASE_PPC64 (OP_LSUB_IMM
)
2472 if (!ppc_is_imm16 (-ins
->inst_imm
)) {
2473 NEW_INS (cfg
, temp
, OP_ICONST
);
2474 temp
->inst_c0
= ins
->inst_imm
;
2475 temp
->dreg
= mono_alloc_ireg (cfg
);
2476 ins
->sreg2
= temp
->dreg
;
2477 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2489 gboolean is_imm
= ((ins
->inst_imm
& 0xffff0000) && (ins
->inst_imm
& 0xffff));
2490 #ifdef __mono_ppc64__
2491 if (ins
->inst_imm
& 0xffffffff00000000ULL
)
2495 NEW_INS (cfg
, temp
, OP_ICONST
);
2496 temp
->inst_c0
= ins
->inst_imm
;
2497 temp
->dreg
= mono_alloc_ireg (cfg
);
2498 ins
->sreg2
= temp
->dreg
;
2499 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2508 NEW_INS (cfg
, temp
, OP_ICONST
);
2509 temp
->inst_c0
= ins
->inst_imm
;
2510 temp
->dreg
= mono_alloc_ireg (cfg
);
2511 ins
->sreg2
= temp
->dreg
;
2512 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2514 case OP_COMPARE_IMM
:
2515 case OP_ICOMPARE_IMM
:
2516 CASE_PPC64 (OP_LCOMPARE_IMM
)
2518 /* Branch opts can eliminate the branch */
2519 if (!next
|| (!(MONO_IS_COND_BRANCH_OP (next
) || MONO_IS_COND_EXC (next
) || MONO_IS_SETCC (next
)))) {
2520 ins
->opcode
= OP_NOP
;
2524 if (compare_opcode_is_unsigned (next
->opcode
)) {
2525 if (!ppc_is_uimm16 (ins
->inst_imm
)) {
2526 NEW_INS (cfg
, temp
, OP_ICONST
);
2527 temp
->inst_c0
= ins
->inst_imm
;
2528 temp
->dreg
= mono_alloc_ireg (cfg
);
2529 ins
->sreg2
= temp
->dreg
;
2530 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2533 if (!ppc_is_imm16 (ins
->inst_imm
)) {
2534 NEW_INS (cfg
, temp
, OP_ICONST
);
2535 temp
->inst_c0
= ins
->inst_imm
;
2536 temp
->dreg
= mono_alloc_ireg (cfg
);
2537 ins
->sreg2
= temp
->dreg
;
2538 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2544 CASE_PPC64 (OP_LMUL_IMM
)
2545 if (ins
->inst_imm
== 1) {
2546 ins
->opcode
= OP_MOVE
;
2549 if (ins
->inst_imm
== 0) {
2550 ins
->opcode
= OP_ICONST
;
2554 imm
= mono_is_power_of_two (ins
->inst_imm
);
2556 ins
->opcode
= OP_SHL_IMM
;
2557 ins
->inst_imm
= imm
;
2560 if (!ppc_is_imm16 (ins
->inst_imm
)) {
2561 NEW_INS (cfg
, temp
, OP_ICONST
);
2562 temp
->inst_c0
= ins
->inst_imm
;
2563 temp
->dreg
= mono_alloc_ireg (cfg
);
2564 ins
->sreg2
= temp
->dreg
;
2565 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2568 case OP_LOCALLOC_IMM
:
2569 NEW_INS (cfg
, temp
, OP_ICONST
);
2570 temp
->inst_c0
= ins
->inst_imm
;
2571 temp
->dreg
= mono_alloc_ireg (cfg
);
2572 ins
->sreg1
= temp
->dreg
;
2573 ins
->opcode
= OP_LOCALLOC
;
2575 case OP_LOAD_MEMBASE
:
2576 case OP_LOADI4_MEMBASE
:
2577 CASE_PPC64 (OP_LOADI8_MEMBASE
)
2578 case OP_LOADU4_MEMBASE
:
2579 case OP_LOADI2_MEMBASE
:
2580 case OP_LOADU2_MEMBASE
:
2581 case OP_LOADI1_MEMBASE
:
2582 case OP_LOADU1_MEMBASE
:
2583 case OP_LOADR4_MEMBASE
:
2584 case OP_LOADR8_MEMBASE
:
2585 case OP_STORE_MEMBASE_REG
:
2586 CASE_PPC64 (OP_STOREI8_MEMBASE_REG
)
2587 case OP_STOREI4_MEMBASE_REG
:
2588 case OP_STOREI2_MEMBASE_REG
:
2589 case OP_STOREI1_MEMBASE_REG
:
2590 case OP_STORER4_MEMBASE_REG
:
2591 case OP_STORER8_MEMBASE_REG
:
2592 /* we can do two things: load the immed in a register
2593 * and use an indexed load, or see if the immed can be
2594 * represented as an ad_imm + a load with a smaller offset
2595 * that fits. We just do the first for now, optimize later.
2597 if (ppc_is_imm16 (ins
->inst_offset
))
2599 NEW_INS (cfg
, temp
, OP_ICONST
);
2600 temp
->inst_c0
= ins
->inst_offset
;
2601 temp
->dreg
= mono_alloc_ireg (cfg
);
2602 ins
->sreg2
= temp
->dreg
;
2603 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2605 case OP_STORE_MEMBASE_IMM
:
2606 case OP_STOREI1_MEMBASE_IMM
:
2607 case OP_STOREI2_MEMBASE_IMM
:
2608 case OP_STOREI4_MEMBASE_IMM
:
2609 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM
)
2610 NEW_INS (cfg
, temp
, OP_ICONST
);
2611 temp
->inst_c0
= ins
->inst_imm
;
2612 temp
->dreg
= mono_alloc_ireg (cfg
);
2613 ins
->sreg1
= temp
->dreg
;
2614 ins
->opcode
= map_to_reg_reg_op (ins
->opcode
);
2616 goto loop_start
; /* make it handle the possibly big ins->inst_offset */
2619 if (cfg
->compile_aot
) {
2620 /* Keep these in the aot case */
2623 NEW_INS (cfg
, temp
, OP_ICONST
);
2624 temp
->inst_c0
= (gulong
)ins
->inst_p0
;
2625 temp
->dreg
= mono_alloc_ireg (cfg
);
2626 ins
->inst_basereg
= temp
->dreg
;
2627 ins
->inst_offset
= 0;
2628 ins
->opcode
= ins
->opcode
== OP_R4CONST
? OP_LOADR4_MEMBASE
: OP_LOADR8_MEMBASE
;
2630 /* make it handle the possibly big ins->inst_offset
2631 * later optimize to use lis + load_membase
2637 bb
->last_ins
= last_ins
;
2638 bb
->max_vreg
= cfg
->next_vreg
;
2642 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
2644 long offset
= cfg
->arch
.fp_conv_var_offset
;
2646 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2647 #ifdef __mono_ppc64__
2649 ppc_fctidz (code
, ppc_f0
, sreg
);
2654 ppc_fctiwz (code
, ppc_f0
, sreg
);
2657 if (ppc_is_imm16 (offset
+ sub_offset
)) {
2658 ppc_stfd (code
, ppc_f0
, offset
, cfg
->frame_reg
);
2660 ppc_ldr (code
, dreg
, offset
+ sub_offset
, cfg
->frame_reg
);
2662 ppc_lwz (code
, dreg
, offset
+ sub_offset
, cfg
->frame_reg
);
2664 ppc_load (code
, dreg
, offset
);
2665 ppc_add (code
, dreg
, dreg
, cfg
->frame_reg
);
2666 ppc_stfd (code
, ppc_f0
, 0, dreg
);
2668 ppc_ldr (code
, dreg
, sub_offset
, dreg
);
2670 ppc_lwz (code
, dreg
, sub_offset
, dreg
);
2674 ppc_andid (code
, dreg
, dreg
, 0xff);
2676 ppc_andid (code
, dreg
, dreg
, 0xffff);
2677 #ifdef __mono_ppc64__
2679 ppc_clrldi (code
, dreg
, dreg
, 32);
2683 ppc_extsb (code
, dreg
, dreg
);
2685 ppc_extsh (code
, dreg
, dreg
);
2686 #ifdef __mono_ppc64__
2688 ppc_extsw (code
, dreg
, dreg
);
2695 emit_thunk (guint8
*code
, gconstpointer target
)
2699 /* 2 bytes on 32bit, 5 bytes on 64bit */
2700 ppc_load_sequence (code
, ppc_r0
, target
);
2702 ppc_mtctr (code
, ppc_r0
);
2703 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
2705 mono_arch_flush_icache (p
, code
- p
);
2709 handle_thunk (MonoCompile
*cfg
, MonoDomain
*domain
, guchar
*code
, const guchar
*target
)
2711 MonoJitInfo
*ji
= NULL
;
2712 MonoThunkJitInfo
*info
;
2715 guint8
*orig_target
;
2716 guint8
*target_thunk
;
2719 domain
= mono_domain_get ();
2723 * This can be called multiple times during JITting,
2724 * save the current position in cfg->arch to avoid
2725 * doing a O(n^2) search.
2727 if (!cfg
->arch
.thunks
) {
2728 cfg
->arch
.thunks
= cfg
->thunks
;
2729 cfg
->arch
.thunks_size
= cfg
->thunk_area
;
2731 thunks
= cfg
->arch
.thunks
;
2732 thunks_size
= cfg
->arch
.thunks_size
;
2734 g_print ("thunk failed %p->%p, thunk space=%d method %s", code
, target
, thunks_size
, mono_method_full_name (cfg
->method
, TRUE
));
2735 g_assert_not_reached ();
2738 g_assert (*(guint32
*)thunks
== 0);
2739 emit_thunk (thunks
, target
);
2740 ppc_patch (code
, thunks
);
2742 cfg
->arch
.thunks
+= THUNK_SIZE
;
2743 cfg
->arch
.thunks_size
-= THUNK_SIZE
;
2745 ji
= mini_jit_info_table_find (domain
, (char *) code
, NULL
);
2747 info
= mono_jit_info_get_thunk_info (ji
);
2750 thunks
= (guint8
*) ji
->code_start
+ info
->thunks_offset
;
2751 thunks_size
= info
->thunks_size
;
2753 orig_target
= mono_arch_get_call_target (code
+ 4);
2755 mono_mini_arch_lock ();
2757 target_thunk
= NULL
;
2758 if (orig_target
>= thunks
&& orig_target
< thunks
+ thunks_size
) {
2759 /* The call already points to a thunk, because of trampolines etc. */
2760 target_thunk
= orig_target
;
2762 for (p
= thunks
; p
< thunks
+ thunks_size
; p
+= THUNK_SIZE
) {
2763 if (((guint32
*) p
) [0] == 0) {
2768 /* ppc64 requires 5 instructions, 32bit two instructions */
2769 #ifdef __mono_ppc64__
2770 const int const_load_size
= 5;
2772 const int const_load_size
= 2;
2774 guint32 load
[const_load_size
];
2775 guchar
*templ
= (guchar
*) load
;
2776 ppc_load_sequence (templ
, ppc_r0
, target
);
2777 if (!memcmp (p
, load
, const_load_size
)) {
2778 /* Thunk already points to target */
2786 // g_print ("THUNK: %p %p %p\n", code, target, target_thunk);
2788 if (!target_thunk
) {
2789 mono_mini_arch_unlock ();
2790 g_print ("thunk failed %p->%p, thunk space=%d method %s", code
, target
, thunks_size
, cfg
? mono_method_full_name (cfg
->method
, TRUE
) : mono_method_full_name (jinfo_get_method (ji
), TRUE
));
2791 g_assert_not_reached ();
2794 emit_thunk (target_thunk
, target
);
2795 ppc_patch (code
, target_thunk
);
2797 mono_mini_arch_unlock ();
2802 patch_ins (guint8
*code
, guint32 ins
)
2804 *(guint32
*)code
= ins
;
2805 mono_arch_flush_icache (code
, 4);
2809 ppc_patch_full (MonoCompile
*cfg
, MonoDomain
*domain
, guchar
*code
, const guchar
*target
, gboolean is_fd
)
2811 guint32 ins
= *(guint32
*)code
;
2812 guint32 prim
= ins
>> 26;
2815 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2817 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2818 gint diff
= target
- code
;
2821 if (diff
<= 33554431){
2822 ins
= (18 << 26) | (diff
) | (ins
& 1);
2823 patch_ins (code
, ins
);
2827 /* diff between 0 and -33554432 */
2828 if (diff
>= -33554432){
2829 ins
= (18 << 26) | (diff
& ~0xfc000000) | (ins
& 1);
2830 patch_ins (code
, ins
);
2835 if ((glong
)target
>= 0){
2836 if ((glong
)target
<= 33554431){
2837 ins
= (18 << 26) | ((gulong
) target
) | (ins
& 1) | 2;
2838 patch_ins (code
, ins
);
2842 if ((glong
)target
>= -33554432){
2843 ins
= (18 << 26) | (((gulong
)target
) & ~0xfc000000) | (ins
& 1) | 2;
2844 patch_ins (code
, ins
);
2849 handle_thunk (cfg
, domain
, code
, target
);
2852 g_assert_not_reached ();
2860 guint32 li
= (gulong
)target
;
2861 ins
= (ins
& 0xffff0000) | (ins
& 3);
2862 ovf
= li
& 0xffff0000;
2863 if (ovf
!= 0 && ovf
!= 0xffff0000)
2864 g_assert_not_reached ();
2867 // FIXME: assert the top bits of li are 0
2869 gint diff
= target
- code
;
2870 ins
= (ins
& 0xffff0000) | (ins
& 3);
2871 ovf
= diff
& 0xffff0000;
2872 if (ovf
!= 0 && ovf
!= 0xffff0000)
2873 g_assert_not_reached ();
2877 patch_ins (code
, ins
);
2881 if (prim
== 15 || ins
== 0x4e800021 || ins
== 0x4e800020 || ins
== 0x4e800420) {
2882 #ifdef __mono_ppc64__
2883 guint32
*seq
= (guint32
*)code
;
2884 guint32
*branch_ins
;
2886 /* the trampoline code will try to patch the blrl, blr, bcctr */
2887 if (ins
== 0x4e800021 || ins
== 0x4e800020 || ins
== 0x4e800420) {
2889 if (ppc_is_load_op (seq
[-3]) || ppc_opcode (seq
[-3]) == 31) /* ld || lwz || mr */
2894 if (ppc_is_load_op (seq
[5])
2895 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2896 /* With function descs we need to do more careful
2898 || ppc_opcode (seq
[5]) == 31 /* ld || lwz || mr */
2901 branch_ins
= seq
+ 8;
2903 branch_ins
= seq
+ 6;
2906 seq
= (guint32
*)code
;
2907 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2908 g_assert (mono_ppc_is_direct_call_sequence (branch_ins
));
2910 if (ppc_is_load_op (seq
[5])) {
2911 g_assert (ppc_is_load_op (seq
[6]));
2914 guint8
*buf
= (guint8
*)&seq
[5];
2915 ppc_mr (buf
, PPC_CALL_REG
, ppc_r12
);
2920 target
= mono_get_addr_from_ftnptr ((gpointer
)target
);
2923 /* FIXME: make this thread safe */
2924 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2925 /* FIXME: we're assuming we're using r12 here */
2926 ppc_load_ptr_sequence (code
, ppc_r12
, target
);
2928 ppc_load_ptr_sequence (code
, PPC_CALL_REG
, target
);
2930 mono_arch_flush_icache ((guint8
*)seq
, 28);
2933 /* the trampoline code will try to patch the blrl, blr, bcctr */
2934 if (ins
== 0x4e800021 || ins
== 0x4e800020 || ins
== 0x4e800420) {
2937 /* this is the lis/ori/mtlr/blrl sequence */
2938 seq
= (guint32
*)code
;
2939 g_assert ((seq
[0] >> 26) == 15);
2940 g_assert ((seq
[1] >> 26) == 24);
2941 g_assert ((seq
[2] >> 26) == 31);
2942 g_assert (seq
[3] == 0x4e800021 || seq
[3] == 0x4e800020 || seq
[3] == 0x4e800420);
2943 /* FIXME: make this thread safe */
2944 ppc_lis (code
, PPC_CALL_REG
, (guint32
)(target
) >> 16);
2945 ppc_ori (code
, PPC_CALL_REG
, PPC_CALL_REG
, (guint32
)(target
) & 0xffff);
2946 mono_arch_flush_icache (code
- 8, 8);
2949 g_assert_not_reached ();
2951 // g_print ("patched with 0x%08x\n", ins);
2955 ppc_patch (guchar
*code
, const guchar
*target
)
2957 ppc_patch_full (NULL
, NULL
, code
, target
, FALSE
);
2961 mono_ppc_patch (guchar
*code
, const guchar
*target
)
2963 ppc_patch (code
, target
);
2967 emit_move_return_value (MonoCompile
*cfg
, MonoInst
*ins
, guint8
*code
)
2969 switch (ins
->opcode
) {
2972 case OP_FCALL_MEMBASE
:
2973 if (ins
->dreg
!= ppc_f1
)
2974 ppc_fmr (code
, ins
->dreg
, ppc_f1
);
2982 emit_reserve_param_area (MonoCompile
*cfg
, guint8
*code
)
2984 long size
= cfg
->param_area
;
2986 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
2987 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
2992 ppc_ldptr (code
, ppc_r0
, 0, ppc_sp
);
2993 if (ppc_is_imm16 (-size
)) {
2994 ppc_stptr_update (code
, ppc_r0
, -size
, ppc_sp
);
2996 ppc_load (code
, ppc_r12
, -size
);
2997 ppc_stptr_update_indexed (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3004 emit_unreserve_param_area (MonoCompile
*cfg
, guint8
*code
)
3006 long size
= cfg
->param_area
;
3008 size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
3009 size
&= -MONO_ARCH_FRAME_ALIGNMENT
;
3014 ppc_ldptr (code
, ppc_r0
, 0, ppc_sp
);
3015 if (ppc_is_imm16 (size
)) {
3016 ppc_stptr_update (code
, ppc_r0
, size
, ppc_sp
);
3018 ppc_load (code
, ppc_r12
, size
);
3019 ppc_stptr_update_indexed (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3025 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3029 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
3031 MonoInst
*ins
, *next
;
3033 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
3034 MonoInst
*last_ins
= NULL
;
3038 /* we don't align basic blocks of loops on ppc */
3040 if (cfg
->verbose_level
> 2)
3041 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
3043 cpos
= bb
->max_offset
;
3045 MONO_BB_FOR_EACH_INS (bb
, ins
) {
3046 const guint offset
= code
- cfg
->native_code
;
3047 set_code_cursor (cfg
, code
);
3048 max_len
= ins_get_size (ins
->opcode
);
3049 code
= realloc_code (cfg
, max_len
);
3050 // if (ins->cil_code)
3051 // g_print ("cil code\n");
3052 mono_debug_record_line_number (cfg
, ins
, offset
);
3054 switch (normalize_opcode (ins
->opcode
)) {
3055 case OP_RELAXED_NOP
:
3058 case OP_DUMMY_ICONST
:
3059 case OP_DUMMY_I8CONST
:
3060 case OP_DUMMY_R8CONST
:
3061 case OP_DUMMY_R4CONST
:
3062 case OP_NOT_REACHED
:
3065 case OP_IL_SEQ_POINT
:
3066 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3068 case OP_SEQ_POINT
: {
3071 if (cfg
->compile_aot
)
3075 * Read from the single stepping trigger page. This will cause a
3076 * SIGSEGV when single stepping is enabled.
3077 * We do this _before_ the breakpoint, so single stepping after
3078 * a breakpoint is hit will step to the next IL offset.
3080 if (ins
->flags
& MONO_INST_SINGLE_STEP_LOC
) {
3081 ppc_load (code
, ppc_r12
, (gsize
)ss_trigger_page
);
3082 ppc_ldptr (code
, ppc_r12
, 0, ppc_r12
);
3085 mono_add_seq_point (cfg
, bb
, ins
, code
- cfg
->native_code
);
3088 * A placeholder for a possible breakpoint inserted by
3089 * mono_arch_set_breakpoint ().
3091 for (i
= 0; i
< BREAKPOINT_SIZE
/ 4; ++i
)
3096 ppc_mullw (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3097 ppc_mulhw (code
, ppc_r3
, ins
->sreg1
, ins
->sreg2
);
3098 ppc_mr (code
, ppc_r4
, ppc_r0
);
3101 ppc_mullw (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3102 ppc_mulhwu (code
, ppc_r3
, ins
->sreg1
, ins
->sreg2
);
3103 ppc_mr (code
, ppc_r4
, ppc_r0
);
3105 case OP_MEMORY_BARRIER
:
3108 case OP_STOREI1_MEMBASE_REG
:
3109 if (ppc_is_imm16 (ins
->inst_offset
)) {
3110 ppc_stb (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3112 if (ppc_is_imm32 (ins
->inst_offset
)) {
3113 ppc_addis (code
, ppc_r11
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
3114 ppc_stb (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r11
);
3116 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3117 ppc_stbx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3121 case OP_STOREI2_MEMBASE_REG
:
3122 if (ppc_is_imm16 (ins
->inst_offset
)) {
3123 ppc_sth (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3125 if (ppc_is_imm32 (ins
->inst_offset
)) {
3126 ppc_addis (code
, ppc_r11
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
3127 ppc_sth (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r11
);
3129 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3130 ppc_sthx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3134 case OP_STORE_MEMBASE_REG
:
3135 if (ppc_is_imm16 (ins
->inst_offset
)) {
3136 ppc_stptr (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3138 if (ppc_is_imm32 (ins
->inst_offset
)) {
3139 ppc_addis (code
, ppc_r11
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
3140 ppc_stptr (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r11
);
3142 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3143 ppc_stptr_indexed (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3147 #ifdef MONO_ARCH_ILP32
3148 case OP_STOREI8_MEMBASE_REG
:
3149 if (ppc_is_imm16 (ins
->inst_offset
)) {
3150 ppc_str (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3152 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3153 ppc_str_indexed (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
3157 case OP_STOREI1_MEMINDEX
:
3158 ppc_stbx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
3160 case OP_STOREI2_MEMINDEX
:
3161 ppc_sthx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
3163 case OP_STORE_MEMINDEX
:
3164 ppc_stptr_indexed (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
3167 g_assert_not_reached ();
3169 case OP_LOAD_MEMBASE
:
3170 if (ppc_is_imm16 (ins
->inst_offset
)) {
3171 ppc_ldptr (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3173 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3174 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3175 ppc_ldptr (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3177 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3178 ppc_ldptr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3182 case OP_LOADI4_MEMBASE
:
3183 #ifdef __mono_ppc64__
3184 if (ppc_is_imm16 (ins
->inst_offset
)) {
3185 ppc_lwa (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3187 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3188 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3189 ppc_lwa (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3191 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3192 ppc_lwax (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3197 case OP_LOADU4_MEMBASE
:
3198 if (ppc_is_imm16 (ins
->inst_offset
)) {
3199 ppc_lwz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3201 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3202 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3203 ppc_lwz (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3205 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3206 ppc_lwzx (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3210 case OP_LOADI1_MEMBASE
:
3211 case OP_LOADU1_MEMBASE
:
3212 if (ppc_is_imm16 (ins
->inst_offset
)) {
3213 ppc_lbz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3215 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3216 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3217 ppc_lbz (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3219 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3220 ppc_lbzx (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3223 if (ins
->opcode
== OP_LOADI1_MEMBASE
)
3224 ppc_extsb (code
, ins
->dreg
, ins
->dreg
);
3226 case OP_LOADU2_MEMBASE
:
3227 if (ppc_is_imm16 (ins
->inst_offset
)) {
3228 ppc_lhz (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_lhz (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3234 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3235 ppc_lhzx (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3239 case OP_LOADI2_MEMBASE
:
3240 if (ppc_is_imm16 (ins
->inst_offset
)) {
3241 ppc_lha (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3243 if (ppc_is_imm32 (ins
->inst_offset
) && (ins
->dreg
> 0)) {
3244 ppc_addis (code
, ins
->dreg
, ins
->inst_basereg
, ppc_ha(ins
->inst_offset
));
3245 ppc_lha (code
, ins
->dreg
, ins
->inst_offset
, ins
->dreg
);
3247 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3248 ppc_lhax (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3252 #ifdef MONO_ARCH_ILP32
3253 case OP_LOADI8_MEMBASE
:
3254 if (ppc_is_imm16 (ins
->inst_offset
)) {
3255 ppc_ldr (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3257 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
3258 ppc_ldr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3262 case OP_LOAD_MEMINDEX
:
3263 ppc_ldptr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3265 case OP_LOADI4_MEMINDEX
:
3266 #ifdef __mono_ppc64__
3267 ppc_lwax (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3270 case OP_LOADU4_MEMINDEX
:
3271 ppc_lwzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3273 case OP_LOADU2_MEMINDEX
:
3274 ppc_lhzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3276 case OP_LOADI2_MEMINDEX
:
3277 ppc_lhax (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3279 case OP_LOADU1_MEMINDEX
:
3280 ppc_lbzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3282 case OP_LOADI1_MEMINDEX
:
3283 ppc_lbzx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
3284 ppc_extsb (code
, ins
->dreg
, ins
->dreg
);
3286 case OP_ICONV_TO_I1
:
3287 CASE_PPC64 (OP_LCONV_TO_I1
)
3288 ppc_extsb (code
, ins
->dreg
, ins
->sreg1
);
3290 case OP_ICONV_TO_I2
:
3291 CASE_PPC64 (OP_LCONV_TO_I2
)
3292 ppc_extsh (code
, ins
->dreg
, ins
->sreg1
);
3294 case OP_ICONV_TO_U1
:
3295 CASE_PPC64 (OP_LCONV_TO_U1
)
3296 ppc_clrlwi (code
, ins
->dreg
, ins
->sreg1
, 24);
3298 case OP_ICONV_TO_U2
:
3299 CASE_PPC64 (OP_LCONV_TO_U2
)
3300 ppc_clrlwi (code
, ins
->dreg
, ins
->sreg1
, 16);
3304 CASE_PPC64 (OP_LCOMPARE
)
3305 L
= (sizeof (target_mgreg_t
) == 4 || ins
->opcode
== OP_ICOMPARE
) ? 0 : 1;
3307 if (next
&& compare_opcode_is_unsigned (next
->opcode
))
3308 ppc_cmpl (code
, 0, L
, ins
->sreg1
, ins
->sreg2
);
3310 ppc_cmp (code
, 0, L
, ins
->sreg1
, ins
->sreg2
);
3312 case OP_COMPARE_IMM
:
3313 case OP_ICOMPARE_IMM
:
3314 CASE_PPC64 (OP_LCOMPARE_IMM
)
3315 L
= (sizeof (target_mgreg_t
) == 4 || ins
->opcode
== OP_ICOMPARE_IMM
) ? 0 : 1;
3317 if (next
&& compare_opcode_is_unsigned (next
->opcode
)) {
3318 if (ppc_is_uimm16 (ins
->inst_imm
)) {
3319 ppc_cmpli (code
, 0, L
, ins
->sreg1
, (ins
->inst_imm
& 0xffff));
3321 g_assert_not_reached ();
3324 if (ppc_is_imm16 (ins
->inst_imm
)) {
3325 ppc_cmpi (code
, 0, L
, ins
->sreg1
, (ins
->inst_imm
& 0xffff));
3327 g_assert_not_reached ();
3333 * gdb does not like encountering a trap in the debugged code. So
3334 * instead of emitting a trap, we emit a call a C function and place a
3338 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3339 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_JIT_ICALL
,
3340 (gpointer
)"mono_break");
3341 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3342 ppc_load_func (code
, PPC_CALL_REG
, 0);
3343 ppc_mtlr (code
, PPC_CALL_REG
);
3351 ppc_addco (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3354 CASE_PPC64 (OP_LADD
)
3355 ppc_add (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3359 ppc_adde (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3362 if (ppc_is_imm16 (ins
->inst_imm
)) {
3363 ppc_addic (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3365 g_assert_not_reached ();
3370 CASE_PPC64 (OP_LADD_IMM
)
3371 if (ppc_is_imm16 (ins
->inst_imm
)) {
3372 ppc_addi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3374 g_assert_not_reached ();
3378 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3380 ppc_addo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3381 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3382 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3383 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3385 case OP_IADD_OVF_UN
:
3386 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3388 ppc_addco (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3389 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3390 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3391 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3394 CASE_PPC64 (OP_LSUB_OVF
)
3395 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3397 ppc_subfo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3398 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3399 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3400 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3402 case OP_ISUB_OVF_UN
:
3403 CASE_PPC64 (OP_LSUB_OVF_UN
)
3404 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3406 ppc_subfc (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3407 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3408 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3409 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
3411 case OP_ADD_OVF_CARRY
:
3412 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3414 ppc_addeo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3415 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3416 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3417 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3419 case OP_ADD_OVF_UN_CARRY
:
3420 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3422 ppc_addeo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3423 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3424 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3425 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3427 case OP_SUB_OVF_CARRY
:
3428 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3430 ppc_subfeo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3431 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3432 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3433 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3435 case OP_SUB_OVF_UN_CARRY
:
3436 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3438 ppc_subfeo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3439 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3440 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
3441 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
3445 ppc_subfco (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3448 CASE_PPC64 (OP_LSUB
)
3449 ppc_subf (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3453 ppc_subfe (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
3457 CASE_PPC64 (OP_LSUB_IMM
)
3458 // we add the negated value
3459 if (ppc_is_imm16 (-ins
->inst_imm
))
3460 ppc_addi (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
3462 g_assert_not_reached ();
3466 g_assert (ppc_is_imm16 (ins
->inst_imm
));
3467 ppc_subfic (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3470 ppc_subfze (code
, ins
->dreg
, ins
->sreg1
);
3473 CASE_PPC64 (OP_LAND
)
3474 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3475 ppc_and (code
, ins
->sreg1
, ins
->dreg
, ins
->sreg2
);
3479 CASE_PPC64 (OP_LAND_IMM
)
3480 if (!(ins
->inst_imm
& 0xffff0000)) {
3481 ppc_andid (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3482 } else if (!(ins
->inst_imm
& 0xffff)) {
3483 ppc_andisd (code
, ins
->sreg1
, ins
->dreg
, ((guint32
)ins
->inst_imm
>> 16));
3485 g_assert_not_reached ();
3489 CASE_PPC64 (OP_LDIV
) {
3490 guint8
*divisor_is_m1
;
3491 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3493 ppc_compare_reg_imm (code
, 0, ins
->sreg2
, -1);
3494 divisor_is_m1
= code
;
3495 ppc_bc (code
, PPC_BR_FALSE
| PPC_BR_LIKELY
, PPC_BR_EQ
, 0);
3496 ppc_lis (code
, ppc_r0
, 0x8000);
3497 #ifdef __mono_ppc64__
3498 if (ins
->opcode
== OP_LDIV
)
3499 ppc_sldi (code
, ppc_r0
, ppc_r0
, 32);
3501 ppc_compare (code
, 0, ins
->sreg1
, ppc_r0
);
3502 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
3503 ppc_patch (divisor_is_m1
, code
);
3504 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3506 if (ins
->opcode
== OP_IDIV
)
3507 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3508 #ifdef __mono_ppc64__
3510 ppc_divdod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3512 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3513 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3514 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3518 CASE_PPC64 (OP_LDIV_UN
)
3519 if (ins
->opcode
== OP_IDIV_UN
)
3520 ppc_divwuod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3521 #ifdef __mono_ppc64__
3523 ppc_divduod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3525 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3526 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3527 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
3533 g_assert_not_reached ();
3536 ppc_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3540 CASE_PPC64 (OP_LOR_IMM
)
3541 if (!(ins
->inst_imm
& 0xffff0000)) {
3542 ppc_ori (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3543 } else if (!(ins
->inst_imm
& 0xffff)) {
3544 ppc_oris (code
, ins
->dreg
, ins
->sreg1
, ((guint32
)(ins
->inst_imm
) >> 16));
3546 g_assert_not_reached ();
3550 CASE_PPC64 (OP_LXOR
)
3551 ppc_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3555 CASE_PPC64 (OP_LXOR_IMM
)
3556 if (!(ins
->inst_imm
& 0xffff0000)) {
3557 ppc_xori (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3558 } else if (!(ins
->inst_imm
& 0xffff)) {
3559 ppc_xoris (code
, ins
->sreg1
, ins
->dreg
, ((guint32
)(ins
->inst_imm
) >> 16));
3561 g_assert_not_reached ();
3565 CASE_PPC64 (OP_LSHL
)
3566 ppc_shift_left (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3570 CASE_PPC64 (OP_LSHL_IMM
)
3571 ppc_shift_left_imm (code
, ins
->dreg
, ins
->sreg1
, MASK_SHIFT_IMM (ins
->inst_imm
));
3574 ppc_sraw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3577 ppc_shift_right_arith_imm (code
, ins
->dreg
, ins
->sreg1
, MASK_SHIFT_IMM (ins
->inst_imm
));
3580 if (MASK_SHIFT_IMM (ins
->inst_imm
))
3581 ppc_shift_right_imm (code
, ins
->dreg
, ins
->sreg1
, MASK_SHIFT_IMM (ins
->inst_imm
));
3583 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
3586 ppc_srw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3589 CASE_PPC64 (OP_LNOT
)
3590 ppc_not (code
, ins
->dreg
, ins
->sreg1
);
3593 CASE_PPC64 (OP_LNEG
)
3594 ppc_neg (code
, ins
->dreg
, ins
->sreg1
);
3597 CASE_PPC64 (OP_LMUL
)
3598 ppc_multiply (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3602 CASE_PPC64 (OP_LMUL_IMM
)
3603 if (ppc_is_imm16 (ins
->inst_imm
)) {
3604 ppc_mulli (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
3606 g_assert_not_reached ();
3610 CASE_PPC64 (OP_LMUL_OVF
)
3611 /* we annot use mcrxr, since it's not implemented on some processors
3612 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3614 if (ins
->opcode
== OP_IMUL_OVF
)
3615 ppc_mullwo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3616 #ifdef __mono_ppc64__
3618 ppc_mulldo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3620 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
3621 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
3622 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
3624 case OP_IMUL_OVF_UN
:
3625 CASE_PPC64 (OP_LMUL_OVF_UN
)
3626 /* we first multiply to get the high word and compare to 0
3627 * to set the flags, then the result is discarded and then
3628 * we multiply to get the lower * bits result
3630 if (ins
->opcode
== OP_IMUL_OVF_UN
)
3631 ppc_mulhwu (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3632 #ifdef __mono_ppc64__
3634 ppc_mulhdu (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
3636 ppc_cmpi (code
, 0, 0, ppc_r0
, 0);
3637 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN
- CEE_BEQ
, "OverflowException");
3638 ppc_multiply (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3641 ppc_load (code
, ins
->dreg
, ins
->inst_c0
);
3644 ppc_load (code
, ins
->dreg
, ins
->inst_l
);
3647 case OP_LOAD_GOTADDR
:
3648 /* The PLT implementation depends on this */
3649 g_assert (ins
->dreg
== ppc_r30
);
3651 code
= mono_arch_emit_load_got_addr (cfg
->native_code
, code
, cfg
, NULL
);
3654 // FIXME: Fix max instruction length
3655 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_right
->inst_i1
, ins
->inst_right
->inst_p0
);
3656 /* arch_emit_got_access () patches this */
3657 ppc_load32 (code
, ppc_r0
, 0);
3658 ppc_ldptr_indexed (code
, ins
->dreg
, ins
->inst_basereg
, ppc_r0
);
3661 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3662 ppc_load_sequence (code
, ins
->dreg
, 0);
3664 CASE_PPC32 (OP_ICONV_TO_I4
)
3665 CASE_PPC32 (OP_ICONV_TO_U4
)
3667 if (ins
->dreg
!= ins
->sreg1
)
3668 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
3671 int saved
= ins
->sreg1
;
3672 if (ins
->sreg1
== ppc_r3
) {
3673 ppc_mr (code
, ppc_r0
, ins
->sreg1
);
3676 if (ins
->sreg2
!= ppc_r3
)
3677 ppc_mr (code
, ppc_r3
, ins
->sreg2
);
3678 if (saved
!= ppc_r4
)
3679 ppc_mr (code
, ppc_r4
, saved
);
3683 if (ins
->dreg
!= ins
->sreg1
)
3684 ppc_fmr (code
, ins
->dreg
, ins
->sreg1
);
3686 case OP_MOVE_F_TO_I4
:
3687 ppc_stfs (code
, ins
->sreg1
, -4, ppc_r1
);
3688 ppc_ldptr (code
, ins
->dreg
, -4, ppc_r1
);
3690 case OP_MOVE_I4_TO_F
:
3691 ppc_stw (code
, ins
->sreg1
, -4, ppc_r1
);
3692 ppc_lfs (code
, ins
->dreg
, -4, ppc_r1
);
3694 #ifdef __mono_ppc64__
3695 case OP_MOVE_F_TO_I8
:
3696 ppc_stfd (code
, ins
->sreg1
, -8, ppc_r1
);
3697 ppc_ldptr (code
, ins
->dreg
, -8, ppc_r1
);
3699 case OP_MOVE_I8_TO_F
:
3700 ppc_stptr (code
, ins
->sreg1
, -8, ppc_r1
);
3701 ppc_lfd (code
, ins
->dreg
, -8, ppc_r1
);
3704 case OP_FCONV_TO_R4
:
3705 ppc_frsp (code
, ins
->dreg
, ins
->sreg1
);
3708 case OP_TAILCALL_PARAMETER
:
3709 // This opcode helps compute sizes, i.e.
3710 // of the subsequent OP_TAILCALL, but contributes no code.
3711 g_assert (ins
->next
);
3716 MonoCallInst
*call
= (MonoCallInst
*)ins
;
3719 * Keep in sync with mono_arch_emit_epilog
3721 g_assert (!cfg
->method
->save_lmf
);
3723 * Note: we can use ppc_r12 here because it is dead anyway:
3724 * we're leaving the method.
3726 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
3727 long ret_offset
= cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
;
3728 if (ppc_is_imm16 (ret_offset
)) {
3729 ppc_ldptr (code
, ppc_r0
, ret_offset
, cfg
->frame_reg
);
3731 ppc_load (code
, ppc_r12
, ret_offset
);
3732 ppc_ldptr_indexed (code
, ppc_r0
, cfg
->frame_reg
, ppc_r12
);
3734 ppc_mtlr (code
, ppc_r0
);
3737 if (ppc_is_imm16 (cfg
->stack_usage
)) {
3738 ppc_addi (code
, ppc_r12
, cfg
->frame_reg
, cfg
->stack_usage
);
3740 /* cfg->stack_usage is an int, so we can use
3741 * an addis/addi sequence here even in 64-bit. */
3742 ppc_addis (code
, ppc_r12
, cfg
->frame_reg
, ppc_ha(cfg
->stack_usage
));
3743 ppc_addi (code
, ppc_r12
, ppc_r12
, cfg
->stack_usage
);
3745 if (!cfg
->method
->save_lmf
) {
3747 for (i
= 31; i
>= 13; --i
) {
3748 if (cfg
->used_int_regs
& (1 << i
)) {
3749 pos
+= sizeof (target_mgreg_t
);
3750 ppc_ldptr (code
, i
, -pos
, ppc_r12
);
3754 /* FIXME restore from MonoLMF: though this can't happen yet */
3757 /* Copy arguments on the stack to our argument area */
3758 if (call
->stack_usage
) {
3759 code
= emit_memcpy (code
, call
->stack_usage
, ppc_r12
, PPC_STACK_PARAM_OFFSET
, ppc_sp
, PPC_STACK_PARAM_OFFSET
);
3760 /* r12 was clobbered */
3761 g_assert (cfg
->frame_reg
== ppc_sp
);
3762 if (ppc_is_imm16 (cfg
->stack_usage
)) {
3763 ppc_addi (code
, ppc_r12
, cfg
->frame_reg
, cfg
->stack_usage
);
3765 /* cfg->stack_usage is an int, so we can use
3766 * an addis/addi sequence here even in 64-bit. */
3767 ppc_addis (code
, ppc_r12
, cfg
->frame_reg
, ppc_ha(cfg
->stack_usage
));
3768 ppc_addi (code
, ppc_r12
, ppc_r12
, cfg
->stack_usage
);
3772 ppc_mr (code
, ppc_sp
, ppc_r12
);
3773 mono_add_patch_info (cfg
, (guint8
*) code
- cfg
->native_code
, MONO_PATCH_INFO_METHOD_JUMP
, call
->method
);
3774 cfg
->thunk_area
+= THUNK_SIZE
;
3775 if (cfg
->compile_aot
) {
3776 /* arch_emit_got_access () patches this */
3777 ppc_load32 (code
, ppc_r0
, 0);
3778 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3779 ppc_ldptr_indexed (code
, ppc_r12
, ppc_r30
, ppc_r0
);
3780 ppc_ldptr (code
, ppc_r0
, 0, ppc_r12
);
3782 ppc_ldptr_indexed (code
, ppc_r0
, ppc_r30
, ppc_r0
);
3784 ppc_mtctr (code
, ppc_r0
);
3785 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
3792 /* ensure ins->sreg1 is not NULL */
3793 ppc_ldptr (code
, ppc_r0
, 0, ins
->sreg1
);
3796 long cookie_offset
= cfg
->sig_cookie
+ cfg
->stack_usage
;
3797 if (ppc_is_imm16 (cookie_offset
)) {
3798 ppc_addi (code
, ppc_r0
, cfg
->frame_reg
, cookie_offset
);
3800 ppc_load (code
, ppc_r0
, cookie_offset
);
3801 ppc_add (code
, ppc_r0
, cfg
->frame_reg
, ppc_r0
);
3803 ppc_stptr (code
, ppc_r0
, 0, ins
->sreg1
);
3812 call
= (MonoCallInst
*)ins
;
3813 if (ins
->flags
& MONO_INST_HAS_METHOD
)
3814 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
3816 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
3817 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3818 ppc_load_func (code
, PPC_CALL_REG
, 0);
3819 ppc_mtlr (code
, PPC_CALL_REG
);
3824 /* FIXME: this should be handled somewhere else in the new jit */
3825 code
= emit_move_return_value (cfg
, ins
, code
);
3831 case OP_VOIDCALL_REG
:
3833 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3834 ppc_ldptr (code
, ppc_r0
, 0, ins
->sreg1
);
3835 /* FIXME: if we know that this is a method, we
3836 can omit this load */
3837 ppc_ldptr (code
, ppc_r2
, 8, ins
->sreg1
);
3838 ppc_mtlr (code
, ppc_r0
);
3840 #if (_CALL_ELF == 2)
3841 if (ins
->flags
& MONO_INST_HAS_METHOD
) {
3842 // Not a global entry point
3844 // Need to set up r12 with function entry address for global entry point
3845 if (ppc_r12
!= ins
->sreg1
) {
3846 ppc_mr(code
,ppc_r12
,ins
->sreg1
);
3850 ppc_mtlr (code
, ins
->sreg1
);
3853 /* FIXME: this should be handled somewhere else in the new jit */
3854 code
= emit_move_return_value (cfg
, ins
, code
);
3856 case OP_FCALL_MEMBASE
:
3857 case OP_LCALL_MEMBASE
:
3858 case OP_VCALL_MEMBASE
:
3859 case OP_VCALL2_MEMBASE
:
3860 case OP_VOIDCALL_MEMBASE
:
3861 case OP_CALL_MEMBASE
:
3862 if (cfg
->compile_aot
&& ins
->sreg1
== ppc_r12
) {
3863 /* The trampolines clobber this */
3864 ppc_mr (code
, ppc_r29
, ins
->sreg1
);
3865 ppc_ldptr (code
, ppc_r0
, ins
->inst_offset
, ppc_r29
);
3867 ppc_ldptr (code
, ppc_r0
, ins
->inst_offset
, ins
->sreg1
);
3869 ppc_mtlr (code
, ppc_r0
);
3871 /* FIXME: this should be handled somewhere else in the new jit */
3872 code
= emit_move_return_value (cfg
, ins
, code
);
3875 guint8
* zero_loop_jump
, * zero_loop_start
;
3876 /* keep alignment */
3877 int alloca_waste
= PPC_STACK_PARAM_OFFSET
+ cfg
->param_area
+ 31;
3878 int area_offset
= alloca_waste
;
3880 ppc_addi (code
, ppc_r12
, ins
->sreg1
, alloca_waste
+ 31);
3881 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3882 ppc_clear_right_imm (code
, ppc_r12
, ppc_r12
, 4);
3883 /* use ctr to store the number of words to 0 if needed */
3884 if (ins
->flags
& MONO_INST_INIT
) {
3885 /* we zero 4 bytes at a time:
3886 * we add 7 instead of 3 so that we set the counter to
3887 * at least 1, otherwise the bdnz instruction will make
3888 * it negative and iterate billions of times.
3890 ppc_addi (code
, ppc_r0
, ins
->sreg1
, 7);
3891 ppc_shift_right_arith_imm (code
, ppc_r0
, ppc_r0
, 2);
3892 ppc_mtctr (code
, ppc_r0
);
3894 ppc_ldptr (code
, ppc_r0
, 0, ppc_sp
);
3895 ppc_neg (code
, ppc_r12
, ppc_r12
);
3896 ppc_stptr_update_indexed (code
, ppc_r0
, ppc_sp
, ppc_r12
);
3898 /* FIXME: make this loop work in 8 byte
3899 increments on PPC64 */
3900 if (ins
->flags
& MONO_INST_INIT
) {
3901 /* adjust the dest reg by -4 so we can use stwu */
3902 /* we actually adjust -8 because we let the loop
3905 ppc_addi (code
, ins
->dreg
, ppc_sp
, (area_offset
- 8));
3906 ppc_li (code
, ppc_r12
, 0);
3907 zero_loop_start
= code
;
3908 ppc_stwu (code
, ppc_r12
, 4, ins
->dreg
);
3909 zero_loop_jump
= code
;
3910 ppc_bc (code
, PPC_BR_DEC_CTR_NONZERO
, 0, 0);
3911 ppc_patch (zero_loop_jump
, zero_loop_start
);
3913 ppc_addi (code
, ins
->dreg
, ppc_sp
, area_offset
);
3918 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3919 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_JIT_ICALL
,
3920 (gpointer
)"mono_arch_throw_exception");
3921 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3922 ppc_load_func (code
, PPC_CALL_REG
, 0);
3923 ppc_mtlr (code
, PPC_CALL_REG
);
3932 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3933 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_JIT_ICALL
,
3934 (gpointer
)"mono_arch_rethrow_exception");
3935 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
3936 ppc_load_func (code
, PPC_CALL_REG
, 0);
3937 ppc_mtlr (code
, PPC_CALL_REG
);
3944 case OP_START_HANDLER
: {
3945 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3946 g_assert (spvar
->inst_basereg
!= ppc_sp
);
3947 code
= emit_reserve_param_area (cfg
, code
);
3948 ppc_mflr (code
, ppc_r0
);
3949 if (ppc_is_imm16 (spvar
->inst_offset
)) {
3950 ppc_stptr (code
, ppc_r0
, spvar
->inst_offset
, spvar
->inst_basereg
);
3952 ppc_load (code
, ppc_r12
, spvar
->inst_offset
);
3953 ppc_stptr_indexed (code
, ppc_r0
, ppc_r12
, spvar
->inst_basereg
);
3957 case OP_ENDFILTER
: {
3958 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3959 g_assert (spvar
->inst_basereg
!= ppc_sp
);
3960 code
= emit_unreserve_param_area (cfg
, code
);
3961 if (ins
->sreg1
!= ppc_r3
)
3962 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
3963 if (ppc_is_imm16 (spvar
->inst_offset
)) {
3964 ppc_ldptr (code
, ppc_r0
, spvar
->inst_offset
, spvar
->inst_basereg
);
3966 ppc_load (code
, ppc_r12
, spvar
->inst_offset
);
3967 ppc_ldptr_indexed (code
, ppc_r0
, spvar
->inst_basereg
, ppc_r12
);
3969 ppc_mtlr (code
, ppc_r0
);
3973 case OP_ENDFINALLY
: {
3974 MonoInst
*spvar
= mono_find_spvar_for_region (cfg
, bb
->region
);
3975 g_assert (spvar
->inst_basereg
!= ppc_sp
);
3976 code
= emit_unreserve_param_area (cfg
, code
);
3977 ppc_ldptr (code
, ppc_r0
, spvar
->inst_offset
, spvar
->inst_basereg
);
3978 ppc_mtlr (code
, ppc_r0
);
3982 case OP_CALL_HANDLER
:
3983 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
3985 for (GList
*tmp
= ins
->inst_eh_blocks
; tmp
!= bb
->clause_holes
; tmp
= tmp
->prev
)
3986 mono_cfg_add_try_hole (cfg
, ((MonoLeaveClause
*) tmp
->data
)->clause
, code
, bb
);
3989 ins
->inst_c0
= code
- cfg
->native_code
;
3992 /*if (ins->inst_target_bb->native_offset) {
3994 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3996 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
4001 ppc_mtctr (code
, ins
->sreg1
);
4002 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
4005 ppc_li (code
, ins
->dreg
, 0);
4006 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_EQ
, 2);
4007 ppc_li (code
, ins
->dreg
, 1);
4011 CASE_PPC64 (OP_LCEQ
)
4012 ppc_li (code
, ins
->dreg
, 0);
4013 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 2);
4014 ppc_li (code
, ins
->dreg
, 1);
4020 CASE_PPC64 (OP_LCLT
)
4021 CASE_PPC64 (OP_LCLT_UN
)
4022 ppc_li (code
, ins
->dreg
, 1);
4023 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
4024 ppc_li (code
, ins
->dreg
, 0);
4028 ppc_li (code
, ins
->dreg
, 1);
4029 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_LT
, 2);
4030 ppc_li (code
, ins
->dreg
, 0);
4036 CASE_PPC64 (OP_LCGT
)
4037 CASE_PPC64 (OP_LCGT_UN
)
4038 ppc_li (code
, ins
->dreg
, 1);
4039 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
4040 ppc_li (code
, ins
->dreg
, 0);
4044 ppc_li (code
, ins
->dreg
, 1);
4045 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_GT
, 2);
4046 ppc_li (code
, ins
->dreg
, 0);
4048 case OP_COND_EXC_EQ
:
4049 case OP_COND_EXC_NE_UN
:
4050 case OP_COND_EXC_LT
:
4051 case OP_COND_EXC_LT_UN
:
4052 case OP_COND_EXC_GT
:
4053 case OP_COND_EXC_GT_UN
:
4054 case OP_COND_EXC_GE
:
4055 case OP_COND_EXC_GE_UN
:
4056 case OP_COND_EXC_LE
:
4057 case OP_COND_EXC_LE_UN
:
4058 EMIT_COND_SYSTEM_EXCEPTION (ins
->opcode
- OP_COND_EXC_EQ
, ins
->inst_p1
);
4060 case OP_COND_EXC_IEQ
:
4061 case OP_COND_EXC_INE_UN
:
4062 case OP_COND_EXC_ILT
:
4063 case OP_COND_EXC_ILT_UN
:
4064 case OP_COND_EXC_IGT
:
4065 case OP_COND_EXC_IGT_UN
:
4066 case OP_COND_EXC_IGE
:
4067 case OP_COND_EXC_IGE_UN
:
4068 case OP_COND_EXC_ILE
:
4069 case OP_COND_EXC_ILE_UN
:
4070 EMIT_COND_SYSTEM_EXCEPTION (ins
->opcode
- OP_COND_EXC_IEQ
, ins
->inst_p1
);
4082 EMIT_COND_BRANCH (ins
, ins
->opcode
- OP_IBEQ
);
4085 /* floating point opcodes */
4087 g_assert (cfg
->compile_aot
);
4089 /* FIXME: Optimize this */
4091 ppc_mflr (code
, ppc_r12
);
4093 *(double*)code
= *(double*)ins
->inst_p0
;
4095 ppc_lfd (code
, ins
->dreg
, 8, ppc_r12
);
4098 g_assert_not_reached ();
4100 case OP_STORER8_MEMBASE_REG
:
4101 if (ppc_is_imm16 (ins
->inst_offset
)) {
4102 ppc_stfd (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
4104 if (ppc_is_imm32 (ins
->inst_offset
)) {
4105 ppc_addis (code
, ppc_r11
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4106 ppc_stfd (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r11
);
4108 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4109 ppc_stfdx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
4113 case OP_LOADR8_MEMBASE
:
4114 if (ppc_is_imm16 (ins
->inst_offset
)) {
4115 ppc_lfd (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
4117 if (ppc_is_imm32 (ins
->inst_offset
)) {
4118 ppc_addis (code
, ppc_r11
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4119 ppc_lfd (code
, ins
->dreg
, ins
->inst_offset
, ppc_r11
);
4121 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4122 ppc_lfdx (code
, ins
->dreg
, ins
->inst_destbasereg
, ppc_r0
);
4126 case OP_STORER4_MEMBASE_REG
:
4127 ppc_frsp (code
, ins
->sreg1
, ins
->sreg1
);
4128 if (ppc_is_imm16 (ins
->inst_offset
)) {
4129 ppc_stfs (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
4131 if (ppc_is_imm32 (ins
->inst_offset
)) {
4132 ppc_addis (code
, ppc_r11
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4133 ppc_stfs (code
, ins
->sreg1
, ins
->inst_offset
, ppc_r11
);
4135 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4136 ppc_stfsx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
4140 case OP_LOADR4_MEMBASE
:
4141 if (ppc_is_imm16 (ins
->inst_offset
)) {
4142 ppc_lfs (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
4144 if (ppc_is_imm32 (ins
->inst_offset
)) {
4145 ppc_addis (code
, ppc_r11
, ins
->inst_destbasereg
, ppc_ha(ins
->inst_offset
));
4146 ppc_lfs (code
, ins
->dreg
, ins
->inst_offset
, ppc_r11
);
4148 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4149 ppc_lfsx (code
, ins
->dreg
, ins
->inst_destbasereg
, ppc_r0
);
4153 case OP_LOADR4_MEMINDEX
:
4154 ppc_lfsx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
4156 case OP_LOADR8_MEMINDEX
:
4157 ppc_lfdx (code
, ins
->dreg
, ins
->inst_basereg
, ins
->sreg2
);
4159 case OP_STORER4_MEMINDEX
:
4160 ppc_frsp (code
, ins
->sreg1
, ins
->sreg1
);
4161 ppc_stfsx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
4163 case OP_STORER8_MEMINDEX
:
4164 ppc_stfdx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->sreg2
);
4167 case CEE_CONV_R4
: /* FIXME: change precision */
4169 g_assert_not_reached ();
4170 case OP_FCONV_TO_I1
:
4171 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
4173 case OP_FCONV_TO_U1
:
4174 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
4176 case OP_FCONV_TO_I2
:
4177 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
4179 case OP_FCONV_TO_U2
:
4180 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
4182 case OP_FCONV_TO_I4
:
4184 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
4186 case OP_FCONV_TO_U4
:
4188 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
4190 case OP_LCONV_TO_R_UN
:
4191 g_assert_not_reached ();
4192 /* Implemented as helper calls */
4194 case OP_LCONV_TO_OVF_I4_2
:
4195 case OP_LCONV_TO_OVF_I
: {
4196 #ifdef __mono_ppc64__
4199 guint8
*negative_branch
, *msword_positive_branch
, *msword_negative_branch
, *ovf_ex_target
;
4200 // Check if its negative
4201 ppc_cmpi (code
, 0, 0, ins
->sreg1
, 0);
4202 negative_branch
= code
;
4203 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 0);
4204 // Its positive msword == 0
4205 ppc_cmpi (code
, 0, 0, ins
->sreg2
, 0);
4206 msword_positive_branch
= code
;
4207 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_EQ
, 0);
4209 ovf_ex_target
= code
;
4210 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS
, 0, "OverflowException");
4212 ppc_patch (negative_branch
, code
);
4213 ppc_cmpi (code
, 0, 0, ins
->sreg2
, -1);
4214 msword_negative_branch
= code
;
4215 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4216 ppc_patch (msword_negative_branch
, ovf_ex_target
);
4218 ppc_patch (msword_positive_branch
, code
);
4219 if (ins
->dreg
!= ins
->sreg1
)
4220 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
4225 ppc_frind (code
, ins
->dreg
, ins
->sreg1
);
4228 ppc_frizd (code
, ins
->dreg
, ins
->sreg1
);
4231 ppc_fripd (code
, ins
->dreg
, ins
->sreg1
);
4234 ppc_frimd (code
, ins
->dreg
, ins
->sreg1
);
4237 ppc_fabsd (code
, ins
->dreg
, ins
->sreg1
);
4240 ppc_fsqrtsd (code
, ins
->dreg
, ins
->sreg1
);
4243 ppc_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
4246 ppc_fadd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4249 ppc_fsub (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4252 ppc_fmul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4255 ppc_fdiv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4258 ppc_fneg (code
, ins
->dreg
, ins
->sreg1
);
4262 g_assert_not_reached ();
4264 /* These min/max require POWER5 */
4266 ppc_cmp (code
, 0, 0, ins
->sreg1
, ins
->sreg2
);
4267 ppc_isellt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4270 ppc_cmpl (code
, 0, 0, ins
->sreg1
, ins
->sreg2
);
4271 ppc_isellt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4274 ppc_cmp (code
, 0, 0, ins
->sreg1
, ins
->sreg2
);
4275 ppc_iselgt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4278 ppc_cmpl (code
, 0, 0, ins
->sreg1
, ins
->sreg2
);
4279 ppc_iselgt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4281 CASE_PPC64 (OP_LMIN
)
4282 ppc_cmpl (code
, 0, 1, ins
->sreg1
, ins
->sreg2
);
4283 ppc_isellt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4285 CASE_PPC64 (OP_LMIN_UN
)
4286 ppc_cmpl (code
, 0, 1, ins
->sreg1
, ins
->sreg2
);
4287 ppc_isellt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4289 CASE_PPC64 (OP_LMAX
)
4290 ppc_cmp (code
, 0, 1, ins
->sreg1
, ins
->sreg2
);
4291 ppc_iselgt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4293 CASE_PPC64 (OP_LMAX_UN
)
4294 ppc_cmpl (code
, 0, 1, ins
->sreg1
, ins
->sreg2
);
4295 ppc_iselgt (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4298 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
4302 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
4303 ppc_li (code
, ins
->dreg
, 1);
4304 ppc_bc (code
, ins
->opcode
== OP_FCEQ
? PPC_BR_TRUE
: PPC_BR_FALSE
, PPC_BR_EQ
, 2);
4305 ppc_li (code
, ins
->dreg
, 0);
4309 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
4310 ppc_li (code
, ins
->dreg
, 1);
4311 ppc_bc (code
, ins
->opcode
== OP_FCLT
? PPC_BR_TRUE
: PPC_BR_FALSE
, PPC_BR_LT
, 2);
4312 ppc_li (code
, ins
->dreg
, 0);
4315 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
4316 ppc_li (code
, ins
->dreg
, 1);
4317 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 3);
4318 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
4319 ppc_li (code
, ins
->dreg
, 0);
4323 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
4324 ppc_li (code
, ins
->dreg
, 1);
4325 ppc_bc (code
, ins
->opcode
== OP_FCGT
? PPC_BR_TRUE
: PPC_BR_FALSE
, PPC_BR_GT
, 2);
4326 ppc_li (code
, ins
->dreg
, 0);
4329 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
4330 ppc_li (code
, ins
->dreg
, 1);
4331 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 3);
4332 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
4333 ppc_li (code
, ins
->dreg
, 0);
4336 EMIT_COND_BRANCH (ins
, CEE_BEQ
- CEE_BEQ
);
4339 EMIT_COND_BRANCH (ins
, CEE_BNE_UN
- CEE_BEQ
);
4342 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4343 EMIT_COND_BRANCH (ins
, CEE_BLT
- CEE_BEQ
);
4346 EMIT_COND_BRANCH_FLAGS (ins
, PPC_BR_TRUE
, PPC_BR_SO
);
4347 EMIT_COND_BRANCH (ins
, CEE_BLT_UN
- CEE_BEQ
);
4350 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4351 EMIT_COND_BRANCH (ins
, CEE_BGT
- CEE_BEQ
);
4354 EMIT_COND_BRANCH_FLAGS (ins
, PPC_BR_TRUE
, PPC_BR_SO
);
4355 EMIT_COND_BRANCH (ins
, CEE_BGT_UN
- CEE_BEQ
);
4358 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4359 EMIT_COND_BRANCH (ins
, CEE_BGE
- CEE_BEQ
);
4362 EMIT_COND_BRANCH (ins
, CEE_BGE_UN
- CEE_BEQ
);
4365 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 2);
4366 EMIT_COND_BRANCH (ins
, CEE_BLE
- CEE_BEQ
);
4369 EMIT_COND_BRANCH (ins
, CEE_BLE_UN
- CEE_BEQ
);
4372 g_assert_not_reached ();
4373 case OP_PPC_CHECK_FINITE
: {
4374 ppc_rlwinm (code
, ins
->sreg1
, ins
->sreg1
, 0, 1, 31);
4375 ppc_addis (code
, ins
->sreg1
, ins
->sreg1
, -32752);
4376 ppc_rlwinmd (code
, ins
->sreg1
, ins
->sreg1
, 1, 31, 31);
4377 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ
- CEE_BEQ
, "ArithmeticException");
4380 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_c1
, ins
->inst_p0
);
4381 #ifdef __mono_ppc64__
4382 ppc_load_sequence (code
, ins
->dreg
, (guint64
)0x0f0f0f0f0f0f0f0fLL
);
4384 ppc_load_sequence (code
, ins
->dreg
, (gulong
)0x0f0f0f0fL
);
4389 #ifdef __mono_ppc64__
4390 case OP_ICONV_TO_I4
:
4392 ppc_extsw (code
, ins
->dreg
, ins
->sreg1
);
4394 case OP_ICONV_TO_U4
:
4396 ppc_clrldi (code
, ins
->dreg
, ins
->sreg1
, 32);
4398 case OP_ICONV_TO_R4
:
4399 case OP_ICONV_TO_R8
:
4400 case OP_LCONV_TO_R4
:
4401 case OP_LCONV_TO_R8
: {
4403 if (ins
->opcode
== OP_ICONV_TO_R4
|| ins
->opcode
== OP_ICONV_TO_R8
) {
4404 ppc_extsw (code
, ppc_r0
, ins
->sreg1
);
4409 if (cpu_hw_caps
& PPC_MOVE_FPR_GPR
) {
4410 ppc_mffgpr (code
, ins
->dreg
, tmp
);
4412 ppc_str (code
, tmp
, -8, ppc_r1
);
4413 ppc_lfd (code
, ins
->dreg
, -8, ppc_r1
);
4415 ppc_fcfid (code
, ins
->dreg
, ins
->dreg
);
4416 if (ins
->opcode
== OP_ICONV_TO_R4
|| ins
->opcode
== OP_LCONV_TO_R4
)
4417 ppc_frsp (code
, ins
->dreg
, ins
->dreg
);
4421 ppc_srad (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4424 ppc_srd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
4427 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4429 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
4430 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1 << 13)); /* CA */
4431 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, ins
->inst_p1
);
4433 case OP_COND_EXC_OV
:
4434 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
4435 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1 << 14)); /* OV */
4436 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, ins
->inst_p1
);
4448 EMIT_COND_BRANCH (ins
, ins
->opcode
- OP_LBEQ
);
4450 case OP_FCONV_TO_I8
:
4451 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 8, TRUE
);
4453 case OP_FCONV_TO_U8
:
4454 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 8, FALSE
);
4456 case OP_STOREI4_MEMBASE_REG
:
4457 if (ppc_is_imm16 (ins
->inst_offset
)) {
4458 ppc_stw (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
4460 ppc_load (code
, ppc_r0
, ins
->inst_offset
);
4461 ppc_stwx (code
, ins
->sreg1
, ins
->inst_destbasereg
, ppc_r0
);
4464 case OP_STOREI4_MEMINDEX
:
4465 ppc_stwx (code
, ins
->sreg1
, ins
->sreg2
, ins
->inst_destbasereg
);
4468 ppc_srawi (code
, ins
->dreg
, ins
->sreg1
, (ins
->inst_imm
& 0x1f));
4470 case OP_ISHR_UN_IMM
:
4471 if (ins
->inst_imm
& 0x1f)
4472 ppc_srwi (code
, ins
->dreg
, ins
->sreg1
, (ins
->inst_imm
& 0x1f));
4474 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
4477 case OP_ICONV_TO_R4
:
4478 case OP_ICONV_TO_R8
: {
4479 if (cpu_hw_caps
& PPC_ISA_64
) {
4480 ppc_srawi(code
, ppc_r0
, ins
->sreg1
, 31);
4481 ppc_stw (code
, ppc_r0
, -8, ppc_r1
);
4482 ppc_stw (code
, ins
->sreg1
, -4, ppc_r1
);
4483 ppc_lfd (code
, ins
->dreg
, -8, ppc_r1
);
4484 ppc_fcfid (code
, ins
->dreg
, ins
->dreg
);
4485 if (ins
->opcode
== OP_ICONV_TO_R4
)
4486 ppc_frsp (code
, ins
->dreg
, ins
->dreg
);
4492 case OP_ATOMIC_ADD_I4
:
4493 CASE_PPC64 (OP_ATOMIC_ADD_I8
) {
4494 int location
= ins
->inst_basereg
;
4495 int addend
= ins
->sreg2
;
4496 guint8
*loop
, *branch
;
4497 g_assert (ins
->inst_offset
== 0);
4501 if (ins
->opcode
== OP_ATOMIC_ADD_I4
)
4502 ppc_lwarx (code
, ppc_r0
, 0, location
);
4503 #ifdef __mono_ppc64__
4505 ppc_ldarx (code
, ppc_r0
, 0, location
);
4508 ppc_add (code
, ppc_r0
, ppc_r0
, addend
);
4510 if (ins
->opcode
== OP_ATOMIC_ADD_I4
)
4511 ppc_stwcxd (code
, ppc_r0
, 0, location
);
4512 #ifdef __mono_ppc64__
4514 ppc_stdcxd (code
, ppc_r0
, 0, location
);
4518 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4519 ppc_patch (branch
, loop
);
4522 ppc_mr (code
, ins
->dreg
, ppc_r0
);
4525 case OP_ATOMIC_CAS_I4
:
4526 CASE_PPC64 (OP_ATOMIC_CAS_I8
) {
4527 int location
= ins
->sreg1
;
4528 int value
= ins
->sreg2
;
4529 int comparand
= ins
->sreg3
;
4530 guint8
*start
, *not_equal
, *lost_reservation
;
4534 if (ins
->opcode
== OP_ATOMIC_CAS_I4
)
4535 ppc_lwarx (code
, ppc_r0
, 0, location
);
4536 #ifdef __mono_ppc64__
4538 ppc_ldarx (code
, ppc_r0
, 0, location
);
4541 ppc_cmp (code
, 0, ins
->opcode
== OP_ATOMIC_CAS_I4
? 0 : 1, ppc_r0
, comparand
);
4543 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4545 if (ins
->opcode
== OP_ATOMIC_CAS_I4
)
4546 ppc_stwcxd (code
, value
, 0, location
);
4547 #ifdef __mono_ppc64__
4549 ppc_stdcxd (code
, value
, 0, location
);
4552 lost_reservation
= code
;
4553 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
4554 ppc_patch (lost_reservation
, start
);
4555 ppc_patch (not_equal
, code
);
4558 ppc_mr (code
, ins
->dreg
, ppc_r0
);
4561 case OP_LIVERANGE_START
: {
4562 if (cfg
->verbose_level
> 1)
4563 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg
, ins
->inst_c0
)->vreg
, (int)(code
- cfg
->native_code
));
4564 MONO_VARINFO (cfg
, ins
->inst_c0
)->live_range_start
= code
- cfg
->native_code
;
4567 case OP_LIVERANGE_END
: {
4568 if (cfg
->verbose_level
> 1)
4569 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg
, ins
->inst_c0
)->vreg
, (int)(code
- cfg
->native_code
));
4570 MONO_VARINFO (cfg
, ins
->inst_c0
)->live_range_end
= code
- cfg
->native_code
;
4573 case OP_GC_SAFE_POINT
:
4577 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
4578 g_assert_not_reached ();
4581 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
4582 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4583 mono_inst_name (ins
->opcode
), max_len
, (glong
)(code
- cfg
->native_code
- offset
));
4584 g_assert_not_reached ();
4592 set_code_cursor (cfg
, code
);
4594 #endif /* !DISABLE_JIT */
4597 mono_arch_register_lowlevel_calls (void)
4599 /* The signature doesn't matter */
4600 mono_register_jit_icall (mono_ppc_throw_exception
, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE
);
4603 #ifdef __mono_ppc64__
4604 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4605 #define patch_load_sequence(ip,val) do {\
4606 guint16 *__load = (guint16*)(ip); \
4607 g_assert (sizeof (val) == sizeof (gsize)); \
4608 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4609 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4610 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4611 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4613 #elif G_BYTE_ORDER == G_BIG_ENDIAN
4614 #define patch_load_sequence(ip,val) do {\
4615 guint16 *__load = (guint16*)(ip); \
4616 g_assert (sizeof (val) == sizeof (gsize)); \
4617 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4618 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4619 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4620 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4623 #error huh? No endianess defined by compiler
4626 #define patch_load_sequence(ip,val) do {\
4627 guint16 *__lis_ori = (guint16*)(ip); \
4628 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4629 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4635 mono_arch_patch_code_new (MonoCompile
*cfg
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gpointer target
)
4637 unsigned char *ip
= ji
->ip
.i
+ code
;
4638 gboolean is_fd
= FALSE
;
4641 case MONO_PATCH_INFO_IP
:
4642 patch_load_sequence (ip
, ip
);
4644 case MONO_PATCH_INFO_METHOD_REL
:
4645 g_assert_not_reached ();
4646 *((gpointer
*)(ip
)) = code
+ ji
->data
.offset
;
4648 case MONO_PATCH_INFO_SWITCH
: {
4649 gpointer
*table
= (gpointer
*)ji
->data
.table
->table
;
4652 patch_load_sequence (ip
, table
);
4654 for (i
= 0; i
< ji
->data
.table
->table_size
; i
++) {
4655 table
[i
] = (glong
)ji
->data
.table
->table
[i
] + code
;
4657 /* we put into the table the absolute address, no need for ppc_patch in this case */
4660 case MONO_PATCH_INFO_METHODCONST
:
4661 case MONO_PATCH_INFO_CLASS
:
4662 case MONO_PATCH_INFO_IMAGE
:
4663 case MONO_PATCH_INFO_FIELD
:
4664 case MONO_PATCH_INFO_VTABLE
:
4665 case MONO_PATCH_INFO_IID
:
4666 case MONO_PATCH_INFO_SFLDA
:
4667 case MONO_PATCH_INFO_LDSTR
:
4668 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
4669 case MONO_PATCH_INFO_LDTOKEN
:
4670 /* from OP_AOTCONST : lis + ori */
4671 patch_load_sequence (ip
, target
);
4673 case MONO_PATCH_INFO_R4
:
4674 case MONO_PATCH_INFO_R8
:
4675 g_assert_not_reached ();
4676 *((gconstpointer
*)(ip
+ 2)) = ji
->data
.target
;
4678 case MONO_PATCH_INFO_EXC_NAME
:
4679 g_assert_not_reached ();
4680 *((gconstpointer
*)(ip
+ 1)) = ji
->data
.name
;
4682 case MONO_PATCH_INFO_NONE
:
4683 case MONO_PATCH_INFO_BB_OVF
:
4684 case MONO_PATCH_INFO_EXC_OVF
:
4685 /* everything is dealt with at epilog output time */
4687 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4688 case MONO_PATCH_INFO_JIT_ICALL
:
4689 case MONO_PATCH_INFO_ABS
:
4690 case MONO_PATCH_INFO_RGCTX_FETCH
:
4691 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
4696 ppc_patch_full (cfg
, domain
, ip
, target
, is_fd
);
4702 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4703 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4704 * the instruction offset immediate for all the registers.
4707 save_registers (MonoCompile
*cfg
, guint8
* code
, int pos
, int base_reg
, gboolean save_lmf
, guint32 used_int_regs
, int cfa_offset
)
4711 for (i
= 13; i
<= 31; i
++) {
4712 if (used_int_regs
& (1 << i
)) {
4713 ppc_str (code
, i
, pos
, base_reg
);
4714 mono_emit_unwind_op_offset (cfg
, code
, i
, pos
- cfa_offset
);
4715 pos
+= sizeof (target_mgreg_t
);
4719 /* pos is the start of the MonoLMF structure */
4720 int offset
= pos
+ G_STRUCT_OFFSET (MonoLMF
, iregs
);
4721 for (i
= 13; i
<= 31; i
++) {
4722 ppc_str (code
, i
, offset
, base_reg
);
4723 mono_emit_unwind_op_offset (cfg
, code
, i
, offset
- cfa_offset
);
4724 offset
+= sizeof (target_mgreg_t
);
4726 offset
= pos
+ G_STRUCT_OFFSET (MonoLMF
, fregs
);
4727 for (i
= 14; i
< 32; i
++) {
4728 ppc_stfd (code
, i
, offset
, base_reg
);
4729 offset
+= sizeof (gdouble
);
4736 * Stack frame layout:
4738 * ------------------- sp
4739 * MonoLMF structure or saved registers
4740 * -------------------
4742 * -------------------
4744 * -------------------
4745 * param area size is cfg->param_area
4746 * -------------------
4747 * linkage area size is PPC_STACK_PARAM_OFFSET
4748 * ------------------- sp
4752 mono_arch_emit_prolog (MonoCompile
*cfg
)
4754 MonoMethod
*method
= cfg
->method
;
4756 MonoMethodSignature
*sig
;
4758 long alloc_size
, pos
, max_offset
, cfa_offset
;
4763 int tailcall_struct_index
;
4765 sig
= mono_method_signature_internal (method
);
4766 cfg
->code_size
= 512 + sig
->param_count
* 32;
4767 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
4771 /* We currently emit unwind info for aot, but don't use it */
4772 mono_emit_unwind_op_def_cfa (cfg
, code
, ppc_r1
, 0);
4774 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
4775 ppc_mflr (code
, ppc_r0
);
4776 ppc_str (code
, ppc_r0
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
4777 mono_emit_unwind_op_offset (cfg
, code
, ppc_lr
, PPC_RET_ADDR_OFFSET
);
4780 alloc_size
= cfg
->stack_offset
;
4783 if (!method
->save_lmf
) {
4784 for (i
= 31; i
>= 13; --i
) {
4785 if (cfg
->used_int_regs
& (1 << i
)) {
4786 pos
+= sizeof (target_mgreg_t
);
4790 pos
+= sizeof (MonoLMF
);
4794 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4795 if (alloc_size
& (MONO_ARCH_FRAME_ALIGNMENT
- 1)) {
4796 alloc_size
+= MONO_ARCH_FRAME_ALIGNMENT
- 1;
4797 alloc_size
&= ~(MONO_ARCH_FRAME_ALIGNMENT
- 1);
4800 cfg
->stack_usage
= alloc_size
;
4801 g_assert ((alloc_size
& (MONO_ARCH_FRAME_ALIGNMENT
-1)) == 0);
4803 if (ppc_is_imm16 (-alloc_size
)) {
4804 ppc_str_update (code
, ppc_sp
, -alloc_size
, ppc_sp
);
4805 cfa_offset
= alloc_size
;
4806 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, alloc_size
);
4807 code
= save_registers (cfg
, code
, alloc_size
- pos
, ppc_sp
, method
->save_lmf
, cfg
->used_int_regs
, cfa_offset
);
4810 ppc_addi (code
, ppc_r12
, ppc_sp
, -pos
);
4811 ppc_load (code
, ppc_r0
, -alloc_size
);
4812 ppc_str_update_indexed (code
, ppc_sp
, ppc_sp
, ppc_r0
);
4813 cfa_offset
= alloc_size
;
4814 mono_emit_unwind_op_def_cfa_offset (cfg
, code
, alloc_size
);
4815 code
= save_registers (cfg
, code
, 0, ppc_r12
, method
->save_lmf
, cfg
->used_int_regs
, cfa_offset
);
4818 if (cfg
->frame_reg
!= ppc_sp
) {
4819 ppc_mr (code
, cfg
->frame_reg
, ppc_sp
);
4820 mono_emit_unwind_op_def_cfa_reg (cfg
, code
, cfg
->frame_reg
);
4823 /* store runtime generic context */
4824 if (cfg
->rgctx_var
) {
4825 g_assert (cfg
->rgctx_var
->opcode
== OP_REGOFFSET
&&
4826 (cfg
->rgctx_var
->inst_basereg
== ppc_r1
|| cfg
->rgctx_var
->inst_basereg
== ppc_r31
));
4828 ppc_stptr (code
, MONO_ARCH_RGCTX_REG
, cfg
->rgctx_var
->inst_offset
, cfg
->rgctx_var
->inst_basereg
);
4831 /* compute max_offset in order to use short forward jumps
4832 * we always do it on ppc because the immediate displacement
4833 * for jumps is too small
4836 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
4838 bb
->max_offset
= max_offset
;
4840 MONO_BB_FOR_EACH_INS (bb
, ins
)
4841 max_offset
+= ins_get_size (ins
->opcode
);
4844 /* load arguments allocated to register from the stack */
4847 cinfo
= get_call_info (sig
);
4849 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
4850 ArgInfo
*ainfo
= &cinfo
->ret
;
4852 inst
= cfg
->vret_addr
;
4855 if (ppc_is_imm16 (inst
->inst_offset
)) {
4856 ppc_stptr (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4858 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4859 ppc_stptr_indexed (code
, ainfo
->reg
, ppc_r12
, inst
->inst_basereg
);
4863 tailcall_struct_index
= 0;
4864 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
4865 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4866 inst
= cfg
->args
[pos
];
4868 if (cfg
->verbose_level
> 2)
4869 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->regtype
);
4870 if (inst
->opcode
== OP_REGVAR
) {
4871 if (ainfo
->regtype
== RegTypeGeneral
)
4872 ppc_mr (code
, inst
->dreg
, ainfo
->reg
);
4873 else if (ainfo
->regtype
== RegTypeFP
)
4874 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
4875 else if (ainfo
->regtype
== RegTypeBase
) {
4876 ppc_ldr (code
, ppc_r12
, 0, ppc_sp
);
4877 ppc_ldptr (code
, inst
->dreg
, ainfo
->offset
, ppc_r12
);
4879 g_assert_not_reached ();
4881 if (cfg
->verbose_level
> 2)
4882 g_print ("Argument %ld assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
4884 /* the argument should be put on the stack: FIXME handle size != word */
4885 if (ainfo
->regtype
== RegTypeGeneral
) {
4886 switch (ainfo
->size
) {
4888 if (ppc_is_imm16 (inst
->inst_offset
)) {
4889 ppc_stb (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4891 if (ppc_is_imm32 (inst
->inst_offset
)) {
4892 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4893 ppc_stb (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r12
);
4895 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4896 ppc_stbx (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r12
);
4901 if (ppc_is_imm16 (inst
->inst_offset
)) {
4902 ppc_sth (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4904 if (ppc_is_imm32 (inst
->inst_offset
)) {
4905 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4906 ppc_sth (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r12
);
4908 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4909 ppc_sthx (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r12
);
4913 #ifdef __mono_ppc64__
4915 if (ppc_is_imm16 (inst
->inst_offset
)) {
4916 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4918 if (ppc_is_imm32 (inst
->inst_offset
)) {
4919 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4920 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r12
);
4922 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4923 ppc_stwx (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r12
);
4928 if (ppc_is_imm16 (inst
->inst_offset
)) {
4929 ppc_str (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4931 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4932 ppc_str_indexed (code
, ainfo
->reg
, ppc_r12
, inst
->inst_basereg
);
4937 if (ppc_is_imm16 (inst
->inst_offset
+ 4)) {
4938 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4939 ppc_stw (code
, ainfo
->reg
+ 1, inst
->inst_offset
+ 4, inst
->inst_basereg
);
4941 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4942 ppc_addi (code
, ppc_r12
, ppc_r12
, inst
->inst_offset
);
4943 ppc_stw (code
, ainfo
->reg
, 0, ppc_r12
);
4944 ppc_stw (code
, ainfo
->reg
+ 1, 4, ppc_r12
);
4949 if (ppc_is_imm16 (inst
->inst_offset
)) {
4950 ppc_stptr (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
4952 if (ppc_is_imm32 (inst
->inst_offset
)) {
4953 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4954 ppc_stptr (code
, ainfo
->reg
, inst
->inst_offset
, ppc_r12
);
4956 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4957 ppc_stptr_indexed (code
, ainfo
->reg
, inst
->inst_basereg
, ppc_r12
);
4962 } else if (ainfo
->regtype
== RegTypeBase
) {
4963 g_assert (ppc_is_imm16 (ainfo
->offset
));
4964 /* load the previous stack pointer in r12 */
4965 ppc_ldr (code
, ppc_r12
, 0, ppc_sp
);
4966 ppc_ldptr (code
, ppc_r0
, ainfo
->offset
, ppc_r12
);
4967 switch (ainfo
->size
) {
4969 if (ppc_is_imm16 (inst
->inst_offset
)) {
4970 ppc_stb (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4972 if (ppc_is_imm32 (inst
->inst_offset
)) {
4973 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4974 ppc_stb (code
, ppc_r0
, inst
->inst_offset
, ppc_r12
);
4976 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4977 ppc_stbx (code
, ppc_r0
, inst
->inst_basereg
, ppc_r12
);
4982 if (ppc_is_imm16 (inst
->inst_offset
)) {
4983 ppc_sth (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4985 if (ppc_is_imm32 (inst
->inst_offset
)) {
4986 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
4987 ppc_sth (code
, ppc_r0
, inst
->inst_offset
, ppc_r12
);
4989 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
4990 ppc_sthx (code
, ppc_r0
, inst
->inst_basereg
, ppc_r12
);
4994 #ifdef __mono_ppc64__
4996 if (ppc_is_imm16 (inst
->inst_offset
)) {
4997 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
4999 if (ppc_is_imm32 (inst
->inst_offset
)) {
5000 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
5001 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, ppc_r12
);
5003 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
5004 ppc_stwx (code
, ppc_r0
, inst
->inst_basereg
, ppc_r12
);
5009 if (ppc_is_imm16 (inst
->inst_offset
)) {
5010 ppc_str (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
5012 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
5013 ppc_str_indexed (code
, ppc_r0
, ppc_r12
, inst
->inst_basereg
);
5018 g_assert (ppc_is_imm16 (ainfo
->offset
+ 4));
5019 if (ppc_is_imm16 (inst
->inst_offset
+ 4)) {
5020 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
5021 ppc_lwz (code
, ppc_r0
, ainfo
->offset
+ 4, ppc_r12
);
5022 ppc_stw (code
, ppc_r0
, inst
->inst_offset
+ 4, inst
->inst_basereg
);
5024 /* use r11 to load the 2nd half of the long before we clobber r12. */
5025 ppc_lwz (code
, ppc_r11
, ainfo
->offset
+ 4, ppc_r12
);
5026 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
5027 ppc_addi (code
, ppc_r12
, ppc_r12
, inst
->inst_offset
);
5028 ppc_stw (code
, ppc_r0
, 0, ppc_r12
);
5029 ppc_stw (code
, ppc_r11
, 4, ppc_r12
);
5034 if (ppc_is_imm16 (inst
->inst_offset
)) {
5035 ppc_stptr (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
5037 if (ppc_is_imm32 (inst
->inst_offset
)) {
5038 ppc_addis (code
, ppc_r12
, inst
->inst_basereg
, ppc_ha(inst
->inst_offset
));
5039 ppc_stptr (code
, ppc_r0
, inst
->inst_offset
, ppc_r12
);
5041 ppc_load (code
, ppc_r12
, inst
->inst_offset
);
5042 ppc_stptr_indexed (code
, ppc_r0
, inst
->inst_basereg
, ppc_r12
);
5047 } else if (ainfo
->regtype
== RegTypeFP
) {
5048 g_assert (ppc_is_imm16 (inst
->inst_offset
));
5049 if (ainfo
->size
== 8)
5050 ppc_stfd (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
5051 else if (ainfo
->size
== 4)
5052 ppc_stfs (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
5054 g_assert_not_reached ();
5055 } else if (ainfo
->regtype
== RegTypeFPStructByVal
) {
5056 int doffset
= inst
->inst_offset
;
5060 g_assert (ppc_is_imm16 (inst
->inst_offset
));
5061 g_assert (ppc_is_imm16 (inst
->inst_offset
+ ainfo
->vtregs
* sizeof (target_mgreg_t
)));
5062 /* FIXME: what if there is no class? */
5063 if (sig
->pinvoke
&& mono_class_from_mono_type_internal (inst
->inst_vtype
))
5064 size
= mono_class_native_size (mono_class_from_mono_type_internal (inst
->inst_vtype
), NULL
);
5065 for (cur_reg
= 0; cur_reg
< ainfo
->vtregs
; ++cur_reg
) {
5066 if (ainfo
->size
== 4) {
5067 ppc_stfs (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5069 ppc_stfd (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5071 soffset
+= ainfo
->size
;
5072 doffset
+= ainfo
->size
;
5074 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
5075 int doffset
= inst
->inst_offset
;
5079 g_assert (ppc_is_imm16 (inst
->inst_offset
));
5080 g_assert (ppc_is_imm16 (inst
->inst_offset
+ ainfo
->vtregs
* sizeof (target_mgreg_t
)));
5081 /* FIXME: what if there is no class? */
5082 if (sig
->pinvoke
&& mono_class_from_mono_type_internal (inst
->inst_vtype
))
5083 size
= mono_class_native_size (mono_class_from_mono_type_internal (inst
->inst_vtype
), NULL
);
5084 for (cur_reg
= 0; cur_reg
< ainfo
->vtregs
; ++cur_reg
) {
5087 * Darwin handles 1 and 2 byte
5088 * structs specially by
5089 * loading h/b into the arg
5090 * register. Only done for
5094 ppc_sth (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5096 ppc_stb (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5100 #ifdef __mono_ppc64__
5102 g_assert (cur_reg
== 0);
5103 #if G_BYTE_ORDER == G_BIG_ENDIAN
5104 ppc_sldi (code
, ppc_r0
, ainfo
->reg
,
5105 (sizeof (target_mgreg_t
) - ainfo
->bytes
) * 8);
5106 ppc_stptr (code
, ppc_r0
, doffset
, inst
->inst_basereg
);
5108 if (mono_class_native_size (inst
->klass
, NULL
) == 1) {
5109 ppc_stb (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5110 } else if (mono_class_native_size (inst
->klass
, NULL
) == 2) {
5111 ppc_sth (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5112 } else if (mono_class_native_size (inst
->klass
, NULL
) == 4) { // WDS -- maybe <=4?
5113 ppc_stw (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
5115 ppc_stptr (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
); // WDS -- Better way?
5121 ppc_stptr (code
, ainfo
->reg
+ cur_reg
, doffset
,
5122 inst
->inst_basereg
);
5125 soffset
+= sizeof (target_mgreg_t
);
5126 doffset
+= sizeof (target_mgreg_t
);
5128 if (ainfo
->vtsize
) {
5129 /* FIXME: we need to do the shifting here, too */
5132 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5133 ppc_ldr (code
, ppc_r12
, 0, ppc_sp
);
5134 if ((size
& MONO_PPC_32_64_CASE (3, 7)) != 0) {
5135 code
= emit_memcpy (code
, size
- soffset
,
5136 inst
->inst_basereg
, doffset
,
5137 ppc_r12
, ainfo
->offset
+ soffset
);
5139 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (target_mgreg_t
),
5140 inst
->inst_basereg
, doffset
,
5141 ppc_r12
, ainfo
->offset
+ soffset
);
5144 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
5145 /* if it was originally a RegTypeBase */
5146 if (ainfo
->offset
) {
5147 /* load the previous stack pointer in r12 */
5148 ppc_ldr (code
, ppc_r12
, 0, ppc_sp
);
5149 ppc_ldptr (code
, ppc_r12
, ainfo
->offset
, ppc_r12
);
5151 ppc_mr (code
, ppc_r12
, ainfo
->reg
);
5154 g_assert (ppc_is_imm16 (inst
->inst_offset
));
5155 code
= emit_memcpy (code
, ainfo
->vtsize
, inst
->inst_basereg
, inst
->inst_offset
, ppc_r12
, 0);
5156 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5158 g_assert_not_reached ();
5163 if (method
->save_lmf
) {
5164 if (cfg
->compile_aot
) {
5165 /* Compute the got address which is needed by the PLT entry */
5166 code
= mono_arch_emit_load_got_addr (cfg
->native_code
, code
, cfg
, NULL
);
5168 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_JIT_ICALL
,
5169 (gpointer
)"mono_tls_get_lmf_addr");
5170 if ((FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) && !cfg
->compile_aot
) {
5171 ppc_load_func (code
, PPC_CALL_REG
, 0);
5172 ppc_mtlr (code
, PPC_CALL_REG
);
5177 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5178 /* lmf_offset is the offset from the previous stack pointer,
5179 * alloc_size is the total stack space allocated, so the offset
5180 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5181 * The pointer to the struct is put in ppc_r12 (new_lmf).
5182 * The callee-saved registers are already in the MonoLMF structure
5184 ppc_addi (code
, ppc_r12
, ppc_sp
, alloc_size
- lmf_offset
);
5185 /* ppc_r3 is the result from mono_get_lmf_addr () */
5186 ppc_stptr (code
, ppc_r3
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
), ppc_r12
);
5187 /* new_lmf->previous_lmf = *lmf_addr */
5188 ppc_ldptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r3
);
5189 ppc_stptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r12
);
5190 /* *(lmf_addr) = r12 */
5191 ppc_stptr (code
, ppc_r12
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r3
);
5192 /* save method info */
5193 if (cfg
->compile_aot
)
5195 ppc_load (code
, ppc_r0
, 0);
5197 ppc_load_ptr (code
, ppc_r0
, method
);
5198 ppc_stptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, method
), ppc_r12
);
5199 ppc_stptr (code
, ppc_sp
, G_STRUCT_OFFSET(MonoLMF
, ebp
), ppc_r12
);
5200 /* save the current IP */
5201 if (cfg
->compile_aot
) {
5203 ppc_mflr (code
, ppc_r0
);
5205 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
5206 #ifdef __mono_ppc64__
5207 ppc_load_sequence (code
, ppc_r0
, (guint64
)0x0101010101010101LL
);
5209 ppc_load_sequence (code
, ppc_r0
, (gulong
)0x01010101L
);
5212 ppc_stptr (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, eip
), ppc_r12
);
5215 set_code_cursor (cfg
, code
);
5222 mono_arch_emit_epilog (MonoCompile
*cfg
)
5224 MonoMethod
*method
= cfg
->method
;
5226 int max_epilog_size
= 16 + 20*4;
5229 if (cfg
->method
->save_lmf
)
5230 max_epilog_size
+= 128;
5232 code
= realloc_code (cfg
, max_epilog_size
);
5236 if (method
->save_lmf
) {
5238 pos
+= sizeof (MonoLMF
);
5240 /* save the frame reg in r8 */
5241 ppc_mr (code
, ppc_r8
, cfg
->frame_reg
);
5242 ppc_addi (code
, ppc_r12
, cfg
->frame_reg
, cfg
->stack_usage
- lmf_offset
);
5243 /* r5 = previous_lmf */
5244 ppc_ldptr (code
, ppc_r5
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r12
);
5246 ppc_ldptr (code
, ppc_r6
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
), ppc_r12
);
5247 /* *(lmf_addr) = previous_lmf */
5248 ppc_stptr (code
, ppc_r5
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r6
);
5249 /* FIXME: speedup: there is no actual need to restore the registers if
5250 * we didn't actually change them (idea from Zoltan).
5253 ppc_ldr_multiple (code
, ppc_r13
, G_STRUCT_OFFSET(MonoLMF
, iregs
), ppc_r12
);
5255 /*for (i = 14; i < 32; i++) {
5256 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5258 g_assert (ppc_is_imm16 (cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
));
5259 /* use the saved copy of the frame reg in r8 */
5260 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
5261 ppc_ldr (code
, ppc_r0
, cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
, ppc_r8
);
5262 ppc_mtlr (code
, ppc_r0
);
5264 ppc_addic (code
, ppc_sp
, ppc_r8
, cfg
->stack_usage
);
5266 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
5267 long return_offset
= cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
;
5268 if (ppc_is_imm16 (return_offset
)) {
5269 ppc_ldr (code
, ppc_r0
, return_offset
, cfg
->frame_reg
);
5271 ppc_load (code
, ppc_r12
, return_offset
);
5272 ppc_ldr_indexed (code
, ppc_r0
, cfg
->frame_reg
, ppc_r12
);
5274 ppc_mtlr (code
, ppc_r0
);
5276 if (ppc_is_imm16 (cfg
->stack_usage
)) {
5277 int offset
= cfg
->stack_usage
;
5278 for (i
= 13; i
<= 31; i
++) {
5279 if (cfg
->used_int_regs
& (1 << i
))
5280 offset
-= sizeof (target_mgreg_t
);
5282 if (cfg
->frame_reg
!= ppc_sp
)
5283 ppc_mr (code
, ppc_r12
, cfg
->frame_reg
);
5284 /* note r31 (possibly the frame register) is restored last */
5285 for (i
= 13; i
<= 31; i
++) {
5286 if (cfg
->used_int_regs
& (1 << i
)) {
5287 ppc_ldr (code
, i
, offset
, cfg
->frame_reg
);
5288 offset
+= sizeof (target_mgreg_t
);
5291 if (cfg
->frame_reg
!= ppc_sp
)
5292 ppc_addi (code
, ppc_sp
, ppc_r12
, cfg
->stack_usage
);
5294 ppc_addi (code
, ppc_sp
, ppc_sp
, cfg
->stack_usage
);
5296 ppc_load32 (code
, ppc_r12
, cfg
->stack_usage
);
5297 if (cfg
->used_int_regs
) {
5298 ppc_add (code
, ppc_r12
, cfg
->frame_reg
, ppc_r12
);
5299 for (i
= 31; i
>= 13; --i
) {
5300 if (cfg
->used_int_regs
& (1 << i
)) {
5301 pos
+= sizeof (target_mgreg_t
);
5302 ppc_ldr (code
, i
, -pos
, ppc_r12
);
5305 ppc_mr (code
, ppc_sp
, ppc_r12
);
5307 ppc_add (code
, ppc_sp
, cfg
->frame_reg
, ppc_r12
);
5313 set_code_cursor (cfg
, code
);
5316 #endif /* ifndef DISABLE_JIT */
5318 /* remove once throw_exception_by_name is eliminated */
5320 exception_id_by_name (const char *name
)
5322 if (strcmp (name
, "IndexOutOfRangeException") == 0)
5323 return MONO_EXC_INDEX_OUT_OF_RANGE
;
5324 if (strcmp (name
, "OverflowException") == 0)
5325 return MONO_EXC_OVERFLOW
;
5326 if (strcmp (name
, "ArithmeticException") == 0)
5327 return MONO_EXC_ARITHMETIC
;
5328 if (strcmp (name
, "DivideByZeroException") == 0)
5329 return MONO_EXC_DIVIDE_BY_ZERO
;
5330 if (strcmp (name
, "InvalidCastException") == 0)
5331 return MONO_EXC_INVALID_CAST
;
5332 if (strcmp (name
, "NullReferenceException") == 0)
5333 return MONO_EXC_NULL_REF
;
5334 if (strcmp (name
, "ArrayTypeMismatchException") == 0)
5335 return MONO_EXC_ARRAY_TYPE_MISMATCH
;
5336 if (strcmp (name
, "ArgumentException") == 0)
5337 return MONO_EXC_ARGUMENT
;
5338 g_error ("Unknown intrinsic exception %s\n", name
);
5344 mono_arch_emit_exceptions (MonoCompile
*cfg
)
5346 MonoJumpInfo
*patch_info
;
5349 guint8
* exc_throw_pos
[MONO_EXC_INTRINS_NUM
];
5350 guint8 exc_throw_found
[MONO_EXC_INTRINS_NUM
];
5351 int max_epilog_size
= 50;
5353 for (i
= 0; i
< MONO_EXC_INTRINS_NUM
; i
++) {
5354 exc_throw_pos
[i
] = NULL
;
5355 exc_throw_found
[i
] = 0;
5358 /* count the number of exception infos */
5361 * make sure we have enough space for exceptions
5363 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5364 if (patch_info
->type
== MONO_PATCH_INFO_EXC
) {
5365 i
= exception_id_by_name (patch_info
->data
.target
);
5366 if (!exc_throw_found
[i
]) {
5367 max_epilog_size
+= (2 * PPC_LOAD_SEQUENCE_LENGTH
) + 5 * 4;
5368 exc_throw_found
[i
] = TRUE
;
5370 } else if (patch_info
->type
== MONO_PATCH_INFO_BB_OVF
)
5371 max_epilog_size
+= 12;
5372 else if (patch_info
->type
== MONO_PATCH_INFO_EXC_OVF
) {
5373 MonoOvfJump
*ovfj
= (MonoOvfJump
*)patch_info
->data
.target
;
5374 i
= exception_id_by_name (ovfj
->data
.exception
);
5375 if (!exc_throw_found
[i
]) {
5376 max_epilog_size
+= (2 * PPC_LOAD_SEQUENCE_LENGTH
) + 5 * 4;
5377 exc_throw_found
[i
] = TRUE
;
5379 max_epilog_size
+= 8;
5383 code
= realloc_code (cfg
, max_epilog_size
);
5385 /* add code to raise exceptions */
5386 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
5387 switch (patch_info
->type
) {
5388 case MONO_PATCH_INFO_BB_OVF
: {
5389 MonoOvfJump
*ovfj
= (MonoOvfJump
*)patch_info
->data
.target
;
5390 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
5391 /* patch the initial jump */
5392 ppc_patch (ip
, code
);
5393 ppc_bc (code
, ovfj
->b0_cond
, ovfj
->b1_cond
, 2);
5395 ppc_patch (code
- 4, ip
+ 4); /* jump back after the initiali branch */
5396 /* jump back to the true target */
5398 ip
= ovfj
->data
.bb
->native_offset
+ cfg
->native_code
;
5399 ppc_patch (code
- 4, ip
);
5400 patch_info
->type
= MONO_PATCH_INFO_NONE
;
5403 case MONO_PATCH_INFO_EXC_OVF
: {
5404 MonoOvfJump
*ovfj
= (MonoOvfJump
*)patch_info
->data
.target
;
5405 MonoJumpInfo
*newji
;
5406 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
5407 unsigned char *bcl
= code
;
5408 /* patch the initial jump: we arrived here with a call */
5409 ppc_patch (ip
, code
);
5410 ppc_bc (code
, ovfj
->b0_cond
, ovfj
->b1_cond
, 0);
5412 ppc_patch (code
- 4, ip
+ 4); /* jump back after the initiali branch */
5413 /* patch the conditional jump to the right handler */
5414 /* make it processed next */
5415 newji
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfo
));
5416 newji
->type
= MONO_PATCH_INFO_EXC
;
5417 newji
->ip
.i
= bcl
- cfg
->native_code
;
5418 newji
->data
.target
= ovfj
->data
.exception
;
5419 newji
->next
= patch_info
->next
;
5420 patch_info
->next
= newji
;
5421 patch_info
->type
= MONO_PATCH_INFO_NONE
;
5424 case MONO_PATCH_INFO_EXC
: {
5425 MonoClass
*exc_class
;
5427 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
5428 i
= exception_id_by_name (patch_info
->data
.target
);
5429 if (exc_throw_pos
[i
] && !(ip
> exc_throw_pos
[i
] && ip
- exc_throw_pos
[i
] > 50000)) {
5430 ppc_patch (ip
, exc_throw_pos
[i
]);
5431 patch_info
->type
= MONO_PATCH_INFO_NONE
;
5434 exc_throw_pos
[i
] = code
;
5437 exc_class
= mono_class_load_from_name (mono_defaults
.corlib
, "System", patch_info
->data
.name
);
5439 ppc_patch (ip
, code
);
5440 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5441 ppc_load (code
, ppc_r3
, m_class_get_type_token (exc_class
));
5442 /* we got here from a conditional call, so the calling ip is set in lr */
5443 ppc_mflr (code
, ppc_r4
);
5444 patch_info
->type
= MONO_PATCH_INFO_JIT_ICALL
;
5445 patch_info
->data
.name
= "mono_arch_throw_corlib_exception";
5446 patch_info
->ip
.i
= code
- cfg
->native_code
;
5447 if (FORCE_INDIR_CALL
|| cfg
->method
->dynamic
) {
5448 ppc_load_func (code
, PPC_CALL_REG
, 0);
5449 ppc_mtctr (code
, PPC_CALL_REG
);
5450 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5462 set_code_cursor (cfg
, code
);
5468 try_offset_access (void *value
, guint32 idx
)
5470 register void* me
__asm__ ("r2");
5471 void ***p
= (void***)((char*)me
+ 284);
5472 int idx1
= idx
/ 32;
5473 int idx2
= idx
% 32;
5476 if (value
!= p
[idx1
][idx2
])
5483 mono_arch_finish_init (void)
5488 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
5492 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5494 #define LOADSTORE_SIZE 4
5495 #define JUMP_IMM_SIZE 12
5496 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5497 #define ENABLE_WRONG_METHOD_CHECK 0
5500 * LOCKING: called with the domain lock held
5503 mono_arch_build_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
,
5504 gpointer fail_tramp
)
5508 guint8
*code
, *start
;
5510 for (i
= 0; i
< count
; ++i
) {
5511 MonoIMTCheckItem
*item
= imt_entries
[i
];
5512 if (item
->is_equals
) {
5513 if (item
->check_target_idx
) {
5514 if (!item
->compare_done
)
5515 item
->chunk_size
+= CMP_SIZE
;
5516 if (item
->has_target_code
)
5517 item
->chunk_size
+= BR_SIZE
+ JUMP_IMM32_SIZE
;
5519 item
->chunk_size
+= LOADSTORE_SIZE
+ BR_SIZE
+ JUMP_IMM_SIZE
;
5522 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ JUMP_IMM32_SIZE
* 2;
5523 if (!item
->has_target_code
)
5524 item
->chunk_size
+= LOADSTORE_SIZE
;
5526 item
->chunk_size
+= LOADSTORE_SIZE
+ JUMP_IMM_SIZE
;
5527 #if ENABLE_WRONG_METHOD_CHECK
5528 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
+ 4;
5533 item
->chunk_size
+= CMP_SIZE
+ BR_SIZE
;
5534 imt_entries
[item
->check_target_idx
]->compare_done
= TRUE
;
5536 size
+= item
->chunk_size
;
5538 /* the initial load of the vtable address */
5539 size
+= PPC_LOAD_SEQUENCE_LENGTH
+ LOADSTORE_SIZE
;
5541 code
= mono_method_alloc_generic_virtual_trampoline (domain
, size
);
5543 code
= mono_domain_code_reserve (domain
, size
);
5548 * We need to save and restore r12 because it might be
5549 * used by the caller as the vtable register, so
5550 * clobbering it will trip up the magic trampoline.
5552 * FIXME: Get rid of this by making sure that r12 is
5553 * not used as the vtable register in interface calls.
5555 ppc_stptr (code
, ppc_r12
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
5556 ppc_load (code
, ppc_r12
, (gsize
)(& (vtable
->vtable
[0])));
5558 for (i
= 0; i
< count
; ++i
) {
5559 MonoIMTCheckItem
*item
= imt_entries
[i
];
5560 item
->code_target
= code
;
5561 if (item
->is_equals
) {
5562 if (item
->check_target_idx
) {
5563 if (!item
->compare_done
) {
5564 ppc_load (code
, ppc_r0
, (gsize
)item
->key
);
5565 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5567 item
->jmp_code
= code
;
5568 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5569 if (item
->has_target_code
) {
5570 ppc_load_ptr (code
, ppc_r0
, item
->value
.target_code
);
5572 ppc_ldptr (code
, ppc_r0
, (sizeof (target_mgreg_t
) * item
->value
.vtable_slot
), ppc_r12
);
5573 ppc_ldptr (code
, ppc_r12
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
5575 ppc_mtctr (code
, ppc_r0
);
5576 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5579 ppc_load (code
, ppc_r0
, (gulong
)item
->key
);
5580 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5581 item
->jmp_code
= code
;
5582 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5583 if (item
->has_target_code
) {
5584 ppc_load_ptr (code
, ppc_r0
, item
->value
.target_code
);
5587 ppc_load_ptr (code
, ppc_r0
, & (vtable
->vtable
[item
->value
.vtable_slot
]));
5588 ppc_ldptr_indexed (code
, ppc_r0
, 0, ppc_r0
);
5590 ppc_mtctr (code
, ppc_r0
);
5591 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5592 ppc_patch (item
->jmp_code
, code
);
5593 ppc_load_ptr (code
, ppc_r0
, fail_tramp
);
5594 ppc_mtctr (code
, ppc_r0
);
5595 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5596 item
->jmp_code
= NULL
;
5598 /* enable the commented code to assert on wrong method */
5599 #if ENABLE_WRONG_METHOD_CHECK
5600 ppc_load (code
, ppc_r0
, (guint32
)item
->key
);
5601 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5602 item
->jmp_code
= code
;
5603 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 0);
5605 ppc_ldptr (code
, ppc_r0
, (sizeof (target_mgreg_t
) * item
->value
.vtable_slot
), ppc_r12
);
5606 ppc_ldptr (code
, ppc_r12
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
5607 ppc_mtctr (code
, ppc_r0
);
5608 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
5609 #if ENABLE_WRONG_METHOD_CHECK
5610 ppc_patch (item
->jmp_code
, code
);
5612 item
->jmp_code
= NULL
;
5617 ppc_load (code
, ppc_r0
, (gulong
)item
->key
);
5618 ppc_compare_log (code
, 0, MONO_ARCH_IMT_REG
, ppc_r0
);
5619 item
->jmp_code
= code
;
5620 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_LT
, 0);
5623 /* patch the branches to get to the target items */
5624 for (i
= 0; i
< count
; ++i
) {
5625 MonoIMTCheckItem
*item
= imt_entries
[i
];
5626 if (item
->jmp_code
) {
5627 if (item
->check_target_idx
) {
5628 ppc_patch (item
->jmp_code
, imt_entries
[item
->check_target_idx
]->code_target
);
5634 UnlockedAdd (&mono_stats
.imt_trampolines_size
, code
- start
);
5635 g_assert (code
- start
<= size
);
5636 mono_arch_flush_icache (start
, size
);
5637 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE
, NULL
));
5639 mono_tramp_info_register (mono_tramp_info_create (NULL
, start
, code
- start
, NULL
, NULL
), domain
);
5645 mono_arch_find_imt_method (host_mgreg_t
*regs
, guint8
*code
)
5647 host_mgreg_t
*r
= (host_mgreg_t
*)regs
;
5649 return (MonoMethod
*)(gsize
) r
[MONO_ARCH_IMT_REG
];
5653 mono_arch_find_static_call_vtable (host_mgreg_t
*regs
, guint8
*code
)
5655 return (MonoVTable
*)(gsize
) regs
[MONO_ARCH_RGCTX_REG
];
5659 mono_arch_get_cie_program (void)
5663 mono_add_unwind_op_def_cfa (l
, (guint8
*)NULL
, (guint8
*)NULL
, ppc_r1
, 0);
5669 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
5671 MonoInst
*ins
= NULL
;
5674 if (cmethod
->klass
== mono_class_try_get_math_class ()) {
5675 if (strcmp (cmethod
->name
, "Sqrt") == 0) {
5677 } else if (strcmp (cmethod
->name
, "Abs") == 0 && fsig
->params
[0]->type
== MONO_TYPE_R8
) {
5681 if (opcode
&& fsig
->param_count
== 1) {
5682 MONO_INST_NEW (cfg
, ins
, opcode
);
5683 ins
->type
= STACK_R8
;
5684 ins
->dreg
= mono_alloc_freg (cfg
);
5685 ins
->sreg1
= args
[0]->dreg
;
5686 MONO_ADD_INS (cfg
->cbb
, ins
);
5689 /* Check for Min/Max for (u)int(32|64) */
5691 if (cpu_hw_caps
& PPC_ISA_2_03
) {
5692 if (strcmp (cmethod
->name
, "Min") == 0) {
5693 if (fsig
->params
[0]->type
== MONO_TYPE_I4
)
5695 if (fsig
->params
[0]->type
== MONO_TYPE_U4
)
5696 opcode
= OP_IMIN_UN
;
5697 #ifdef __mono_ppc64__
5698 else if (fsig
->params
[0]->type
== MONO_TYPE_I8
)
5700 else if (fsig
->params
[0]->type
== MONO_TYPE_U8
)
5701 opcode
= OP_LMIN_UN
;
5703 } else if (strcmp (cmethod
->name
, "Max") == 0) {
5704 if (fsig
->params
[0]->type
== MONO_TYPE_I4
)
5706 if (fsig
->params
[0]->type
== MONO_TYPE_U4
)
5707 opcode
= OP_IMAX_UN
;
5708 #ifdef __mono_ppc64__
5709 else if (fsig
->params
[0]->type
== MONO_TYPE_I8
)
5711 else if (fsig
->params
[0]->type
== MONO_TYPE_U8
)
5712 opcode
= OP_LMAX_UN
;
5716 * TODO: Floating point version with fsel, but fsel has
5717 * some peculiarities (need a scratch reg unless
5718 * comparing with 0, NaN/Inf behaviour (then MathF too)
5722 if (opcode
&& fsig
->param_count
== 2) {
5723 MONO_INST_NEW (cfg
, ins
, opcode
);
5724 ins
->type
= fsig
->params
[0]->type
== MONO_TYPE_I4
? STACK_I4
: STACK_I8
;
5725 ins
->dreg
= mono_alloc_ireg (cfg
);
5726 ins
->sreg1
= args
[0]->dreg
;
5727 ins
->sreg2
= args
[1]->dreg
;
5728 MONO_ADD_INS (cfg
->cbb
, ins
);
5731 /* Rounding instructions */
5733 if ((cpu_hw_caps
& PPC_ISA_2X
) && (fsig
->param_count
== 1) && (fsig
->params
[0]->type
== MONO_TYPE_R8
)) {
5735 * XXX: sysmath.c and frin imply round is a little bit
5736 * more complicated than expected? but amd64 does this?
5737 * (also, no float versions of these ops, but frsp
5738 * could be preprended?)
5740 if (!strcmp (cmethod
->name
, "Round"))
5742 else if (!strcmp (cmethod
->name
, "Floor"))
5743 opcode
= OP_PPC_FLOOR
;
5744 else if (!strcmp (cmethod
->name
, "Ceiling"))
5745 opcode
= OP_PPC_CEIL
;
5746 else if (!strcmp (cmethod
->name
, "Truncate"))
5747 opcode
= OP_PPC_TRUNC
;
5749 MONO_INST_NEW (cfg
, ins
, opcode
);
5750 ins
->type
= STACK_R8
;
5751 ins
->dreg
= mono_alloc_freg (cfg
);
5752 ins
->sreg1
= args
[0]->dreg
;
5753 MONO_ADD_INS (cfg
->cbb
, ins
);
5757 if (cmethod
->klass
== mono_class_try_get_mathf_class ()) {
5758 if (strcmp (cmethod
->name
, "Sqrt") == 0) {
5760 } /* XXX: POWER has no single-precision normal FPU abs? */
5762 if (opcode
&& fsig
->param_count
== 1) {
5763 MONO_INST_NEW (cfg
, ins
, opcode
);
5764 ins
->type
= STACK_R4
;
5765 ins
->dreg
= mono_alloc_freg (cfg
);
5766 ins
->sreg1
= args
[0]->dreg
;
5767 MONO_ADD_INS (cfg
->cbb
, ins
);
5774 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5777 return (host_mgreg_t
)(gsize
)MONO_CONTEXT_GET_SP (ctx
);
5779 return ctx
->regs
[reg
];
5783 mono_arch_get_patch_offset (guint8
*code
)
5789 * mono_aot_emit_load_got_addr:
5791 * Emit code to load the got address.
5792 * On PPC, the result is placed into r30.
5795 mono_arch_emit_load_got_addr (guint8
*start
, guint8
*code
, MonoCompile
*cfg
, MonoJumpInfo
**ji
)
5798 ppc_mflr (code
, ppc_r30
);
5800 mono_add_patch_info (cfg
, code
- start
, MONO_PATCH_INFO_GOT_OFFSET
, NULL
);
5802 *ji
= mono_patch_info_list_prepend (*ji
, code
- start
, MONO_PATCH_INFO_GOT_OFFSET
, NULL
);
5803 /* arch_emit_got_address () patches this */
5804 #if defined(TARGET_POWERPC64)
5810 ppc_load32 (code
, ppc_r0
, 0);
5811 ppc_add (code
, ppc_r30
, ppc_r30
, ppc_r0
);
5814 set_code_cursor (cfg
, code
);
5819 * mono_ppc_emit_load_aotconst:
5821 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5822 * TARGET from the mscorlib GOT in full-aot code.
5823 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5827 mono_arch_emit_load_aotconst (guint8
*start
, guint8
*code
, MonoJumpInfo
**ji
, MonoJumpInfoType tramp_type
, gconstpointer target
)
5829 /* Load the mscorlib got address */
5830 ppc_ldptr (code
, ppc_r12
, sizeof (target_mgreg_t
), ppc_r30
);
5831 *ji
= mono_patch_info_list_prepend (*ji
, code
- start
, tramp_type
, target
);
5832 /* arch_emit_got_access () patches this */
5833 ppc_load32 (code
, ppc_r0
, 0);
5834 ppc_ldptr_indexed (code
, ppc_r12
, ppc_r12
, ppc_r0
);
5839 /* Soft Debug support */
5840 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5847 * mono_arch_set_breakpoint:
5849 * See mini-amd64.c for docs.
5852 mono_arch_set_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5855 guint8
*orig_code
= code
;
5857 ppc_load_sequence (code
, ppc_r12
, (gsize
)bp_trigger_page
);
5858 ppc_ldptr (code
, ppc_r12
, 0, ppc_r12
);
5860 g_assert (code
- orig_code
== BREAKPOINT_SIZE
);
5862 mono_arch_flush_icache (orig_code
, code
- orig_code
);
5866 * mono_arch_clear_breakpoint:
5868 * See mini-amd64.c for docs.
5871 mono_arch_clear_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
5876 for (i
= 0; i
< BREAKPOINT_SIZE
/ 4; ++i
)
5879 mono_arch_flush_icache (ip
, code
- ip
);
5883 * mono_arch_is_breakpoint_event:
5885 * See mini-amd64.c for docs.
5888 mono_arch_is_breakpoint_event (void *info
, void *sigctx
)
5890 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5891 /* Sometimes the address is off by 4 */
5892 if (sinfo
->si_addr
>= bp_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)bp_trigger_page
+ 128)
5899 * mono_arch_skip_breakpoint:
5901 * See mini-amd64.c for docs.
5904 mono_arch_skip_breakpoint (MonoContext
*ctx
, MonoJitInfo
*ji
)
5906 /* skip the ldptr */
5907 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
5915 * mono_arch_start_single_stepping:
5917 * See mini-amd64.c for docs.
5920 mono_arch_start_single_stepping (void)
5922 mono_mprotect (ss_trigger_page
, mono_pagesize (), 0);
5926 * mono_arch_stop_single_stepping:
5928 * See mini-amd64.c for docs.
5931 mono_arch_stop_single_stepping (void)
5933 mono_mprotect (ss_trigger_page
, mono_pagesize (), MONO_MMAP_READ
);
5937 * mono_arch_is_single_step_event:
5939 * See mini-amd64.c for docs.
5942 mono_arch_is_single_step_event (void *info
, void *sigctx
)
5944 siginfo_t
* sinfo
= (siginfo_t
*) info
;
5945 /* Sometimes the address is off by 4 */
5946 if (sinfo
->si_addr
>= ss_trigger_page
&& (guint8
*)sinfo
->si_addr
<= (guint8
*)ss_trigger_page
+ 128)
5953 * mono_arch_skip_single_step:
5955 * See mini-amd64.c for docs.
5958 mono_arch_skip_single_step (MonoContext
*ctx
)
5960 /* skip the ldptr */
5961 MONO_CONTEXT_SET_IP (ctx
, (guint8
*)MONO_CONTEXT_GET_IP (ctx
) + 4);
5965 * mono_arch_create_seq_point_info:
5967 * See mini-amd64.c for docs.
5970 mono_arch_get_seq_point_info (MonoDomain
*domain
, guint8
*code
)
5979 mono_arch_opcode_supported (int opcode
)
5982 case OP_ATOMIC_ADD_I4
:
5983 case OP_ATOMIC_CAS_I4
:
5984 #ifdef TARGET_POWERPC64
5985 case OP_ATOMIC_ADD_I8
:
5986 case OP_ATOMIC_CAS_I8
: