[AOT] Make native linker name configurable (#20816)
[mono-project.git] / mono / mini / mini-ppc.c
blob1b2e38a01bed5b41fb60b498dd667f6e6d619966
1 /**
2 * \file
3 * PowerPC backend for the Mono code generator
5 * Authors:
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
13 #include "mini.h"
14 #include <string.h>
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>
23 #include "mono/utils/mono-tls-inline.h"
25 #include "mini-ppc.h"
26 #ifdef TARGET_POWERPC64
27 #include "cpu-ppc64.h"
28 #else
29 #include "cpu-ppc.h"
30 #endif
31 #include "ir-emit.h"
32 #include "aot-runtime.h"
33 #include "mini-runtime.h"
34 #ifdef __APPLE__
35 #include <sys/sysctl.h>
36 #endif
37 #ifdef __linux__
38 #include <unistd.h>
39 #endif
40 #ifdef _AIX
41 #include <sys/systemcfg.h>
42 #endif
44 static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math")
45 static GENERATE_TRY_GET_CLASS_WITH_CACHE (mathf, "System", "MathF")
47 #define FORCE_INDIR_CALL 1
49 enum {
50 TLS_MODE_DETECT,
51 TLS_MODE_FAILED,
52 TLS_MODE_LTHREADS,
53 TLS_MODE_NPTL,
54 TLS_MODE_DARWIN_G4,
55 TLS_MODE_DARWIN_G5
58 /* cpu_hw_caps contains the flags defined below */
59 static int cpu_hw_caps = 0;
60 static int cachelinesize = 0;
61 static int cachelineinc = 0;
62 enum {
63 PPC_ICACHE_SNOOP = 1 << 0,
64 PPC_MULTIPLE_LS_UNITS = 1 << 1,
65 PPC_SMP_CAPABLE = 1 << 2,
66 PPC_ISA_2X = 1 << 3,
67 PPC_ISA_64 = 1 << 4,
68 PPC_MOVE_FPR_GPR = 1 << 5,
69 PPC_ISA_2_03 = 1 << 6,
70 PPC_HW_CAP_END
73 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
75 /* This mutex protects architecture specific caches */
76 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
77 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
78 static mono_mutex_t mini_arch_mutex;
81 * The code generated for sequence points reads from this location, which is
82 * made read-only when single stepping is enabled.
84 static gpointer ss_trigger_page;
86 /* Enabled breakpoints read from this trigger page */
87 static gpointer bp_trigger_page;
89 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
90 MonoInst *inst; \
91 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
92 inst->type = STACK_R8; \
93 inst->dreg = (dr); \
94 inst->inst_p0 = (void*)(addr); \
95 mono_bblock_add_inst (cfg->cbb, inst); \
96 } while (0)
98 const char*
99 mono_arch_regname (int reg) {
100 static const char rnames[][4] = {
101 "r0", "sp", "r2", "r3", "r4",
102 "r5", "r6", "r7", "r8", "r9",
103 "r10", "r11", "r12", "r13", "r14",
104 "r15", "r16", "r17", "r18", "r19",
105 "r20", "r21", "r22", "r23", "r24",
106 "r25", "r26", "r27", "r28", "r29",
107 "r30", "r31"
109 if (reg >= 0 && reg < 32)
110 return rnames [reg];
111 return "unknown";
114 const char*
115 mono_arch_fregname (int reg) {
116 static const char rnames[][4] = {
117 "f0", "f1", "f2", "f3", "f4",
118 "f5", "f6", "f7", "f8", "f9",
119 "f10", "f11", "f12", "f13", "f14",
120 "f15", "f16", "f17", "f18", "f19",
121 "f20", "f21", "f22", "f23", "f24",
122 "f25", "f26", "f27", "f28", "f29",
123 "f30", "f31"
125 if (reg >= 0 && reg < 32)
126 return rnames [reg];
127 return "unknown";
130 /* this function overwrites r0, r11, r12 */
131 static guint8*
132 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
134 /* unrolled, use the counter in big */
135 if (size > sizeof (target_mgreg_t) * 5) {
136 long shifted = size / TARGET_SIZEOF_VOID_P;
137 guint8 *copy_loop_start, *copy_loop_jump;
139 ppc_load (code, ppc_r0, shifted);
140 ppc_mtctr (code, ppc_r0);
141 //g_assert (sreg == ppc_r12);
142 ppc_addi (code, ppc_r11, dreg, (doffset - sizeof (target_mgreg_t)));
143 ppc_addi (code, ppc_r12, sreg, (soffset - sizeof (target_mgreg_t)));
144 copy_loop_start = code;
145 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (target_mgreg_t), ppc_r12);
146 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (target_mgreg_t), ppc_r11);
147 copy_loop_jump = code;
148 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
149 ppc_patch (copy_loop_jump, copy_loop_start);
150 size -= shifted * sizeof (target_mgreg_t);
151 doffset = soffset = 0;
152 dreg = ppc_r11;
154 #ifdef __mono_ppc64__
155 /* the hardware has multiple load/store units and the move is long
156 enough to use more then one register, then use load/load/store/store
157 to execute 2 instructions per cycle. */
158 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
159 while (size >= 16) {
160 ppc_ldptr (code, ppc_r0, soffset, sreg);
161 ppc_ldptr (code, ppc_r11, soffset+8, sreg);
162 ppc_stptr (code, ppc_r0, doffset, dreg);
163 ppc_stptr (code, ppc_r11, doffset+8, dreg);
164 size -= 16;
165 soffset += 16;
166 doffset += 16;
169 while (size >= 8) {
170 ppc_ldr (code, ppc_r0, soffset, sreg);
171 ppc_str (code, ppc_r0, doffset, dreg);
172 size -= 8;
173 soffset += 8;
174 doffset += 8;
176 #else
177 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
178 while (size >= 8) {
179 ppc_lwz (code, ppc_r0, soffset, sreg);
180 ppc_lwz (code, ppc_r11, soffset+4, sreg);
181 ppc_stw (code, ppc_r0, doffset, dreg);
182 ppc_stw (code, ppc_r11, doffset+4, dreg);
183 size -= 8;
184 soffset += 8;
185 doffset += 8;
188 #endif
189 while (size >= 4) {
190 ppc_lwz (code, ppc_r0, soffset, sreg);
191 ppc_stw (code, ppc_r0, doffset, dreg);
192 size -= 4;
193 soffset += 4;
194 doffset += 4;
196 while (size >= 2) {
197 ppc_lhz (code, ppc_r0, soffset, sreg);
198 ppc_sth (code, ppc_r0, doffset, dreg);
199 size -= 2;
200 soffset += 2;
201 doffset += 2;
203 while (size >= 1) {
204 ppc_lbz (code, ppc_r0, soffset, sreg);
205 ppc_stb (code, ppc_r0, doffset, dreg);
206 size -= 1;
207 soffset += 1;
208 doffset += 1;
210 return code;
214 * mono_arch_get_argument_info:
215 * @csig: a method signature
216 * @param_count: the number of parameters to consider
217 * @arg_info: an array to store the result infos
219 * Gathers information on parameters such as size, alignment and
220 * padding. arg_info should be large enought to hold param_count + 1 entries.
222 * Returns the size of the activation frame.
225 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
227 #ifdef __mono_ppc64__
228 NOT_IMPLEMENTED;
229 return -1;
230 #else
231 int k, frame_size = 0;
232 int size, align, pad;
233 int offset = 8;
235 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
236 frame_size += sizeof (target_mgreg_t);
237 offset += 4;
240 arg_info [0].offset = offset;
242 if (csig->hasthis) {
243 frame_size += sizeof (target_mgreg_t);
244 offset += 4;
247 arg_info [0].size = frame_size;
249 for (k = 0; k < param_count; k++) {
251 if (csig->pinvoke)
252 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
253 else
254 size = mini_type_stack_size (csig->params [k], &align);
256 /* ignore alignment for now */
257 align = 1;
259 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
260 arg_info [k].pad = pad;
261 frame_size += size;
262 arg_info [k + 1].pad = 0;
263 arg_info [k + 1].size = size;
264 offset += pad;
265 arg_info [k + 1].offset = offset;
266 offset += size;
269 align = MONO_ARCH_FRAME_ALIGNMENT;
270 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
271 arg_info [k].pad = pad;
273 return frame_size;
274 #endif
277 #ifdef __mono_ppc64__
278 static gboolean
279 is_load_sequence (guint32 *seq)
281 return ppc_opcode (seq [0]) == 15 && /* lis */
282 ppc_opcode (seq [1]) == 24 && /* ori */
283 ppc_opcode (seq [2]) == 30 && /* sldi */
284 ppc_opcode (seq [3]) == 25 && /* oris */
285 ppc_opcode (seq [4]) == 24; /* ori */
288 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
289 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
290 #endif
292 /* ld || lwz */
293 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
295 /* code must point to the blrl */
296 gboolean
297 mono_ppc_is_direct_call_sequence (guint32 *code)
299 #ifdef __mono_ppc64__
300 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
302 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
303 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
304 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
305 if (!is_load_sequence (&code [-8]))
306 return FALSE;
307 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
308 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (target_mgreg_t)) ||
309 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (target_mgreg_t));
311 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
312 return is_load_sequence (&code [-8]);
313 else
314 return is_load_sequence (&code [-6]);
316 return FALSE;
317 #else
318 g_assert(*code == 0x4e800021);
320 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
321 return ppc_opcode (code [-1]) == 31 &&
322 ppc_opcode (code [-2]) == 24 &&
323 ppc_opcode (code [-3]) == 15;
324 #endif
327 #define MAX_ARCH_DELEGATE_PARAMS 7
329 static guint8*
330 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
332 guint8 *code, *start;
334 if (has_target) {
335 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
337 start = code = mono_global_codeman_reserve (size);
338 if (!aot)
339 code = mono_ppc_create_pre_code_ftnptr (code);
341 /* Replace the this argument with the target */
342 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
343 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
344 /* it's a function descriptor */
345 /* Can't use ldptr as it doesn't work with r0 */
346 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
347 #endif
348 ppc_mtctr (code, ppc_r0);
349 ppc_ldptr (code, ppc_r3, MONO_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
350 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
352 g_assert ((code - start) <= size);
354 mono_arch_flush_icache (start, size);
355 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
356 } else {
357 int size, i;
359 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
360 start = code = mono_global_codeman_reserve (size);
361 if (!aot)
362 code = mono_ppc_create_pre_code_ftnptr (code);
364 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
365 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
366 /* it's a function descriptor */
367 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
368 #endif
369 ppc_mtctr (code, ppc_r0);
370 /* slide down the arguments */
371 for (i = 0; i < param_count; ++i) {
372 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
374 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
376 g_assert ((code - start) <= size);
378 mono_arch_flush_icache (start, size);
379 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
382 if (has_target) {
383 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
384 } else {
385 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
386 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
387 g_free (name);
390 return start;
393 GSList*
394 mono_arch_get_delegate_invoke_impls (void)
396 GSList *res = NULL;
397 MonoTrampInfo *info;
398 int i;
400 get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
401 res = g_slist_prepend (res, info);
403 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
404 get_delegate_invoke_impl (&info, FALSE, i, TRUE);
405 res = g_slist_prepend (res, info);
408 return res;
411 gpointer
412 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
414 guint8 *code, *start;
416 /* FIXME: Support more cases */
417 if (MONO_TYPE_ISSTRUCT (sig->ret))
418 return NULL;
420 if (has_target) {
421 static guint8* cached = NULL;
423 if (cached)
424 return cached;
426 if (mono_ee_features.use_aot_trampolines) {
427 start = (guint8*)mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
428 } else {
429 MonoTrampInfo *info;
430 start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
431 mono_tramp_info_register (info, NULL);
433 mono_memory_barrier ();
435 cached = start;
436 } else {
437 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
438 int i;
440 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
441 return NULL;
442 for (i = 0; i < sig->param_count; ++i)
443 if (!mono_is_regsize_var (sig->params [i]))
444 return NULL;
447 code = cache [sig->param_count];
448 if (code)
449 return code;
451 if (mono_ee_features.use_aot_trampolines) {
452 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
453 start = (guint8*)mono_aot_get_trampoline (name);
454 g_free (name);
455 } else {
456 MonoTrampInfo *info;
457 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
458 mono_tramp_info_register (info, NULL);
461 mono_memory_barrier ();
463 cache [sig->param_count] = start;
465 return start;
468 gpointer
469 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
471 return NULL;
474 gpointer
475 mono_arch_get_this_arg_from_call (host_mgreg_t *r, guint8 *code)
477 return (gpointer)(gsize)r [ppc_r3];
480 typedef struct {
481 long int type;
482 long int value;
483 } AuxVec;
485 #define MAX_AUX_ENTRIES 128
487 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
488 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
490 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
492 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
493 #define ISA_64 0x40000000
495 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
496 #define ISA_MOVE_FPR_GPR 0x00000200
498 * Initialize the cpu to execute managed code.
500 void
501 mono_arch_cpu_init (void)
506 * Initialize architecture specific code.
508 void
509 mono_arch_init (void)
511 #if defined(MONO_CROSS_COMPILE)
512 #elif defined(__APPLE__)
513 int mib [3];
514 size_t len = sizeof (cachelinesize);
516 mib [0] = CTL_HW;
517 mib [1] = HW_CACHELINE;
519 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
520 perror ("sysctl");
521 cachelinesize = 128;
522 } else {
523 cachelineinc = cachelinesize;
525 #elif defined(__linux__)
526 AuxVec vec [MAX_AUX_ENTRIES];
527 int i, vec_entries = 0;
528 /* sadly this will work only with 2.6 kernels... */
529 FILE* f = fopen ("/proc/self/auxv", "rb");
531 if (f) {
532 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
533 fclose (f);
536 for (i = 0; i < vec_entries; i++) {
537 int type = vec [i].type;
539 if (type == 19) { /* AT_DCACHEBSIZE */
540 cachelinesize = vec [i].value;
541 continue;
544 #elif defined(G_COMPILER_CODEWARRIOR)
545 cachelinesize = 32;
546 cachelineinc = 32;
547 #elif defined(_AIX)
548 /* FIXME: use block instead? */
549 cachelinesize = _system_configuration.icache_line;
550 cachelineinc = _system_configuration.icache_line;
551 #else
552 //#error Need a way to get cache line size
553 #endif
555 if (mono_hwcap_ppc_has_icache_snoop)
556 cpu_hw_caps |= PPC_ICACHE_SNOOP;
558 if (mono_hwcap_ppc_is_isa_2x)
559 cpu_hw_caps |= PPC_ISA_2X;
561 if (mono_hwcap_ppc_is_isa_2_03)
562 cpu_hw_caps |= PPC_ISA_2_03;
564 if (mono_hwcap_ppc_is_isa_64)
565 cpu_hw_caps |= PPC_ISA_64;
567 if (mono_hwcap_ppc_has_move_fpr_gpr)
568 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
570 if (mono_hwcap_ppc_has_multiple_ls_units)
571 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
573 if (!cachelinesize)
574 cachelinesize = 32;
576 if (!cachelineinc)
577 cachelineinc = cachelinesize;
579 if (mono_cpu_count () > 1)
580 cpu_hw_caps |= PPC_SMP_CAPABLE;
582 mono_os_mutex_init_recursive (&mini_arch_mutex);
584 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
585 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER);
586 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
588 // FIXME: Fix partial sharing for power and remove this
589 mono_set_partial_sharing_supported (FALSE);
593 * Cleanup architecture specific code.
595 void
596 mono_arch_cleanup (void)
598 mono_os_mutex_destroy (&mini_arch_mutex);
601 gboolean
602 mono_arch_have_fast_tls (void)
604 return FALSE;
608 * This function returns the optimizations supported on this cpu.
610 guint32
611 mono_arch_cpu_optimizations (guint32 *exclude_mask)
613 guint32 opts = 0;
615 /* no ppc-specific optimizations yet */
616 *exclude_mask = 0;
617 return opts;
621 * This function test for all SIMD functions supported.
623 * Returns a bitmask corresponding to all supported versions.
626 guint32
627 mono_arch_cpu_enumerate_simd_versions (void)
629 /* SIMD is currently unimplemented */
630 return 0;
633 #ifdef __mono_ppc64__
634 #define CASE_PPC32(c)
635 #define CASE_PPC64(c) case c:
636 #else
637 #define CASE_PPC32(c) case c:
638 #define CASE_PPC64(c)
639 #endif
641 static gboolean
642 is_regsize_var (MonoType *t) {
643 if (t->byref)
644 return TRUE;
645 t = mini_get_underlying_type (t);
646 switch (t->type) {
647 case MONO_TYPE_I4:
648 case MONO_TYPE_U4:
649 CASE_PPC64 (MONO_TYPE_I8)
650 CASE_PPC64 (MONO_TYPE_U8)
651 case MONO_TYPE_I:
652 case MONO_TYPE_U:
653 case MONO_TYPE_PTR:
654 case MONO_TYPE_FNPTR:
655 return TRUE;
656 case MONO_TYPE_OBJECT:
657 case MONO_TYPE_STRING:
658 case MONO_TYPE_CLASS:
659 case MONO_TYPE_SZARRAY:
660 case MONO_TYPE_ARRAY:
661 return TRUE;
662 case MONO_TYPE_GENERICINST:
663 if (!mono_type_generic_inst_is_valuetype (t))
664 return TRUE;
665 return FALSE;
666 case MONO_TYPE_VALUETYPE:
667 return FALSE;
669 return FALSE;
672 #ifndef DISABLE_JIT
673 GList *
674 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
676 GList *vars = NULL;
677 int i;
679 for (i = 0; i < cfg->num_varinfo; i++) {
680 MonoInst *ins = cfg->varinfo [i];
681 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
683 /* unused vars */
684 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
685 continue;
687 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
688 continue;
690 /* we can only allocate 32 bit values */
691 if (is_regsize_var (ins->inst_vtype)) {
692 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
693 g_assert (i == vmv->idx);
694 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
698 return vars;
700 #endif /* ifndef DISABLE_JIT */
702 GList *
703 mono_arch_get_global_int_regs (MonoCompile *cfg)
705 GList *regs = NULL;
706 int i, top = 32;
707 if (cfg->frame_reg != ppc_sp)
708 top = 31;
709 /* ppc_r13 is used by the system on PPC EABI */
710 for (i = 14; i < top; ++i) {
712 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
713 * since the trampolines can clobber r12.
715 if (!(cfg->compile_aot && i == 29))
716 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
719 return regs;
723 * mono_arch_regalloc_cost:
725 * Return the cost, in number of memory references, of the action of
726 * allocating the variable VMV into a register during global register
727 * allocation.
729 guint32
730 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
732 /* FIXME: */
733 return 2;
736 void
737 mono_arch_flush_icache (guint8 *code, gint size)
739 #ifdef MONO_CROSS_COMPILE
740 /* do nothing */
741 #else
742 register guint8 *p;
743 guint8 *endp, *start;
745 p = start = code;
746 endp = p + size;
747 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
748 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
749 #if defined(G_COMPILER_CODEWARRIOR)
750 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
751 for (p = start; p < endp; p += cachelineinc) {
752 asm { dcbf 0, p };
754 } else {
755 for (p = start; p < endp; p += cachelineinc) {
756 asm { dcbst 0, p };
759 asm { sync };
760 p = code;
761 for (p = start; p < endp; p += cachelineinc) {
762 asm {
763 icbi 0, p
764 sync
767 asm {
768 sync
769 isync
771 #else
772 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
773 * The sync is required to insure that the store queue is completely empty.
774 * While the icbi performs no cache operations, icbi/isync is required to
775 * kill local prefetch.
777 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
778 asm ("sync");
779 asm ("icbi 0,%0;" : : "r"(code) : "memory");
780 asm ("isync");
781 return;
783 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
784 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
785 for (p = start; p < endp; p += cachelineinc) {
786 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
788 } else {
789 for (p = start; p < endp; p += cachelineinc) {
790 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
793 asm ("sync");
794 p = code;
795 for (p = start; p < endp; p += cachelineinc) {
796 /* for ISA2.0+ implementations we should not need any extra sync between the
797 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
798 * So I am not sure which chip had this problem but its not an issue on
799 * of the ISA V2 chips.
801 if (cpu_hw_caps & PPC_ISA_2X)
802 asm ("icbi 0,%0;" : : "r"(p) : "memory");
803 else
804 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
806 if (!(cpu_hw_caps & PPC_ISA_2X))
807 asm ("sync");
808 asm ("isync");
809 #endif
810 #endif
813 void
814 mono_arch_flush_register_windows (void)
818 #ifdef __APPLE__
819 #define ALWAYS_ON_STACK(s) s
820 #define FP_ALSO_IN_REG(s) s
821 #else
822 #ifdef __mono_ppc64__
823 #define ALWAYS_ON_STACK(s) s
824 #define FP_ALSO_IN_REG(s) s
825 #else
826 #define ALWAYS_ON_STACK(s)
827 #define FP_ALSO_IN_REG(s)
828 #endif
829 #define ALIGN_DOUBLES
830 #endif
832 enum {
833 RegTypeGeneral,
834 RegTypeBase,
835 RegTypeFP,
836 RegTypeStructByVal,
837 RegTypeStructByAddr,
838 RegTypeFPStructByVal, // For the v2 ABI, floats should be passed in FRs instead of GRs. Only valid for ABI v2!
841 typedef struct {
842 gint32 offset;
843 guint32 vtsize; /* in param area */
844 guint8 reg;
845 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal/RegTypeFPStructByVal */
846 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
847 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal/RegTypeFPStructByVal */
848 guint8 bytes : 4; /* size in bytes - only valid for
849 RegTypeStructByVal/RegTypeFPStructByVal if the struct fits
850 in one word, otherwise it's 0*/
851 } ArgInfo;
853 struct CallInfo {
854 int nargs;
855 guint32 stack_usage;
856 guint32 struct_ret;
857 ArgInfo ret;
858 ArgInfo sig_cookie;
859 gboolean vtype_retaddr;
860 int vret_arg_index;
861 ArgInfo args [1];
864 #define DEBUG(a)
867 #if PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS
869 // Test if a structure is completely composed of either float XOR double fields and has fewer than
870 // PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTER members.
871 // If this is true the structure can be returned directly via float registers instead of by a hidden parameter
872 // pointing to where the return value should be stored.
873 // This is as per the ELF ABI v2.
875 static gboolean
876 is_float_struct_returnable_via_regs (MonoType *type, int* member_cnt, int* member_size)
878 int local_member_cnt, local_member_size;
879 if (!member_cnt) {
880 member_cnt = &local_member_cnt;
882 if (!member_size) {
883 member_size = &local_member_size;
886 gboolean is_all_floats = mini_type_is_hfa(type, member_cnt, member_size);
887 return is_all_floats && (*member_cnt <= PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTERS);
889 #else
891 #define is_float_struct_returnable_via_regs(a,b,c) (FALSE)
893 #endif
895 #if PPC_RETURN_SMALL_STRUCTS_IN_REGS
897 // Test if a structure is smaller in size than 2 doublewords (PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS) and is
898 // completely composed of fields all of basic types.
899 // If this is true the structure can be returned directly via registers r3/r4 instead of by a hidden parameter
900 // pointing to where the return value should be stored.
901 // This is as per the ELF ABI v2.
903 static gboolean
904 is_struct_returnable_via_regs (MonoClass *klass, gboolean is_pinvoke)
906 gboolean has_a_field = FALSE;
907 int size = 0;
908 if (klass) {
909 gpointer iter = NULL;
910 MonoClassField *f;
911 if (is_pinvoke)
912 size = mono_type_native_stack_size (m_class_get_byval_arg (klass), 0);
913 else
914 size = mini_type_stack_size (m_class_get_byval_arg (klass), 0);
915 if (size == 0)
916 return TRUE;
917 if (size > PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS)
918 return FALSE;
919 while ((f = mono_class_get_fields_internal (klass, &iter))) {
920 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
921 // TBD: Is there a better way to check for the basic types?
922 if (f->type->byref) {
923 return FALSE;
924 } else if ((f->type->type >= MONO_TYPE_BOOLEAN) && (f->type->type <= MONO_TYPE_R8)) {
925 has_a_field = TRUE;
926 } else if (MONO_TYPE_ISSTRUCT (f->type)) {
927 MonoClass *klass = mono_class_from_mono_type_internal (f->type);
928 if (is_struct_returnable_via_regs(klass, is_pinvoke)) {
929 has_a_field = TRUE;
930 } else {
931 return FALSE;
933 } else {
934 return FALSE;
939 return has_a_field;
941 #else
943 #define is_struct_returnable_via_regs(a,b) (FALSE)
945 #endif
947 static void inline
948 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
950 #ifdef __mono_ppc64__
951 g_assert (simple);
952 #endif
954 if (simple) {
955 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
956 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
957 ainfo->reg = ppc_sp; /* in the caller */
958 ainfo->regtype = RegTypeBase;
959 *stack_size += sizeof (target_mgreg_t);
960 } else {
961 ALWAYS_ON_STACK (*stack_size += sizeof (target_mgreg_t));
962 ainfo->reg = *gr;
964 } else {
965 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
966 #ifdef ALIGN_DOUBLES
967 //*stack_size += (*stack_size % 8);
968 #endif
969 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
970 ainfo->reg = ppc_sp; /* in the caller */
971 ainfo->regtype = RegTypeBase;
972 *stack_size += 8;
973 } else {
974 #ifdef ALIGN_DOUBLES
975 if (!((*gr) & 1))
976 (*gr) ++;
977 #endif
978 ALWAYS_ON_STACK (*stack_size += 8);
979 ainfo->reg = *gr;
981 (*gr) ++;
983 (*gr) ++;
986 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
987 static gboolean
988 has_only_a_r48_field (MonoClass *klass)
990 gpointer iter;
991 MonoClassField *f;
992 gboolean have_field = FALSE;
993 iter = NULL;
994 while ((f = mono_class_get_fields_internal (klass, &iter))) {
995 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
996 if (have_field)
997 return FALSE;
998 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
999 have_field = TRUE;
1000 else
1001 return FALSE;
1004 return have_field;
1006 #endif
1008 static CallInfo*
1009 get_call_info (MonoMethodSignature *sig)
1011 guint i, fr, gr, pstart;
1012 int n = sig->hasthis + sig->param_count;
1013 MonoType *simpletype;
1014 guint32 stack_size = 0;
1015 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1016 gboolean is_pinvoke = sig->pinvoke;
1018 fr = PPC_FIRST_FPARG_REG;
1019 gr = PPC_FIRST_ARG_REG;
1021 if (mini_type_is_vtype (sig->ret)) {
1022 cinfo->vtype_retaddr = TRUE;
1025 pstart = 0;
1026 n = 0;
1028 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1029 * the first argument, allowing 'this' to be always passed in the first arg reg.
1030 * Also do this if the first argument is a reference type, since virtual calls
1031 * are sometimes made using calli without sig->hasthis set, like in the delegate
1032 * invoke wrappers.
1034 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1035 if (sig->hasthis) {
1036 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1037 n ++;
1038 } else {
1039 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1040 pstart = 1;
1041 n ++;
1043 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1044 cinfo->struct_ret = cinfo->ret.reg;
1045 cinfo->vret_arg_index = 1;
1046 } else {
1047 /* this */
1048 if (sig->hasthis) {
1049 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1050 n ++;
1053 if (cinfo->vtype_retaddr) {
1054 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1055 cinfo->struct_ret = cinfo->ret.reg;
1059 DEBUG(printf("params: %d\n", sig->param_count));
1060 for (i = pstart; i < sig->param_count; ++i) {
1061 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1062 /* Prevent implicit arguments and sig_cookie from
1063 being passed in registers */
1064 gr = PPC_LAST_ARG_REG + 1;
1065 /* FIXME: don't we have to set fr, too? */
1066 /* Emit the signature cookie just before the implicit arguments */
1067 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1069 DEBUG(printf("param %d: ", i));
1070 if (sig->params [i]->byref) {
1071 DEBUG(printf("byref\n"));
1072 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1073 n++;
1074 continue;
1076 simpletype = mini_get_underlying_type (sig->params [i]);
1077 switch (simpletype->type) {
1078 case MONO_TYPE_BOOLEAN:
1079 case MONO_TYPE_I1:
1080 case MONO_TYPE_U1:
1081 cinfo->args [n].size = 1;
1082 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1083 n++;
1084 break;
1085 case MONO_TYPE_CHAR:
1086 case MONO_TYPE_I2:
1087 case MONO_TYPE_U2:
1088 cinfo->args [n].size = 2;
1089 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1090 n++;
1091 break;
1092 case MONO_TYPE_I4:
1093 case MONO_TYPE_U4:
1094 cinfo->args [n].size = 4;
1095 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1096 n++;
1097 break;
1098 case MONO_TYPE_I:
1099 case MONO_TYPE_U:
1100 case MONO_TYPE_PTR:
1101 case MONO_TYPE_FNPTR:
1102 case MONO_TYPE_CLASS:
1103 case MONO_TYPE_OBJECT:
1104 case MONO_TYPE_STRING:
1105 case MONO_TYPE_SZARRAY:
1106 case MONO_TYPE_ARRAY:
1107 cinfo->args [n].size = sizeof (target_mgreg_t);
1108 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1109 n++;
1110 break;
1111 case MONO_TYPE_GENERICINST:
1112 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1113 cinfo->args [n].size = sizeof (target_mgreg_t);
1114 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1115 n++;
1116 break;
1118 /* Fall through */
1119 case MONO_TYPE_VALUETYPE:
1120 case MONO_TYPE_TYPEDBYREF: {
1121 gint size;
1122 MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]);
1123 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1124 size = MONO_ABI_SIZEOF (MonoTypedRef);
1125 else if (is_pinvoke)
1126 size = mono_class_native_size (klass, NULL);
1127 else
1128 size = mono_class_value_size (klass, NULL);
1130 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1131 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1132 cinfo->args [n].size = size;
1134 /* It was 7, now it is 8 in LinuxPPC */
1135 if (fr <= PPC_LAST_FPARG_REG) {
1136 cinfo->args [n].regtype = RegTypeFP;
1137 cinfo->args [n].reg = fr;
1138 fr ++;
1139 FP_ALSO_IN_REG (gr ++);
1140 #if !defined(__mono_ppc64__)
1141 if (size == 8)
1142 FP_ALSO_IN_REG (gr ++);
1143 #endif
1144 ALWAYS_ON_STACK (stack_size += size);
1145 } else {
1146 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1147 cinfo->args [n].regtype = RegTypeBase;
1148 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1149 stack_size += 8;
1151 n++;
1152 break;
1154 #endif
1155 DEBUG(printf ("load %d bytes struct\n",
1156 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1158 #if PPC_PASS_STRUCTS_BY_VALUE
1160 int align_size = size;
1161 int nregs = 0;
1162 int rest = PPC_LAST_ARG_REG - gr + 1;
1163 int n_in_regs = 0;
1165 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1166 int mbr_cnt = 0;
1167 int mbr_size = 0;
1168 gboolean is_all_floats = is_float_struct_returnable_via_regs (sig->params [i], &mbr_cnt, &mbr_size);
1170 if (is_all_floats) {
1171 rest = PPC_LAST_FPARG_REG - fr + 1;
1173 // Pass small (<= 8 member) structures entirely made up of either float or double members
1174 // in FR registers. There have to be at least mbr_cnt registers left.
1175 if (is_all_floats &&
1176 (rest >= mbr_cnt)) {
1177 nregs = mbr_cnt;
1178 n_in_regs = MIN (rest, nregs);
1179 cinfo->args [n].regtype = RegTypeFPStructByVal;
1180 cinfo->args [n].vtregs = n_in_regs;
1181 cinfo->args [n].size = mbr_size;
1182 cinfo->args [n].vtsize = nregs - n_in_regs;
1183 cinfo->args [n].reg = fr;
1184 fr += n_in_regs;
1185 if (mbr_size == 4) {
1186 // floats
1187 FP_ALSO_IN_REG (gr += (n_in_regs+1)/2);
1188 } else {
1189 // doubles
1190 FP_ALSO_IN_REG (gr += (n_in_regs));
1192 } else
1193 #endif
1195 align_size += (sizeof (target_mgreg_t) - 1);
1196 align_size &= ~(sizeof (target_mgreg_t) - 1);
1197 nregs = (align_size + sizeof (target_mgreg_t) -1 ) / sizeof (target_mgreg_t);
1198 n_in_regs = MIN (rest, nregs);
1199 if (n_in_regs < 0)
1200 n_in_regs = 0;
1201 #ifdef __APPLE__
1202 /* FIXME: check this */
1203 if (size >= 3 && size % 4 != 0)
1204 n_in_regs = 0;
1205 #endif
1206 cinfo->args [n].regtype = RegTypeStructByVal;
1207 cinfo->args [n].vtregs = n_in_regs;
1208 cinfo->args [n].size = n_in_regs;
1209 cinfo->args [n].vtsize = nregs - n_in_regs;
1210 cinfo->args [n].reg = gr;
1211 gr += n_in_regs;
1214 #ifdef __mono_ppc64__
1215 if (nregs == 1 && is_pinvoke)
1216 cinfo->args [n].bytes = size;
1217 else
1218 #endif
1219 cinfo->args [n].bytes = 0;
1220 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1221 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1222 stack_size += nregs * sizeof (target_mgreg_t);
1224 #else
1225 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1226 cinfo->args [n].regtype = RegTypeStructByAddr;
1227 cinfo->args [n].vtsize = size;
1228 #endif
1229 n++;
1230 break;
1232 case MONO_TYPE_U8:
1233 case MONO_TYPE_I8:
1234 cinfo->args [n].size = 8;
1235 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1236 n++;
1237 break;
1238 case MONO_TYPE_R4:
1239 cinfo->args [n].size = 4;
1241 /* It was 7, now it is 8 in LinuxPPC */
1242 if (fr <= PPC_LAST_FPARG_REG
1243 // For non-native vararg calls the parms must go in storage
1244 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1246 cinfo->args [n].regtype = RegTypeFP;
1247 cinfo->args [n].reg = fr;
1248 fr ++;
1249 FP_ALSO_IN_REG (gr ++);
1250 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1251 } else {
1252 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1253 cinfo->args [n].regtype = RegTypeBase;
1254 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1255 stack_size += SIZEOF_REGISTER;
1257 n++;
1258 break;
1259 case MONO_TYPE_R8:
1260 cinfo->args [n].size = 8;
1261 /* It was 7, now it is 8 in LinuxPPC */
1262 if (fr <= PPC_LAST_FPARG_REG
1263 // For non-native vararg calls the parms must go in storage
1264 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1266 cinfo->args [n].regtype = RegTypeFP;
1267 cinfo->args [n].reg = fr;
1268 fr ++;
1269 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1270 ALWAYS_ON_STACK (stack_size += 8);
1271 } else {
1272 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1273 cinfo->args [n].regtype = RegTypeBase;
1274 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1275 stack_size += 8;
1277 n++;
1278 break;
1279 default:
1280 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1283 cinfo->nargs = n;
1285 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1286 /* Prevent implicit arguments and sig_cookie from
1287 being passed in registers */
1288 gr = PPC_LAST_ARG_REG + 1;
1289 /* Emit the signature cookie just before the implicit arguments */
1290 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1294 simpletype = mini_get_underlying_type (sig->ret);
1295 switch (simpletype->type) {
1296 case MONO_TYPE_BOOLEAN:
1297 case MONO_TYPE_I1:
1298 case MONO_TYPE_U1:
1299 case MONO_TYPE_I2:
1300 case MONO_TYPE_U2:
1301 case MONO_TYPE_CHAR:
1302 case MONO_TYPE_I4:
1303 case MONO_TYPE_U4:
1304 case MONO_TYPE_I:
1305 case MONO_TYPE_U:
1306 case MONO_TYPE_PTR:
1307 case MONO_TYPE_FNPTR:
1308 case MONO_TYPE_CLASS:
1309 case MONO_TYPE_OBJECT:
1310 case MONO_TYPE_SZARRAY:
1311 case MONO_TYPE_ARRAY:
1312 case MONO_TYPE_STRING:
1313 cinfo->ret.reg = ppc_r3;
1314 break;
1315 case MONO_TYPE_U8:
1316 case MONO_TYPE_I8:
1317 cinfo->ret.reg = ppc_r3;
1318 break;
1319 case MONO_TYPE_R4:
1320 case MONO_TYPE_R8:
1321 cinfo->ret.reg = ppc_f1;
1322 cinfo->ret.regtype = RegTypeFP;
1323 break;
1324 case MONO_TYPE_GENERICINST:
1325 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1326 cinfo->ret.reg = ppc_r3;
1327 break;
1329 break;
1330 case MONO_TYPE_VALUETYPE:
1331 break;
1332 case MONO_TYPE_TYPEDBYREF:
1333 case MONO_TYPE_VOID:
1334 break;
1335 default:
1336 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1340 /* align stack size to 16 */
1341 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1342 stack_size = (stack_size + 15) & ~15;
1344 cinfo->stack_usage = stack_size;
1345 return cinfo;
1348 #ifndef DISABLE_JIT
1350 gboolean
1351 mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_)
1353 CallInfo *caller_info = get_call_info (caller_sig);
1354 CallInfo *callee_info = get_call_info (callee_sig);
1356 gboolean res = IS_SUPPORTED_TAILCALL (callee_info->stack_usage <= caller_info->stack_usage)
1357 && IS_SUPPORTED_TAILCALL (memcmp (&callee_info->ret, &caller_info->ret, sizeof (caller_info->ret)) == 0);
1359 // FIXME ABIs vary as to if this local is in the parameter area or not,
1360 // so this check might not be needed.
1361 for (int i = 0; res && i < callee_info->nargs; ++i) {
1362 res = IS_SUPPORTED_TAILCALL (callee_info->args [i].regtype != RegTypeStructByAddr);
1363 /* An address on the callee's stack is passed as the argument */
1366 g_free (caller_info);
1367 g_free (callee_info);
1369 return res;
1372 #endif
1375 * Set var information according to the calling convention. ppc version.
1376 * The locals var stuff should most likely be split in another method.
1378 void
1379 mono_arch_allocate_vars (MonoCompile *m)
1381 MonoMethodSignature *sig;
1382 MonoMethodHeader *header;
1383 MonoInst *inst;
1384 int i, offset, size, align, curinst;
1385 int frame_reg = ppc_sp;
1386 gint32 *offsets;
1387 guint32 locals_stack_size, locals_stack_align;
1389 m->flags |= MONO_CFG_HAS_SPILLUP;
1391 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1392 * call convs needs to be handled this way.
1394 if (m->flags & MONO_CFG_HAS_VARARGS)
1395 m->param_area = MAX (m->param_area, sizeof (target_mgreg_t)*8);
1396 /* gtk-sharp and other broken code will dllimport vararg functions even with
1397 * non-varargs signatures. Since there is little hope people will get this right
1398 * we assume they won't.
1400 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1401 m->param_area = MAX (m->param_area, sizeof (target_mgreg_t)*8);
1403 header = m->header;
1406 * We use the frame register also for any method that has
1407 * exception clauses. This way, when the handlers are called,
1408 * the code will reference local variables using the frame reg instead of
1409 * the stack pointer: if we had to restore the stack pointer, we'd
1410 * corrupt the method frames that are already on the stack (since
1411 * filters get called before stack unwinding happens) when the filter
1412 * code would call any method (this also applies to finally etc.).
1414 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1415 frame_reg = ppc_r31;
1416 m->frame_reg = frame_reg;
1417 if (frame_reg != ppc_sp) {
1418 m->used_int_regs |= 1 << frame_reg;
1421 sig = mono_method_signature_internal (m->method);
1423 offset = 0;
1424 curinst = 0;
1425 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1426 m->ret->opcode = OP_REGVAR;
1427 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1428 } else {
1429 /* FIXME: handle long values? */
1430 switch (mini_get_underlying_type (sig->ret)->type) {
1431 case MONO_TYPE_VOID:
1432 break;
1433 case MONO_TYPE_R4:
1434 case MONO_TYPE_R8:
1435 m->ret->opcode = OP_REGVAR;
1436 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1437 break;
1438 default:
1439 m->ret->opcode = OP_REGVAR;
1440 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1441 break;
1444 /* local vars are at a positive offset from the stack pointer */
1446 * also note that if the function uses alloca, we use ppc_r31
1447 * to point at the local variables.
1449 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1450 /* align the offset to 16 bytes: not sure this is needed here */
1451 //offset += 16 - 1;
1452 //offset &= ~(16 - 1);
1454 /* add parameter area size for called functions */
1455 offset += m->param_area;
1456 offset += 16 - 1;
1457 offset &= ~(16 - 1);
1459 /* the MonoLMF structure is stored just below the stack pointer */
1460 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1461 offset += sizeof(gpointer) - 1;
1462 offset &= ~(sizeof(gpointer) - 1);
1464 m->vret_addr->opcode = OP_REGOFFSET;
1465 m->vret_addr->inst_basereg = frame_reg;
1466 m->vret_addr->inst_offset = offset;
1468 if (G_UNLIKELY (m->verbose_level > 1)) {
1469 printf ("vret_addr =");
1470 mono_print_ins (m->vret_addr);
1473 offset += sizeof(gpointer);
1476 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1477 if (locals_stack_align) {
1478 offset += (locals_stack_align - 1);
1479 offset &= ~(locals_stack_align - 1);
1481 for (i = m->locals_start; i < m->num_varinfo; i++) {
1482 if (offsets [i] != -1) {
1483 MonoInst *inst = m->varinfo [i];
1484 inst->opcode = OP_REGOFFSET;
1485 inst->inst_basereg = frame_reg;
1486 inst->inst_offset = offset + offsets [i];
1488 g_print ("allocating local %d (%s) to %d\n",
1489 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1493 offset += locals_stack_size;
1495 curinst = 0;
1496 if (sig->hasthis) {
1497 inst = m->args [curinst];
1498 if (inst->opcode != OP_REGVAR) {
1499 inst->opcode = OP_REGOFFSET;
1500 inst->inst_basereg = frame_reg;
1501 offset += sizeof (target_mgreg_t) - 1;
1502 offset &= ~(sizeof (target_mgreg_t) - 1);
1503 inst->inst_offset = offset;
1504 offset += sizeof (target_mgreg_t);
1506 curinst++;
1509 for (i = 0; i < sig->param_count; ++i) {
1510 inst = m->args [curinst];
1511 if (inst->opcode != OP_REGVAR) {
1512 inst->opcode = OP_REGOFFSET;
1513 inst->inst_basereg = frame_reg;
1514 if (sig->pinvoke) {
1515 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1516 inst->backend.is_pinvoke = 1;
1517 } else {
1518 size = mono_type_size (sig->params [i], &align);
1520 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (target_mgreg_t))
1521 size = align = sizeof (target_mgreg_t);
1523 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1524 * they are saved using std in the prolog.
1526 align = sizeof (target_mgreg_t);
1527 offset += align - 1;
1528 offset &= ~(align - 1);
1529 inst->inst_offset = offset;
1530 offset += size;
1532 curinst++;
1535 /* some storage for fp conversions */
1536 offset += 8 - 1;
1537 offset &= ~(8 - 1);
1538 m->arch.fp_conv_var_offset = offset;
1539 offset += 8;
1541 /* align the offset to 16 bytes */
1542 offset += 16 - 1;
1543 offset &= ~(16 - 1);
1545 /* change sign? */
1546 m->stack_offset = offset;
1548 if (sig->call_convention == MONO_CALL_VARARG) {
1549 CallInfo *cinfo = get_call_info (m->method->signature);
1551 m->sig_cookie = cinfo->sig_cookie.offset;
1553 g_free(cinfo);
1557 void
1558 mono_arch_create_vars (MonoCompile *cfg)
1560 MonoMethodSignature *sig = mono_method_signature_internal (cfg->method);
1562 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1563 cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG);
1567 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1568 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1571 static void
1572 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1574 int sig_reg = mono_alloc_ireg (cfg);
1576 /* FIXME: Add support for signature tokens to AOT */
1577 cfg->disable_aot = TRUE;
1579 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1580 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1581 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1584 void
1585 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1587 MonoInst *in, *ins;
1588 MonoMethodSignature *sig;
1589 int i, n;
1590 CallInfo *cinfo;
1592 sig = call->signature;
1593 n = sig->param_count + sig->hasthis;
1595 cinfo = get_call_info (sig);
1597 for (i = 0; i < n; ++i) {
1598 ArgInfo *ainfo = cinfo->args + i;
1599 MonoType *t;
1601 if (i >= sig->hasthis)
1602 t = sig->params [i - sig->hasthis];
1603 else
1604 t = mono_get_int_type ();
1605 t = mini_get_underlying_type (t);
1607 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1608 emit_sig_cookie (cfg, call, cinfo);
1610 in = call->args [i];
1612 if (ainfo->regtype == RegTypeGeneral) {
1613 #ifndef __mono_ppc64__
1614 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1615 MONO_INST_NEW (cfg, ins, OP_MOVE);
1616 ins->dreg = mono_alloc_ireg (cfg);
1617 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1618 MONO_ADD_INS (cfg->cbb, ins);
1619 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1621 MONO_INST_NEW (cfg, ins, OP_MOVE);
1622 ins->dreg = mono_alloc_ireg (cfg);
1623 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1624 MONO_ADD_INS (cfg->cbb, ins);
1625 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1626 } else
1627 #endif
1629 MONO_INST_NEW (cfg, ins, OP_MOVE);
1630 ins->dreg = mono_alloc_ireg (cfg);
1631 ins->sreg1 = in->dreg;
1632 MONO_ADD_INS (cfg->cbb, ins);
1634 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1636 } else if (ainfo->regtype == RegTypeStructByAddr) {
1637 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1638 ins->opcode = OP_OUTARG_VT;
1639 ins->sreg1 = in->dreg;
1640 ins->klass = in->klass;
1641 ins->inst_p0 = call;
1642 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1643 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1644 MONO_ADD_INS (cfg->cbb, ins);
1645 } else if (ainfo->regtype == RegTypeStructByVal) {
1646 /* this is further handled in mono_arch_emit_outarg_vt () */
1647 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1648 ins->opcode = OP_OUTARG_VT;
1649 ins->sreg1 = in->dreg;
1650 ins->klass = in->klass;
1651 ins->inst_p0 = call;
1652 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1653 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1654 MONO_ADD_INS (cfg->cbb, ins);
1655 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1656 /* this is further handled in mono_arch_emit_outarg_vt () */
1657 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1658 ins->opcode = OP_OUTARG_VT;
1659 ins->sreg1 = in->dreg;
1660 ins->klass = in->klass;
1661 ins->inst_p0 = call;
1662 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1663 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1664 MONO_ADD_INS (cfg->cbb, ins);
1665 cfg->flags |= MONO_CFG_HAS_FPOUT;
1666 } else if (ainfo->regtype == RegTypeBase) {
1667 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1668 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1669 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1670 if (t->type == MONO_TYPE_R8)
1671 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1672 else
1673 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1674 } else {
1675 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1677 } else if (ainfo->regtype == RegTypeFP) {
1678 if (t->type == MONO_TYPE_VALUETYPE) {
1679 /* this is further handled in mono_arch_emit_outarg_vt () */
1680 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1681 ins->opcode = OP_OUTARG_VT;
1682 ins->sreg1 = in->dreg;
1683 ins->klass = in->klass;
1684 ins->inst_p0 = call;
1685 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1686 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1687 MONO_ADD_INS (cfg->cbb, ins);
1689 cfg->flags |= MONO_CFG_HAS_FPOUT;
1690 } else {
1691 int dreg = mono_alloc_freg (cfg);
1693 if (ainfo->size == 4) {
1694 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1695 } else {
1696 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1697 ins->dreg = dreg;
1698 ins->sreg1 = in->dreg;
1699 MONO_ADD_INS (cfg->cbb, ins);
1702 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1703 cfg->flags |= MONO_CFG_HAS_FPOUT;
1705 } else {
1706 g_assert_not_reached ();
1710 /* Emit the signature cookie in the case that there is no
1711 additional argument */
1712 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1713 emit_sig_cookie (cfg, call, cinfo);
1715 if (cinfo->struct_ret) {
1716 MonoInst *vtarg;
1718 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1719 vtarg->sreg1 = call->vret_var->dreg;
1720 vtarg->dreg = mono_alloc_preg (cfg);
1721 MONO_ADD_INS (cfg->cbb, vtarg);
1723 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1726 call->stack_usage = cinfo->stack_usage;
1727 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1728 cfg->flags |= MONO_CFG_HAS_CALLS;
1730 g_free (cinfo);
1733 #ifndef DISABLE_JIT
1735 void
1736 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1738 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1739 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1740 int ovf_size = ainfo->vtsize;
1741 int doffset = ainfo->offset;
1742 int i, soffset, dreg;
1744 if (ainfo->regtype == RegTypeStructByVal) {
1745 #ifdef __APPLE__
1746 guint32 size = 0;
1747 #endif
1748 soffset = 0;
1749 #ifdef __APPLE__
1751 * Darwin pinvokes needs some special handling for 1
1752 * and 2 byte arguments
1754 g_assert (ins->klass);
1755 if (call->signature->pinvoke)
1756 size = mono_class_native_size (ins->klass, NULL);
1757 if (size == 2 || size == 1) {
1758 int tmpr = mono_alloc_ireg (cfg);
1759 if (size == 1)
1760 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1761 else
1762 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1763 dreg = mono_alloc_ireg (cfg);
1764 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1765 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1766 } else
1767 #endif
1768 for (i = 0; i < ainfo->vtregs; ++i) {
1769 dreg = mono_alloc_ireg (cfg);
1770 #if G_BYTE_ORDER == G_BIG_ENDIAN
1771 int antipadding = 0;
1772 if (ainfo->bytes) {
1773 g_assert (i == 0);
1774 antipadding = sizeof (target_mgreg_t) - ainfo->bytes;
1776 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1777 if (antipadding)
1778 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1779 #else
1780 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1781 #endif
1782 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1783 soffset += sizeof (target_mgreg_t);
1785 if (ovf_size != 0)
1786 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (target_mgreg_t), TARGET_SIZEOF_VOID_P);
1787 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1788 soffset = 0;
1789 for (i = 0; i < ainfo->vtregs; ++i) {
1790 int tmpr = mono_alloc_freg (cfg);
1791 if (ainfo->size == 4)
1792 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, soffset);
1793 else // ==8
1794 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, soffset);
1795 dreg = mono_alloc_freg (cfg);
1796 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1797 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg+i, TRUE);
1798 soffset += ainfo->size;
1800 if (ovf_size != 0)
1801 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (target_mgreg_t), TARGET_SIZEOF_VOID_P);
1802 } else if (ainfo->regtype == RegTypeFP) {
1803 int tmpr = mono_alloc_freg (cfg);
1804 if (ainfo->size == 4)
1805 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1806 else
1807 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1808 dreg = mono_alloc_freg (cfg);
1809 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1810 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1811 } else {
1812 MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL);
1813 MonoInst *load;
1814 guint32 size;
1816 /* FIXME: alignment? */
1817 if (call->signature->pinvoke) {
1818 size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL);
1819 vtcopy->backend.is_pinvoke = 1;
1820 } else {
1821 size = mini_type_stack_size (m_class_get_byval_arg (src->klass), NULL);
1823 if (size > 0)
1824 g_assert (ovf_size > 0);
1826 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1827 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, TARGET_SIZEOF_VOID_P);
1829 if (ainfo->offset)
1830 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1831 else
1832 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1836 void
1837 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1839 MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret);
1840 if (!ret->byref) {
1841 #ifndef __mono_ppc64__
1842 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1843 MonoInst *ins;
1845 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1846 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1847 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1848 MONO_ADD_INS (cfg->cbb, ins);
1849 return;
1851 #endif
1852 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1853 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1854 return;
1857 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1860 gboolean
1861 mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm)
1863 return TRUE;
1866 #endif /* DISABLE_JIT */
1869 * Conditional branches have a small offset, so if it is likely overflowed,
1870 * we do a branch to the end of the method (uncond branches have much larger
1871 * offsets) where we perform the conditional and jump back unconditionally.
1872 * It's slightly slower, since we add two uncond branches, but it's very simple
1873 * with the current patch implementation and such large methods are likely not
1874 * going to be perf critical anyway.
1876 typedef struct {
1877 union {
1878 MonoBasicBlock *bb;
1879 const char *exception;
1880 } data;
1881 guint32 ip_offset;
1882 guint16 b0_cond;
1883 guint16 b1_cond;
1884 } MonoOvfJump;
1886 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1887 if (0 && ins->inst_true_bb->native_offset) { \
1888 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1889 } else { \
1890 int br_disp = ins->inst_true_bb->max_offset - offset; \
1891 if (!ppc_is_imm16 (br_disp + 8 * 1024) || !ppc_is_imm16 (br_disp - 8 * 1024)) { \
1892 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1893 ovfj->data.bb = ins->inst_true_bb; \
1894 ovfj->ip_offset = 0; \
1895 ovfj->b0_cond = (b0); \
1896 ovfj->b1_cond = (b1); \
1897 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1898 ppc_b (code, 0); \
1899 } else { \
1900 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1901 ppc_bc (code, (b0), (b1), 0); \
1905 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1907 /* emit an exception if condition is fail
1909 * We assign the extra code used to throw the implicit exceptions
1910 * to cfg->bb_exit as far as the big branch handling is concerned
1912 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1913 do { \
1914 int br_disp = cfg->bb_exit->max_offset - offset; \
1915 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1916 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1917 ovfj->data.exception = (exc_name); \
1918 ovfj->ip_offset = code - cfg->native_code; \
1919 ovfj->b0_cond = (b0); \
1920 ovfj->b1_cond = (b1); \
1921 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1922 ppc_bl (code, 0); \
1923 cfg->bb_exit->max_offset += 24; \
1924 } else { \
1925 mono_add_patch_info (cfg, code - cfg->native_code, \
1926 MONO_PATCH_INFO_EXC, exc_name); \
1927 ppc_bcl (code, (b0), (b1), 0); \
1929 } while (0);
1931 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1933 void
1934 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1938 static int
1939 normalize_opcode (int opcode)
1941 switch (opcode) {
1942 #ifndef MONO_ARCH_ILP32
1943 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1944 return OP_LOAD_MEMBASE;
1945 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1946 return OP_LOAD_MEMINDEX;
1947 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1948 return OP_STORE_MEMBASE_REG;
1949 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1950 return OP_STORE_MEMBASE_IMM;
1951 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1952 return OP_STORE_MEMINDEX;
1953 #endif
1954 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
1955 return OP_SHR_IMM;
1956 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
1957 return OP_SHR_UN_IMM;
1958 default:
1959 return opcode;
1963 void
1964 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1966 MonoInst *ins, *n, *last_ins = NULL;
1968 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1969 switch (normalize_opcode (ins->opcode)) {
1970 case OP_MUL_IMM:
1971 /* remove unnecessary multiplication with 1 */
1972 if (ins->inst_imm == 1) {
1973 if (ins->dreg != ins->sreg1) {
1974 ins->opcode = OP_MOVE;
1975 } else {
1976 MONO_DELETE_INS (bb, ins);
1977 continue;
1979 } else {
1980 int power2 = mono_is_power_of_two (ins->inst_imm);
1981 if (power2 > 0) {
1982 ins->opcode = OP_SHL_IMM;
1983 ins->inst_imm = power2;
1986 break;
1987 case OP_LOAD_MEMBASE:
1989 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1990 * OP_LOAD_MEMBASE offset(basereg), reg
1992 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
1993 ins->inst_basereg == last_ins->inst_destbasereg &&
1994 ins->inst_offset == last_ins->inst_offset) {
1995 if (ins->dreg == last_ins->sreg1) {
1996 MONO_DELETE_INS (bb, ins);
1997 continue;
1998 } else {
1999 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2000 ins->opcode = OP_MOVE;
2001 ins->sreg1 = last_ins->sreg1;
2005 * Note: reg1 must be different from the basereg in the second load
2006 * OP_LOAD_MEMBASE offset(basereg), reg1
2007 * OP_LOAD_MEMBASE offset(basereg), reg2
2008 * -->
2009 * OP_LOAD_MEMBASE offset(basereg), reg1
2010 * OP_MOVE reg1, reg2
2012 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2013 ins->inst_basereg != last_ins->dreg &&
2014 ins->inst_basereg == last_ins->inst_basereg &&
2015 ins->inst_offset == last_ins->inst_offset) {
2017 if (ins->dreg == last_ins->dreg) {
2018 MONO_DELETE_INS (bb, ins);
2019 continue;
2020 } else {
2021 ins->opcode = OP_MOVE;
2022 ins->sreg1 = last_ins->dreg;
2025 //g_assert_not_reached ();
2027 #if 0
2029 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2030 * OP_LOAD_MEMBASE offset(basereg), reg
2031 * -->
2032 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2033 * OP_ICONST reg, imm
2035 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2036 ins->inst_basereg == last_ins->inst_destbasereg &&
2037 ins->inst_offset == last_ins->inst_offset) {
2038 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2039 ins->opcode = OP_ICONST;
2040 ins->inst_c0 = last_ins->inst_imm;
2041 g_assert_not_reached (); // check this rule
2042 #endif
2044 break;
2045 case OP_LOADU1_MEMBASE:
2046 case OP_LOADI1_MEMBASE:
2047 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2048 ins->inst_basereg == last_ins->inst_destbasereg &&
2049 ins->inst_offset == last_ins->inst_offset) {
2050 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2051 ins->sreg1 = last_ins->sreg1;
2053 break;
2054 case OP_LOADU2_MEMBASE:
2055 case OP_LOADI2_MEMBASE:
2056 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2057 ins->inst_basereg == last_ins->inst_destbasereg &&
2058 ins->inst_offset == last_ins->inst_offset) {
2059 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2060 ins->sreg1 = last_ins->sreg1;
2062 break;
2063 #ifdef __mono_ppc64__
2064 case OP_LOADU4_MEMBASE:
2065 case OP_LOADI4_MEMBASE:
2066 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2067 ins->inst_basereg == last_ins->inst_destbasereg &&
2068 ins->inst_offset == last_ins->inst_offset) {
2069 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2070 ins->sreg1 = last_ins->sreg1;
2072 break;
2073 #endif
2074 case OP_MOVE:
2075 ins->opcode = OP_MOVE;
2077 * OP_MOVE reg, reg
2079 if (ins->dreg == ins->sreg1) {
2080 MONO_DELETE_INS (bb, ins);
2081 continue;
2084 * OP_MOVE sreg, dreg
2085 * OP_MOVE dreg, sreg
2087 if (last_ins && last_ins->opcode == OP_MOVE &&
2088 ins->sreg1 == last_ins->dreg &&
2089 ins->dreg == last_ins->sreg1) {
2090 MONO_DELETE_INS (bb, ins);
2091 continue;
2093 break;
2095 last_ins = ins;
2096 ins = ins->next;
2098 bb->last_ins = last_ins;
2101 void
2102 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2104 switch (ins->opcode) {
2105 case OP_ICONV_TO_R_UN: {
2106 // This value is OK as-is for both big and little endian because of how it is stored
2107 static const guint64 adjust_val = 0x4330000000000000ULL;
2108 int msw_reg = mono_alloc_ireg (cfg);
2109 int adj_reg = mono_alloc_freg (cfg);
2110 int tmp_reg = mono_alloc_freg (cfg);
2111 int basereg = ppc_sp;
2112 int offset = -8;
2113 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2114 if (!ppc_is_imm16 (offset + 4)) {
2115 basereg = mono_alloc_ireg (cfg);
2116 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2118 #if G_BYTE_ORDER == G_BIG_ENDIAN
2119 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2120 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2121 #else
2122 // For little endian the words are reversed
2123 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2124 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2125 #endif
2126 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2127 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2128 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2129 ins->opcode = OP_NOP;
2130 break;
2132 #ifndef __mono_ppc64__
2133 case OP_ICONV_TO_R4:
2134 case OP_ICONV_TO_R8: {
2135 /* If we have a PPC_FEATURE_64 machine we can avoid
2136 this and use the fcfid instruction. Otherwise
2137 on an old 32-bit chip and we have to do this the
2138 hard way. */
2139 if (!(cpu_hw_caps & PPC_ISA_64)) {
2140 /* FIXME: change precision for CEE_CONV_R4 */
2141 static const guint64 adjust_val = 0x4330000080000000ULL;
2142 int msw_reg = mono_alloc_ireg (cfg);
2143 int xored = mono_alloc_ireg (cfg);
2144 int adj_reg = mono_alloc_freg (cfg);
2145 int tmp_reg = mono_alloc_freg (cfg);
2146 int basereg = ppc_sp;
2147 int offset = -8;
2148 if (!ppc_is_imm16 (offset + 4)) {
2149 basereg = mono_alloc_ireg (cfg);
2150 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2152 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2153 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2154 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2155 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2156 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2157 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2158 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2159 if (ins->opcode == OP_ICONV_TO_R4)
2160 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2161 ins->opcode = OP_NOP;
2163 break;
2165 #endif
2166 case OP_CKFINITE: {
2167 int msw_reg = mono_alloc_ireg (cfg);
2168 int basereg = ppc_sp;
2169 int offset = -8;
2170 if (!ppc_is_imm16 (offset + 4)) {
2171 basereg = mono_alloc_ireg (cfg);
2172 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2174 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2175 #if G_BYTE_ORDER == G_BIG_ENDIAN
2176 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2177 #else
2178 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2179 #endif
2180 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_CHECK_FINITE, -1, msw_reg);
2181 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2182 ins->opcode = OP_NOP;
2183 break;
2185 #ifdef __mono_ppc64__
2186 case OP_IADD_OVF:
2187 case OP_IADD_OVF_UN:
2188 case OP_ISUB_OVF: {
2189 int shifted1_reg = mono_alloc_ireg (cfg);
2190 int shifted2_reg = mono_alloc_ireg (cfg);
2191 int result_shifted_reg = mono_alloc_ireg (cfg);
2193 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2194 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2195 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2196 if (ins->opcode == OP_IADD_OVF_UN)
2197 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2198 else
2199 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2200 ins->opcode = OP_NOP;
2201 break;
2203 #endif
2204 default:
2205 break;
2209 void
2210 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2212 switch (ins->opcode) {
2213 case OP_LADD_OVF:
2214 /* ADC sets the condition code */
2215 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2216 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2217 NULLIFY_INS (ins);
2218 break;
2219 case OP_LADD_OVF_UN:
2220 /* ADC sets the condition code */
2221 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2222 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));
2223 NULLIFY_INS (ins);
2224 break;
2225 case OP_LSUB_OVF:
2226 /* SBB sets the condition code */
2227 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2228 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2229 NULLIFY_INS (ins);
2230 break;
2231 case OP_LSUB_OVF_UN:
2232 /* SBB sets the condition code */
2233 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2234 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));
2235 NULLIFY_INS (ins);
2236 break;
2237 case OP_LNEG:
2238 /* From gcc generated code */
2239 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), 0);
2240 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1));
2241 NULLIFY_INS (ins);
2242 break;
2243 default:
2244 break;
2249 * the branch_b0_table should maintain the order of these
2250 * opcodes.
2251 case CEE_BEQ:
2252 case CEE_BGE:
2253 case CEE_BGT:
2254 case CEE_BLE:
2255 case CEE_BLT:
2256 case CEE_BNE_UN:
2257 case CEE_BGE_UN:
2258 case CEE_BGT_UN:
2259 case CEE_BLE_UN:
2260 case CEE_BLT_UN:
2262 static const guchar
2263 branch_b0_table [] = {
2264 PPC_BR_TRUE,
2265 PPC_BR_FALSE,
2266 PPC_BR_TRUE,
2267 PPC_BR_FALSE,
2268 PPC_BR_TRUE,
2270 PPC_BR_FALSE,
2271 PPC_BR_FALSE,
2272 PPC_BR_TRUE,
2273 PPC_BR_FALSE,
2274 PPC_BR_TRUE
2277 static const guchar
2278 branch_b1_table [] = {
2279 PPC_BR_EQ,
2280 PPC_BR_LT,
2281 PPC_BR_GT,
2282 PPC_BR_GT,
2283 PPC_BR_LT,
2285 PPC_BR_EQ,
2286 PPC_BR_LT,
2287 PPC_BR_GT,
2288 PPC_BR_GT,
2289 PPC_BR_LT
2292 #define NEW_INS(cfg,dest,op) do { \
2293 MONO_INST_NEW((cfg), (dest), (op)); \
2294 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2295 } while (0)
2297 static int
2298 map_to_reg_reg_op (int op)
2300 switch (op) {
2301 case OP_ADD_IMM:
2302 return OP_IADD;
2303 case OP_SUB_IMM:
2304 return OP_ISUB;
2305 case OP_AND_IMM:
2306 return OP_IAND;
2307 case OP_COMPARE_IMM:
2308 return OP_COMPARE;
2309 case OP_ICOMPARE_IMM:
2310 return OP_ICOMPARE;
2311 case OP_LCOMPARE_IMM:
2312 return OP_LCOMPARE;
2313 case OP_ADDCC_IMM:
2314 return OP_IADDCC;
2315 case OP_ADC_IMM:
2316 return OP_IADC;
2317 case OP_SUBCC_IMM:
2318 return OP_ISUBCC;
2319 case OP_SBB_IMM:
2320 return OP_ISBB;
2321 case OP_OR_IMM:
2322 return OP_IOR;
2323 case OP_XOR_IMM:
2324 return OP_IXOR;
2325 case OP_MUL_IMM:
2326 return OP_IMUL;
2327 case OP_LMUL_IMM:
2328 return OP_LMUL;
2329 case OP_LOAD_MEMBASE:
2330 return OP_LOAD_MEMINDEX;
2331 case OP_LOADI4_MEMBASE:
2332 return OP_LOADI4_MEMINDEX;
2333 case OP_LOADU4_MEMBASE:
2334 return OP_LOADU4_MEMINDEX;
2335 case OP_LOADI8_MEMBASE:
2336 return OP_LOADI8_MEMINDEX;
2337 case OP_LOADU1_MEMBASE:
2338 return OP_LOADU1_MEMINDEX;
2339 case OP_LOADI2_MEMBASE:
2340 return OP_LOADI2_MEMINDEX;
2341 case OP_LOADU2_MEMBASE:
2342 return OP_LOADU2_MEMINDEX;
2343 case OP_LOADI1_MEMBASE:
2344 return OP_LOADI1_MEMINDEX;
2345 case OP_LOADR4_MEMBASE:
2346 return OP_LOADR4_MEMINDEX;
2347 case OP_LOADR8_MEMBASE:
2348 return OP_LOADR8_MEMINDEX;
2349 case OP_STOREI1_MEMBASE_REG:
2350 return OP_STOREI1_MEMINDEX;
2351 case OP_STOREI2_MEMBASE_REG:
2352 return OP_STOREI2_MEMINDEX;
2353 case OP_STOREI4_MEMBASE_REG:
2354 return OP_STOREI4_MEMINDEX;
2355 case OP_STOREI8_MEMBASE_REG:
2356 return OP_STOREI8_MEMINDEX;
2357 case OP_STORE_MEMBASE_REG:
2358 return OP_STORE_MEMINDEX;
2359 case OP_STORER4_MEMBASE_REG:
2360 return OP_STORER4_MEMINDEX;
2361 case OP_STORER8_MEMBASE_REG:
2362 return OP_STORER8_MEMINDEX;
2363 case OP_STORE_MEMBASE_IMM:
2364 return OP_STORE_MEMBASE_REG;
2365 case OP_STOREI1_MEMBASE_IMM:
2366 return OP_STOREI1_MEMBASE_REG;
2367 case OP_STOREI2_MEMBASE_IMM:
2368 return OP_STOREI2_MEMBASE_REG;
2369 case OP_STOREI4_MEMBASE_IMM:
2370 return OP_STOREI4_MEMBASE_REG;
2371 case OP_STOREI8_MEMBASE_IMM:
2372 return OP_STOREI8_MEMBASE_REG;
2374 if (mono_op_imm_to_op (op) == -1)
2375 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2376 return mono_op_imm_to_op (op);
2379 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2381 #define compare_opcode_is_unsigned(opcode) \
2382 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2383 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2384 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2385 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2386 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2387 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2388 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2389 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2392 * Remove from the instruction list the instructions that can't be
2393 * represented with very simple instructions with no register
2394 * requirements.
2396 void
2397 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2399 MonoInst *ins, *next, *temp, *last_ins = NULL;
2400 int imm;
2402 MONO_BB_FOR_EACH_INS (bb, ins) {
2403 loop_start:
2404 switch (ins->opcode) {
2405 case OP_IDIV_UN_IMM:
2406 case OP_IDIV_IMM:
2407 case OP_IREM_IMM:
2408 case OP_IREM_UN_IMM:
2409 CASE_PPC64 (OP_LREM_IMM) {
2410 NEW_INS (cfg, temp, OP_ICONST);
2411 temp->inst_c0 = ins->inst_imm;
2412 temp->dreg = mono_alloc_ireg (cfg);
2413 ins->sreg2 = temp->dreg;
2414 if (ins->opcode == OP_IDIV_IMM)
2415 ins->opcode = OP_IDIV;
2416 else if (ins->opcode == OP_IREM_IMM)
2417 ins->opcode = OP_IREM;
2418 else if (ins->opcode == OP_IDIV_UN_IMM)
2419 ins->opcode = OP_IDIV_UN;
2420 else if (ins->opcode == OP_IREM_UN_IMM)
2421 ins->opcode = OP_IREM_UN;
2422 else if (ins->opcode == OP_LREM_IMM)
2423 ins->opcode = OP_LREM;
2424 last_ins = temp;
2425 /* handle rem separately */
2426 goto loop_start;
2428 case OP_IREM:
2429 case OP_IREM_UN:
2430 CASE_PPC64 (OP_LREM)
2431 CASE_PPC64 (OP_LREM_UN) {
2432 MonoInst *mul;
2433 /* we change a rem dest, src1, src2 to
2434 * div temp1, src1, src2
2435 * mul temp2, temp1, src2
2436 * sub dest, src1, temp2
2438 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2439 NEW_INS (cfg, mul, OP_IMUL);
2440 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2441 ins->opcode = OP_ISUB;
2442 } else {
2443 NEW_INS (cfg, mul, OP_LMUL);
2444 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2445 ins->opcode = OP_LSUB;
2447 temp->sreg1 = ins->sreg1;
2448 temp->sreg2 = ins->sreg2;
2449 temp->dreg = mono_alloc_ireg (cfg);
2450 mul->sreg1 = temp->dreg;
2451 mul->sreg2 = ins->sreg2;
2452 mul->dreg = mono_alloc_ireg (cfg);
2453 ins->sreg2 = mul->dreg;
2454 break;
2456 case OP_IADD_IMM:
2457 CASE_PPC64 (OP_LADD_IMM)
2458 case OP_ADD_IMM:
2459 case OP_ADDCC_IMM:
2460 if (!ppc_is_imm16 (ins->inst_imm)) {
2461 NEW_INS (cfg, temp, OP_ICONST);
2462 temp->inst_c0 = ins->inst_imm;
2463 temp->dreg = mono_alloc_ireg (cfg);
2464 ins->sreg2 = temp->dreg;
2465 ins->opcode = map_to_reg_reg_op (ins->opcode);
2467 break;
2468 case OP_ISUB_IMM:
2469 CASE_PPC64 (OP_LSUB_IMM)
2470 case OP_SUB_IMM:
2471 if (!ppc_is_imm16 (-ins->inst_imm)) {
2472 NEW_INS (cfg, temp, OP_ICONST);
2473 temp->inst_c0 = ins->inst_imm;
2474 temp->dreg = mono_alloc_ireg (cfg);
2475 ins->sreg2 = temp->dreg;
2476 ins->opcode = map_to_reg_reg_op (ins->opcode);
2478 break;
2479 case OP_IAND_IMM:
2480 case OP_IOR_IMM:
2481 case OP_IXOR_IMM:
2482 case OP_LAND_IMM:
2483 case OP_LOR_IMM:
2484 case OP_LXOR_IMM:
2485 case OP_AND_IMM:
2486 case OP_OR_IMM:
2487 case OP_XOR_IMM: {
2488 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2489 #ifdef __mono_ppc64__
2490 if (ins->inst_imm & 0xffffffff00000000ULL)
2491 is_imm = TRUE;
2492 #endif
2493 if (is_imm) {
2494 NEW_INS (cfg, temp, OP_ICONST);
2495 temp->inst_c0 = ins->inst_imm;
2496 temp->dreg = mono_alloc_ireg (cfg);
2497 ins->sreg2 = temp->dreg;
2498 ins->opcode = map_to_reg_reg_op (ins->opcode);
2500 break;
2502 case OP_ISBB_IMM:
2503 case OP_IADC_IMM:
2504 case OP_SBB_IMM:
2505 case OP_SUBCC_IMM:
2506 case OP_ADC_IMM:
2507 NEW_INS (cfg, temp, OP_ICONST);
2508 temp->inst_c0 = ins->inst_imm;
2509 temp->dreg = mono_alloc_ireg (cfg);
2510 ins->sreg2 = temp->dreg;
2511 ins->opcode = map_to_reg_reg_op (ins->opcode);
2512 break;
2513 case OP_COMPARE_IMM:
2514 case OP_ICOMPARE_IMM:
2515 CASE_PPC64 (OP_LCOMPARE_IMM)
2516 next = ins->next;
2517 /* Branch opts can eliminate the branch */
2518 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2519 ins->opcode = OP_NOP;
2520 break;
2522 g_assert(next);
2523 if (compare_opcode_is_unsigned (next->opcode)) {
2524 if (!ppc_is_uimm16 (ins->inst_imm)) {
2525 NEW_INS (cfg, temp, OP_ICONST);
2526 temp->inst_c0 = ins->inst_imm;
2527 temp->dreg = mono_alloc_ireg (cfg);
2528 ins->sreg2 = temp->dreg;
2529 ins->opcode = map_to_reg_reg_op (ins->opcode);
2531 } else {
2532 if (!ppc_is_imm16 (ins->inst_imm)) {
2533 NEW_INS (cfg, temp, OP_ICONST);
2534 temp->inst_c0 = ins->inst_imm;
2535 temp->dreg = mono_alloc_ireg (cfg);
2536 ins->sreg2 = temp->dreg;
2537 ins->opcode = map_to_reg_reg_op (ins->opcode);
2540 break;
2541 case OP_IMUL_IMM:
2542 case OP_MUL_IMM:
2543 CASE_PPC64 (OP_LMUL_IMM)
2544 if (ins->inst_imm == 1) {
2545 ins->opcode = OP_MOVE;
2546 break;
2548 if (ins->inst_imm == 0) {
2549 ins->opcode = OP_ICONST;
2550 ins->inst_c0 = 0;
2551 break;
2553 imm = mono_is_power_of_two (ins->inst_imm);
2554 if (imm > 0) {
2555 ins->opcode = OP_SHL_IMM;
2556 ins->inst_imm = imm;
2557 break;
2559 if (!ppc_is_imm16 (ins->inst_imm)) {
2560 NEW_INS (cfg, temp, OP_ICONST);
2561 temp->inst_c0 = ins->inst_imm;
2562 temp->dreg = mono_alloc_ireg (cfg);
2563 ins->sreg2 = temp->dreg;
2564 ins->opcode = map_to_reg_reg_op (ins->opcode);
2566 break;
2567 case OP_LOCALLOC_IMM:
2568 NEW_INS (cfg, temp, OP_ICONST);
2569 temp->inst_c0 = ins->inst_imm;
2570 temp->dreg = mono_alloc_ireg (cfg);
2571 ins->sreg1 = temp->dreg;
2572 ins->opcode = OP_LOCALLOC;
2573 break;
2574 case OP_LOAD_MEMBASE:
2575 case OP_LOADI4_MEMBASE:
2576 CASE_PPC64 (OP_LOADI8_MEMBASE)
2577 case OP_LOADU4_MEMBASE:
2578 case OP_LOADI2_MEMBASE:
2579 case OP_LOADU2_MEMBASE:
2580 case OP_LOADI1_MEMBASE:
2581 case OP_LOADU1_MEMBASE:
2582 case OP_LOADR4_MEMBASE:
2583 case OP_LOADR8_MEMBASE:
2584 case OP_STORE_MEMBASE_REG:
2585 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2586 case OP_STOREI4_MEMBASE_REG:
2587 case OP_STOREI2_MEMBASE_REG:
2588 case OP_STOREI1_MEMBASE_REG:
2589 case OP_STORER4_MEMBASE_REG:
2590 case OP_STORER8_MEMBASE_REG:
2591 /* we can do two things: load the immed in a register
2592 * and use an indexed load, or see if the immed can be
2593 * represented as an ad_imm + a load with a smaller offset
2594 * that fits. We just do the first for now, optimize later.
2596 if (ppc_is_imm16 (ins->inst_offset))
2597 break;
2598 NEW_INS (cfg, temp, OP_ICONST);
2599 temp->inst_c0 = ins->inst_offset;
2600 temp->dreg = mono_alloc_ireg (cfg);
2601 ins->sreg2 = temp->dreg;
2602 ins->opcode = map_to_reg_reg_op (ins->opcode);
2603 break;
2604 case OP_STORE_MEMBASE_IMM:
2605 case OP_STOREI1_MEMBASE_IMM:
2606 case OP_STOREI2_MEMBASE_IMM:
2607 case OP_STOREI4_MEMBASE_IMM:
2608 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2609 NEW_INS (cfg, temp, OP_ICONST);
2610 temp->inst_c0 = ins->inst_imm;
2611 temp->dreg = mono_alloc_ireg (cfg);
2612 ins->sreg1 = temp->dreg;
2613 ins->opcode = map_to_reg_reg_op (ins->opcode);
2614 last_ins = temp;
2615 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2616 case OP_R8CONST:
2617 case OP_R4CONST:
2618 if (cfg->compile_aot) {
2619 /* Keep these in the aot case */
2620 break;
2622 NEW_INS (cfg, temp, OP_ICONST);
2623 temp->inst_c0 = (gulong)ins->inst_p0;
2624 temp->dreg = mono_alloc_ireg (cfg);
2625 ins->inst_basereg = temp->dreg;
2626 ins->inst_offset = 0;
2627 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2628 last_ins = temp;
2629 /* make it handle the possibly big ins->inst_offset
2630 * later optimize to use lis + load_membase
2632 goto loop_start;
2634 last_ins = ins;
2636 bb->last_ins = last_ins;
2637 bb->max_vreg = cfg->next_vreg;
2640 static guchar*
2641 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2643 long offset = cfg->arch.fp_conv_var_offset;
2644 long sub_offset;
2645 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2646 #ifdef __mono_ppc64__
2647 if (size == 8) {
2648 ppc_fctidz (code, ppc_f0, sreg);
2649 sub_offset = 0;
2650 } else
2651 #endif
2653 ppc_fctiwz (code, ppc_f0, sreg);
2654 sub_offset = 4;
2656 if (ppc_is_imm16 (offset + sub_offset)) {
2657 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2658 if (size == 8)
2659 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2660 else
2661 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2662 } else {
2663 ppc_load (code, dreg, offset);
2664 ppc_add (code, dreg, dreg, cfg->frame_reg);
2665 ppc_stfd (code, ppc_f0, 0, dreg);
2666 if (size == 8)
2667 ppc_ldr (code, dreg, sub_offset, dreg);
2668 else
2669 ppc_lwz (code, dreg, sub_offset, dreg);
2671 if (!is_signed) {
2672 if (size == 1)
2673 ppc_andid (code, dreg, dreg, 0xff);
2674 else if (size == 2)
2675 ppc_andid (code, dreg, dreg, 0xffff);
2676 #ifdef __mono_ppc64__
2677 else if (size == 4)
2678 ppc_clrldi (code, dreg, dreg, 32);
2679 #endif
2680 } else {
2681 if (size == 1)
2682 ppc_extsb (code, dreg, dreg);
2683 else if (size == 2)
2684 ppc_extsh (code, dreg, dreg);
2685 #ifdef __mono_ppc64__
2686 else if (size == 4)
2687 ppc_extsw (code, dreg, dreg);
2688 #endif
2690 return code;
2693 static void
2694 emit_thunk (guint8 *code, gconstpointer target)
2696 guint8 *p = code;
2698 /* 2 bytes on 32bit, 5 bytes on 64bit */
2699 ppc_load_sequence (code, ppc_r0, target);
2701 ppc_mtctr (code, ppc_r0);
2702 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2704 mono_arch_flush_icache (p, code - p);
2707 static void
2708 handle_thunk (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
2710 MonoJitInfo *ji = NULL;
2711 MonoThunkJitInfo *info;
2712 guint8 *thunks, *p;
2713 int thunks_size;
2714 guint8 *orig_target;
2715 guint8 *target_thunk;
2717 if (!domain)
2718 domain = mono_domain_get ();
2720 if (cfg) {
2722 * This can be called multiple times during JITting,
2723 * save the current position in cfg->arch to avoid
2724 * doing a O(n^2) search.
2726 if (!cfg->arch.thunks) {
2727 cfg->arch.thunks = cfg->thunks;
2728 cfg->arch.thunks_size = cfg->thunk_area;
2730 thunks = cfg->arch.thunks;
2731 thunks_size = cfg->arch.thunks_size;
2732 if (!thunks_size) {
2733 g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, mono_method_full_name (cfg->method, TRUE));
2734 g_assert_not_reached ();
2737 g_assert (*(guint32*)thunks == 0);
2738 emit_thunk (thunks, target);
2739 ppc_patch (code, thunks);
2741 cfg->arch.thunks += THUNK_SIZE;
2742 cfg->arch.thunks_size -= THUNK_SIZE;
2743 } else {
2744 ji = mini_jit_info_table_find (domain, (char *) code, NULL);
2745 g_assert (ji);
2746 info = mono_jit_info_get_thunk_info (ji);
2747 g_assert (info);
2749 thunks = (guint8 *) ji->code_start + info->thunks_offset;
2750 thunks_size = info->thunks_size;
2752 orig_target = mono_arch_get_call_target (code + 4);
2754 mono_mini_arch_lock ();
2756 target_thunk = NULL;
2757 if (orig_target >= thunks && orig_target < thunks + thunks_size) {
2758 /* The call already points to a thunk, because of trampolines etc. */
2759 target_thunk = orig_target;
2760 } else {
2761 for (p = thunks; p < thunks + thunks_size; p += THUNK_SIZE) {
2762 if (((guint32 *) p) [0] == 0) {
2763 /* Free entry */
2764 target_thunk = p;
2765 break;
2766 } else {
2767 /* ppc64 requires 5 instructions, 32bit two instructions */
2768 #ifdef __mono_ppc64__
2769 const int const_load_size = 5;
2770 #else
2771 const int const_load_size = 2;
2772 #endif
2773 guint32 load [const_load_size];
2774 guchar *templ = (guchar *) load;
2775 ppc_load_sequence (templ, ppc_r0, target);
2776 if (!memcmp (p, load, const_load_size)) {
2777 /* Thunk already points to target */
2778 target_thunk = p;
2779 break;
2785 // g_print ("THUNK: %p %p %p\n", code, target, target_thunk);
2787 if (!target_thunk) {
2788 mono_mini_arch_unlock ();
2789 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));
2790 g_assert_not_reached ();
2793 emit_thunk (target_thunk, target);
2794 ppc_patch (code, target_thunk);
2796 mono_mini_arch_unlock ();
2800 static void
2801 patch_ins (guint8 *code, guint32 ins)
2803 *(guint32*)code = ins;
2804 mono_arch_flush_icache (code, 4);
2807 static void
2808 ppc_patch_full (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target, gboolean is_fd)
2810 guint32 ins = *(guint32*)code;
2811 guint32 prim = ins >> 26;
2812 guint32 ovf;
2814 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2815 if (prim == 18) {
2816 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2817 gint diff = target - code;
2818 g_assert (!is_fd);
2819 if (diff >= 0){
2820 if (diff <= 33554431){
2821 ins = (18 << 26) | (diff) | (ins & 1);
2822 patch_ins (code, ins);
2823 return;
2825 } else {
2826 /* diff between 0 and -33554432 */
2827 if (diff >= -33554432){
2828 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2829 patch_ins (code, ins);
2830 return;
2834 if ((glong)target >= 0){
2835 if ((glong)target <= 33554431){
2836 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2837 patch_ins (code, ins);
2838 return;
2840 } else {
2841 if ((glong)target >= -33554432){
2842 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2843 patch_ins (code, ins);
2844 return;
2848 handle_thunk (cfg, domain, code, target);
2849 return;
2851 g_assert_not_reached ();
2855 if (prim == 16) {
2856 g_assert (!is_fd);
2857 // absolute address
2858 if (ins & 2) {
2859 guint32 li = (gulong)target;
2860 ins = (ins & 0xffff0000) | (ins & 3);
2861 ovf = li & 0xffff0000;
2862 if (ovf != 0 && ovf != 0xffff0000)
2863 g_assert_not_reached ();
2864 li &= 0xffff;
2865 ins |= li;
2866 // FIXME: assert the top bits of li are 0
2867 } else {
2868 gint diff = target - code;
2869 ins = (ins & 0xffff0000) | (ins & 3);
2870 ovf = diff & 0xffff0000;
2871 if (ovf != 0 && ovf != 0xffff0000)
2872 g_assert_not_reached ();
2873 diff &= 0xffff;
2874 ins |= diff;
2876 patch_ins (code, ins);
2877 return;
2880 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2881 #ifdef __mono_ppc64__
2882 guint32 *seq = (guint32*)code;
2883 guint32 *branch_ins;
2885 /* the trampoline code will try to patch the blrl, blr, bcctr */
2886 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2887 branch_ins = seq;
2888 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2889 code -= 32;
2890 else
2891 code -= 24;
2892 } else {
2893 if (ppc_is_load_op (seq [5])
2894 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2895 /* With function descs we need to do more careful
2896 matches. */
2897 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
2898 #endif
2900 branch_ins = seq + 8;
2901 else
2902 branch_ins = seq + 6;
2905 seq = (guint32*)code;
2906 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2907 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2909 if (ppc_is_load_op (seq [5])) {
2910 g_assert (ppc_is_load_op (seq [6]));
2912 if (!is_fd) {
2913 guint8 *buf = (guint8*)&seq [5];
2914 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
2915 ppc_nop (buf);
2917 } else {
2918 if (is_fd)
2919 target = (const guchar*)mono_get_addr_from_ftnptr ((gpointer)target);
2922 /* FIXME: make this thread safe */
2923 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2924 /* FIXME: we're assuming we're using r12 here */
2925 ppc_load_ptr_sequence (code, ppc_r12, target);
2926 #else
2927 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
2928 #endif
2929 mono_arch_flush_icache ((guint8*)seq, 28);
2930 #else
2931 guint32 *seq;
2932 /* the trampoline code will try to patch the blrl, blr, bcctr */
2933 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2934 code -= 12;
2936 /* this is the lis/ori/mtlr/blrl sequence */
2937 seq = (guint32*)code;
2938 g_assert ((seq [0] >> 26) == 15);
2939 g_assert ((seq [1] >> 26) == 24);
2940 g_assert ((seq [2] >> 26) == 31);
2941 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2942 /* FIXME: make this thread safe */
2943 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
2944 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
2945 mono_arch_flush_icache (code - 8, 8);
2946 #endif
2947 } else {
2948 g_assert_not_reached ();
2950 // g_print ("patched with 0x%08x\n", ins);
2953 void
2954 ppc_patch (guchar *code, const guchar *target)
2956 ppc_patch_full (NULL, NULL, code, target, FALSE);
2959 void
2960 mono_ppc_patch (guchar *code, const guchar *target)
2962 ppc_patch (code, target);
2965 static guint8*
2966 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2968 switch (ins->opcode) {
2969 case OP_FCALL:
2970 case OP_FCALL_REG:
2971 case OP_FCALL_MEMBASE:
2972 if (ins->dreg != ppc_f1)
2973 ppc_fmr (code, ins->dreg, ppc_f1);
2974 break;
2977 return code;
2980 static guint8*
2981 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2983 long size = cfg->param_area;
2985 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2986 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2988 if (!size)
2989 return code;
2991 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
2992 if (ppc_is_imm16 (-size)) {
2993 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
2994 } else {
2995 ppc_load (code, ppc_r12, -size);
2996 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
2999 return code;
3002 static guint8*
3003 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3005 long size = cfg->param_area;
3007 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3008 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3010 if (!size)
3011 return code;
3013 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3014 if (ppc_is_imm16 (size)) {
3015 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3016 } else {
3017 ppc_load (code, ppc_r12, size);
3018 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3021 return code;
3024 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3026 #ifndef DISABLE_JIT
3027 void
3028 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3030 MonoInst *ins, *next;
3031 MonoCallInst *call;
3032 guint8 *code = cfg->native_code + cfg->code_len;
3033 MonoInst *last_ins = NULL;
3034 int max_len, cpos;
3035 int L;
3037 /* we don't align basic blocks of loops on ppc */
3039 if (cfg->verbose_level > 2)
3040 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3042 cpos = bb->max_offset;
3044 MONO_BB_FOR_EACH_INS (bb, ins) {
3045 const guint offset = code - cfg->native_code;
3046 set_code_cursor (cfg, code);
3047 max_len = ins_get_size (ins->opcode);
3048 code = realloc_code (cfg, max_len);
3049 // if (ins->cil_code)
3050 // g_print ("cil code\n");
3051 mono_debug_record_line_number (cfg, ins, offset);
3053 switch (normalize_opcode (ins->opcode)) {
3054 case OP_RELAXED_NOP:
3055 case OP_NOP:
3056 case OP_DUMMY_USE:
3057 case OP_DUMMY_ICONST:
3058 case OP_DUMMY_I8CONST:
3059 case OP_DUMMY_R8CONST:
3060 case OP_DUMMY_R4CONST:
3061 case OP_NOT_REACHED:
3062 case OP_NOT_NULL:
3063 break;
3064 case OP_IL_SEQ_POINT:
3065 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3066 break;
3067 case OP_SEQ_POINT: {
3068 int i;
3070 if (cfg->compile_aot)
3071 NOT_IMPLEMENTED;
3074 * Read from the single stepping trigger page. This will cause a
3075 * SIGSEGV when single stepping is enabled.
3076 * We do this _before_ the breakpoint, so single stepping after
3077 * a breakpoint is hit will step to the next IL offset.
3079 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3080 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3081 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3084 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3087 * A placeholder for a possible breakpoint inserted by
3088 * mono_arch_set_breakpoint ().
3090 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3091 ppc_nop (code);
3092 break;
3094 case OP_BIGMUL:
3095 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3096 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3097 ppc_mr (code, ppc_r4, ppc_r0);
3098 break;
3099 case OP_BIGMUL_UN:
3100 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3101 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3102 ppc_mr (code, ppc_r4, ppc_r0);
3103 break;
3104 case OP_MEMORY_BARRIER:
3105 ppc_sync (code);
3106 break;
3107 case OP_STOREI1_MEMBASE_REG:
3108 if (ppc_is_imm16 (ins->inst_offset)) {
3109 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3110 } else {
3111 if (ppc_is_imm32 (ins->inst_offset)) {
3112 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3113 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3114 } else {
3115 ppc_load (code, ppc_r0, ins->inst_offset);
3116 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3119 break;
3120 case OP_STOREI2_MEMBASE_REG:
3121 if (ppc_is_imm16 (ins->inst_offset)) {
3122 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3123 } else {
3124 if (ppc_is_imm32 (ins->inst_offset)) {
3125 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3126 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3127 } else {
3128 ppc_load (code, ppc_r0, ins->inst_offset);
3129 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3132 break;
3133 case OP_STORE_MEMBASE_REG:
3134 if (ppc_is_imm16 (ins->inst_offset)) {
3135 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3136 } else {
3137 if (ppc_is_imm32 (ins->inst_offset)) {
3138 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3139 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3140 } else {
3141 ppc_load (code, ppc_r0, ins->inst_offset);
3142 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3145 break;
3146 #ifdef MONO_ARCH_ILP32
3147 case OP_STOREI8_MEMBASE_REG:
3148 if (ppc_is_imm16 (ins->inst_offset)) {
3149 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3150 } else {
3151 ppc_load (code, ppc_r0, ins->inst_offset);
3152 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3154 break;
3155 #endif
3156 case OP_STOREI1_MEMINDEX:
3157 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3158 break;
3159 case OP_STOREI2_MEMINDEX:
3160 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3161 break;
3162 case OP_STORE_MEMINDEX:
3163 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3164 break;
3165 case OP_LOADU4_MEM:
3166 g_assert_not_reached ();
3167 break;
3168 case OP_LOAD_MEMBASE:
3169 if (ppc_is_imm16 (ins->inst_offset)) {
3170 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3171 } else {
3172 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3173 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3174 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3175 } else {
3176 ppc_load (code, ppc_r0, ins->inst_offset);
3177 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3180 break;
3181 case OP_LOADI4_MEMBASE:
3182 #ifdef __mono_ppc64__
3183 if (ppc_is_imm16 (ins->inst_offset)) {
3184 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3185 } else {
3186 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3187 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3188 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3189 } else {
3190 ppc_load (code, ppc_r0, ins->inst_offset);
3191 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3194 break;
3195 #endif
3196 case OP_LOADU4_MEMBASE:
3197 if (ppc_is_imm16 (ins->inst_offset)) {
3198 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3199 } else {
3200 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3201 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3202 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3203 } else {
3204 ppc_load (code, ppc_r0, ins->inst_offset);
3205 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3208 break;
3209 case OP_LOADI1_MEMBASE:
3210 case OP_LOADU1_MEMBASE:
3211 if (ppc_is_imm16 (ins->inst_offset)) {
3212 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3213 } else {
3214 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3215 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3216 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3217 } else {
3218 ppc_load (code, ppc_r0, ins->inst_offset);
3219 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3222 if (ins->opcode == OP_LOADI1_MEMBASE)
3223 ppc_extsb (code, ins->dreg, ins->dreg);
3224 break;
3225 case OP_LOADU2_MEMBASE:
3226 if (ppc_is_imm16 (ins->inst_offset)) {
3227 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3228 } else {
3229 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3230 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3231 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3232 } else {
3233 ppc_load (code, ppc_r0, ins->inst_offset);
3234 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3237 break;
3238 case OP_LOADI2_MEMBASE:
3239 if (ppc_is_imm16 (ins->inst_offset)) {
3240 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3241 } else {
3242 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3243 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3244 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3245 } else {
3246 ppc_load (code, ppc_r0, ins->inst_offset);
3247 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3250 break;
3251 #ifdef MONO_ARCH_ILP32
3252 case OP_LOADI8_MEMBASE:
3253 if (ppc_is_imm16 (ins->inst_offset)) {
3254 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3255 } else {
3256 ppc_load (code, ppc_r0, ins->inst_offset);
3257 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3259 break;
3260 #endif
3261 case OP_LOAD_MEMINDEX:
3262 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3263 break;
3264 case OP_LOADI4_MEMINDEX:
3265 #ifdef __mono_ppc64__
3266 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3267 break;
3268 #endif
3269 case OP_LOADU4_MEMINDEX:
3270 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3271 break;
3272 case OP_LOADU2_MEMINDEX:
3273 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3274 break;
3275 case OP_LOADI2_MEMINDEX:
3276 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3277 break;
3278 case OP_LOADU1_MEMINDEX:
3279 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3280 break;
3281 case OP_LOADI1_MEMINDEX:
3282 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3283 ppc_extsb (code, ins->dreg, ins->dreg);
3284 break;
3285 case OP_ICONV_TO_I1:
3286 CASE_PPC64 (OP_LCONV_TO_I1)
3287 ppc_extsb (code, ins->dreg, ins->sreg1);
3288 break;
3289 case OP_ICONV_TO_I2:
3290 CASE_PPC64 (OP_LCONV_TO_I2)
3291 ppc_extsh (code, ins->dreg, ins->sreg1);
3292 break;
3293 case OP_ICONV_TO_U1:
3294 CASE_PPC64 (OP_LCONV_TO_U1)
3295 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3296 break;
3297 case OP_ICONV_TO_U2:
3298 CASE_PPC64 (OP_LCONV_TO_U2)
3299 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3300 break;
3301 case OP_COMPARE:
3302 case OP_ICOMPARE:
3303 CASE_PPC64 (OP_LCOMPARE)
3304 L = (sizeof (target_mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3305 next = ins->next;
3306 if (next && compare_opcode_is_unsigned (next->opcode))
3307 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3308 else
3309 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3310 break;
3311 case OP_COMPARE_IMM:
3312 case OP_ICOMPARE_IMM:
3313 CASE_PPC64 (OP_LCOMPARE_IMM)
3314 L = (sizeof (target_mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3315 next = ins->next;
3316 if (next && compare_opcode_is_unsigned (next->opcode)) {
3317 if (ppc_is_uimm16 (ins->inst_imm)) {
3318 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3319 } else {
3320 g_assert_not_reached ();
3322 } else {
3323 if (ppc_is_imm16 (ins->inst_imm)) {
3324 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3325 } else {
3326 g_assert_not_reached ();
3329 break;
3330 case OP_BREAK:
3332 * gdb does not like encountering a trap in the debugged code. So
3333 * instead of emitting a trap, we emit a call a C function and place a
3334 * breakpoint there.
3336 //ppc_break (code);
3337 ppc_mr (code, ppc_r3, ins->sreg1);
3338 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break));
3339 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3340 ppc_load_func (code, PPC_CALL_REG, 0);
3341 ppc_mtlr (code, PPC_CALL_REG);
3342 ppc_blrl (code);
3343 } else {
3344 ppc_bl (code, 0);
3346 break;
3347 case OP_ADDCC:
3348 case OP_IADDCC:
3349 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3350 break;
3351 case OP_IADD:
3352 CASE_PPC64 (OP_LADD)
3353 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3354 break;
3355 case OP_ADC:
3356 case OP_IADC:
3357 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3358 break;
3359 case OP_ADDCC_IMM:
3360 if (ppc_is_imm16 (ins->inst_imm)) {
3361 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3362 } else {
3363 g_assert_not_reached ();
3365 break;
3366 case OP_ADD_IMM:
3367 case OP_IADD_IMM:
3368 CASE_PPC64 (OP_LADD_IMM)
3369 if (ppc_is_imm16 (ins->inst_imm)) {
3370 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3371 } else {
3372 g_assert_not_reached ();
3374 break;
3375 case OP_IADD_OVF:
3376 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3378 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3379 ppc_mfspr (code, ppc_r0, ppc_xer);
3380 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3381 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3382 break;
3383 case OP_IADD_OVF_UN:
3384 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3386 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3387 ppc_mfspr (code, ppc_r0, ppc_xer);
3388 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3389 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3390 break;
3391 case OP_ISUB_OVF:
3392 CASE_PPC64 (OP_LSUB_OVF)
3393 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3395 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3396 ppc_mfspr (code, ppc_r0, ppc_xer);
3397 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3398 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3399 break;
3400 case OP_ISUB_OVF_UN:
3401 CASE_PPC64 (OP_LSUB_OVF_UN)
3402 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3404 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3405 ppc_mfspr (code, ppc_r0, ppc_xer);
3406 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3407 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3408 break;
3409 case OP_ADD_OVF_CARRY:
3410 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3412 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3413 ppc_mfspr (code, ppc_r0, ppc_xer);
3414 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3415 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3416 break;
3417 case OP_ADD_OVF_UN_CARRY:
3418 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3420 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3421 ppc_mfspr (code, ppc_r0, ppc_xer);
3422 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3423 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3424 break;
3425 case OP_SUB_OVF_CARRY:
3426 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3428 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3429 ppc_mfspr (code, ppc_r0, ppc_xer);
3430 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3431 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3432 break;
3433 case OP_SUB_OVF_UN_CARRY:
3434 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3436 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3437 ppc_mfspr (code, ppc_r0, ppc_xer);
3438 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3439 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3440 break;
3441 case OP_SUBCC:
3442 case OP_ISUBCC:
3443 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3444 break;
3445 case OP_ISUB:
3446 CASE_PPC64 (OP_LSUB)
3447 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3448 break;
3449 case OP_SBB:
3450 case OP_ISBB:
3451 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3452 break;
3453 case OP_SUB_IMM:
3454 case OP_ISUB_IMM:
3455 CASE_PPC64 (OP_LSUB_IMM)
3456 // we add the negated value
3457 if (ppc_is_imm16 (-ins->inst_imm))
3458 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3459 else {
3460 g_assert_not_reached ();
3462 break;
3463 case OP_PPC_SUBFIC:
3464 g_assert (ppc_is_imm16 (ins->inst_imm));
3465 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3466 break;
3467 case OP_PPC_SUBFZE:
3468 ppc_subfze (code, ins->dreg, ins->sreg1);
3469 break;
3470 case OP_IAND:
3471 CASE_PPC64 (OP_LAND)
3472 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3473 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3474 break;
3475 case OP_AND_IMM:
3476 case OP_IAND_IMM:
3477 CASE_PPC64 (OP_LAND_IMM)
3478 if (!(ins->inst_imm & 0xffff0000)) {
3479 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3480 } else if (!(ins->inst_imm & 0xffff)) {
3481 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3482 } else {
3483 g_assert_not_reached ();
3485 break;
3486 case OP_IDIV:
3487 CASE_PPC64 (OP_LDIV) {
3488 guint8 *divisor_is_m1;
3489 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3491 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3492 divisor_is_m1 = code;
3493 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3494 ppc_lis (code, ppc_r0, 0x8000);
3495 #ifdef __mono_ppc64__
3496 if (ins->opcode == OP_LDIV)
3497 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3498 #endif
3499 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3500 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3501 ppc_patch (divisor_is_m1, code);
3502 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3504 if (ins->opcode == OP_IDIV)
3505 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3506 #ifdef __mono_ppc64__
3507 else
3508 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3509 #endif
3510 ppc_mfspr (code, ppc_r0, ppc_xer);
3511 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3512 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3513 break;
3515 case OP_IDIV_UN:
3516 CASE_PPC64 (OP_LDIV_UN)
3517 if (ins->opcode == OP_IDIV_UN)
3518 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3519 #ifdef __mono_ppc64__
3520 else
3521 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3522 #endif
3523 ppc_mfspr (code, ppc_r0, ppc_xer);
3524 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3525 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3526 break;
3527 case OP_DIV_IMM:
3528 case OP_IREM:
3529 case OP_IREM_UN:
3530 case OP_REM_IMM:
3531 g_assert_not_reached ();
3532 case OP_IOR:
3533 CASE_PPC64 (OP_LOR)
3534 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3535 break;
3536 case OP_OR_IMM:
3537 case OP_IOR_IMM:
3538 CASE_PPC64 (OP_LOR_IMM)
3539 if (!(ins->inst_imm & 0xffff0000)) {
3540 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3541 } else if (!(ins->inst_imm & 0xffff)) {
3542 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3543 } else {
3544 g_assert_not_reached ();
3546 break;
3547 case OP_IXOR:
3548 CASE_PPC64 (OP_LXOR)
3549 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3550 break;
3551 case OP_IXOR_IMM:
3552 case OP_XOR_IMM:
3553 CASE_PPC64 (OP_LXOR_IMM)
3554 if (!(ins->inst_imm & 0xffff0000)) {
3555 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3556 } else if (!(ins->inst_imm & 0xffff)) {
3557 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3558 } else {
3559 g_assert_not_reached ();
3561 break;
3562 case OP_ISHL:
3563 CASE_PPC64 (OP_LSHL)
3564 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3565 break;
3566 case OP_SHL_IMM:
3567 case OP_ISHL_IMM:
3568 CASE_PPC64 (OP_LSHL_IMM)
3569 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3570 break;
3571 case OP_ISHR:
3572 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3573 break;
3574 case OP_SHR_IMM:
3575 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3576 break;
3577 case OP_SHR_UN_IMM:
3578 if (MASK_SHIFT_IMM (ins->inst_imm))
3579 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3580 else
3581 ppc_mr (code, ins->dreg, ins->sreg1);
3582 break;
3583 case OP_ISHR_UN:
3584 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3585 break;
3586 case OP_INOT:
3587 CASE_PPC64 (OP_LNOT)
3588 ppc_not (code, ins->dreg, ins->sreg1);
3589 break;
3590 case OP_INEG:
3591 CASE_PPC64 (OP_LNEG)
3592 ppc_neg (code, ins->dreg, ins->sreg1);
3593 break;
3594 case OP_IMUL:
3595 CASE_PPC64 (OP_LMUL)
3596 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3597 break;
3598 case OP_IMUL_IMM:
3599 case OP_MUL_IMM:
3600 CASE_PPC64 (OP_LMUL_IMM)
3601 if (ppc_is_imm16 (ins->inst_imm)) {
3602 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3603 } else {
3604 g_assert_not_reached ();
3606 break;
3607 case OP_IMUL_OVF:
3608 CASE_PPC64 (OP_LMUL_OVF)
3609 /* we annot use mcrxr, since it's not implemented on some processors
3610 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3612 if (ins->opcode == OP_IMUL_OVF)
3613 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3614 #ifdef __mono_ppc64__
3615 else
3616 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3617 #endif
3618 ppc_mfspr (code, ppc_r0, ppc_xer);
3619 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3620 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3621 break;
3622 case OP_IMUL_OVF_UN:
3623 CASE_PPC64 (OP_LMUL_OVF_UN)
3624 /* we first multiply to get the high word and compare to 0
3625 * to set the flags, then the result is discarded and then
3626 * we multiply to get the lower * bits result
3628 if (ins->opcode == OP_IMUL_OVF_UN)
3629 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3630 #ifdef __mono_ppc64__
3631 else
3632 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3633 #endif
3634 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3635 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3636 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 break;
3638 case OP_ICONST:
3639 ppc_load (code, ins->dreg, ins->inst_c0);
3640 break;
3641 case OP_I8CONST: {
3642 ppc_load (code, ins->dreg, ins->inst_l);
3643 break;
3645 case OP_LOAD_GOTADDR:
3646 /* The PLT implementation depends on this */
3647 g_assert (ins->dreg == ppc_r30);
3649 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3650 break;
3651 case OP_GOT_ENTRY:
3652 // FIXME: Fix max instruction length
3653 /* XXX: This is hairy; we're casting a pointer from a union to an enum... */
3654 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)(intptr_t)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3655 /* arch_emit_got_access () patches this */
3656 ppc_load32 (code, ppc_r0, 0);
3657 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3658 break;
3659 case OP_AOTCONST:
3660 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)(intptr_t)ins->inst_i1, ins->inst_p0);
3661 ppc_load_sequence (code, ins->dreg, 0);
3662 break;
3663 CASE_PPC32 (OP_ICONV_TO_I4)
3664 CASE_PPC32 (OP_ICONV_TO_U4)
3665 case OP_MOVE:
3666 if (ins->dreg != ins->sreg1)
3667 ppc_mr (code, ins->dreg, ins->sreg1);
3668 break;
3669 case OP_SETLRET: {
3670 int saved = ins->sreg1;
3671 if (ins->sreg1 == ppc_r3) {
3672 ppc_mr (code, ppc_r0, ins->sreg1);
3673 saved = ppc_r0;
3675 if (ins->sreg2 != ppc_r3)
3676 ppc_mr (code, ppc_r3, ins->sreg2);
3677 if (saved != ppc_r4)
3678 ppc_mr (code, ppc_r4, saved);
3679 break;
3681 case OP_FMOVE:
3682 if (ins->dreg != ins->sreg1)
3683 ppc_fmr (code, ins->dreg, ins->sreg1);
3684 break;
3685 case OP_MOVE_F_TO_I4:
3686 ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3687 ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3688 break;
3689 case OP_MOVE_I4_TO_F:
3690 ppc_stw (code, ins->sreg1, -4, ppc_r1);
3691 ppc_lfs (code, ins->dreg, -4, ppc_r1);
3692 break;
3693 #ifdef __mono_ppc64__
3694 case OP_MOVE_F_TO_I8:
3695 ppc_stfd (code, ins->sreg1, -8, ppc_r1);
3696 ppc_ldptr (code, ins->dreg, -8, ppc_r1);
3697 break;
3698 case OP_MOVE_I8_TO_F:
3699 ppc_stptr (code, ins->sreg1, -8, ppc_r1);
3700 ppc_lfd (code, ins->dreg, -8, ppc_r1);
3701 break;
3702 #endif
3703 case OP_FCONV_TO_R4:
3704 ppc_frsp (code, ins->dreg, ins->sreg1);
3705 break;
3707 case OP_TAILCALL_PARAMETER:
3708 // This opcode helps compute sizes, i.e.
3709 // of the subsequent OP_TAILCALL, but contributes no code.
3710 g_assert (ins->next);
3711 break;
3713 case OP_TAILCALL: {
3714 int i, pos;
3715 MonoCallInst *call = (MonoCallInst*)ins;
3718 * Keep in sync with mono_arch_emit_epilog
3720 g_assert (!cfg->method->save_lmf);
3722 * Note: we can use ppc_r12 here because it is dead anyway:
3723 * we're leaving the method.
3725 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3726 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3727 if (ppc_is_imm16 (ret_offset)) {
3728 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3729 } else {
3730 ppc_load (code, ppc_r12, ret_offset);
3731 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3733 ppc_mtlr (code, ppc_r0);
3736 if (ppc_is_imm16 (cfg->stack_usage)) {
3737 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3738 } else {
3739 /* cfg->stack_usage is an int, so we can use
3740 * an addis/addi sequence here even in 64-bit. */
3741 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3742 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3744 if (!cfg->method->save_lmf) {
3745 pos = 0;
3746 for (i = 31; i >= 13; --i) {
3747 if (cfg->used_int_regs & (1 << i)) {
3748 pos += sizeof (target_mgreg_t);
3749 ppc_ldptr (code, i, -pos, ppc_r12);
3752 } else {
3753 /* FIXME restore from MonoLMF: though this can't happen yet */
3756 /* Copy arguments on the stack to our argument area */
3757 if (call->stack_usage) {
3758 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3759 /* r12 was clobbered */
3760 g_assert (cfg->frame_reg == ppc_sp);
3761 if (ppc_is_imm16 (cfg->stack_usage)) {
3762 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3763 } else {
3764 /* cfg->stack_usage is an int, so we can use
3765 * an addis/addi sequence here even in 64-bit. */
3766 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3767 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3771 ppc_mr (code, ppc_sp, ppc_r12);
3772 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3773 cfg->thunk_area += THUNK_SIZE;
3774 if (cfg->compile_aot) {
3775 /* arch_emit_got_access () patches this */
3776 ppc_load32 (code, ppc_r0, 0);
3777 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3778 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3779 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3780 #else
3781 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3782 #endif
3783 ppc_mtctr (code, ppc_r0);
3784 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3785 } else {
3786 ppc_b (code, 0);
3788 break;
3790 case OP_CHECK_THIS:
3791 /* ensure ins->sreg1 is not NULL */
3792 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3793 break;
3794 case OP_ARGLIST: {
3795 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3796 if (ppc_is_imm16 (cookie_offset)) {
3797 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3798 } else {
3799 ppc_load (code, ppc_r0, cookie_offset);
3800 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3802 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3803 break;
3805 case OP_FCALL:
3806 case OP_LCALL:
3807 case OP_VCALL:
3808 case OP_VCALL2:
3809 case OP_VOIDCALL:
3810 case OP_CALL:
3811 call = (MonoCallInst*)ins;
3812 mono_call_add_patch_info (cfg, call, offset);
3813 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3814 ppc_load_func (code, PPC_CALL_REG, 0);
3815 ppc_mtlr (code, PPC_CALL_REG);
3816 ppc_blrl (code);
3817 } else {
3818 ppc_bl (code, 0);
3820 /* FIXME: this should be handled somewhere else in the new jit */
3821 code = emit_move_return_value (cfg, ins, code);
3822 break;
3823 case OP_FCALL_REG:
3824 case OP_LCALL_REG:
3825 case OP_VCALL_REG:
3826 case OP_VCALL2_REG:
3827 case OP_VOIDCALL_REG:
3828 case OP_CALL_REG:
3829 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3830 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3831 /* FIXME: if we know that this is a method, we
3832 can omit this load */
3833 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3834 ppc_mtlr (code, ppc_r0);
3835 #else
3836 #if (_CALL_ELF == 2)
3837 if (ins->flags & MONO_INST_HAS_METHOD) {
3838 // Not a global entry point
3839 } else {
3840 // Need to set up r12 with function entry address for global entry point
3841 if (ppc_r12 != ins->sreg1) {
3842 ppc_mr(code,ppc_r12,ins->sreg1);
3845 #endif
3846 ppc_mtlr (code, ins->sreg1);
3847 #endif
3848 ppc_blrl (code);
3849 /* FIXME: this should be handled somewhere else in the new jit */
3850 code = emit_move_return_value (cfg, ins, code);
3851 break;
3852 case OP_FCALL_MEMBASE:
3853 case OP_LCALL_MEMBASE:
3854 case OP_VCALL_MEMBASE:
3855 case OP_VCALL2_MEMBASE:
3856 case OP_VOIDCALL_MEMBASE:
3857 case OP_CALL_MEMBASE:
3858 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3859 /* The trampolines clobber this */
3860 ppc_mr (code, ppc_r29, ins->sreg1);
3861 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3862 } else {
3863 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3865 ppc_mtlr (code, ppc_r0);
3866 ppc_blrl (code);
3867 /* FIXME: this should be handled somewhere else in the new jit */
3868 code = emit_move_return_value (cfg, ins, code);
3869 break;
3870 case OP_LOCALLOC: {
3871 guint8 * zero_loop_jump, * zero_loop_start;
3872 /* keep alignment */
3873 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3874 int area_offset = alloca_waste;
3875 area_offset &= ~31;
3876 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
3877 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3878 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
3879 /* use ctr to store the number of words to 0 if needed */
3880 if (ins->flags & MONO_INST_INIT) {
3881 /* we zero 4 bytes at a time:
3882 * we add 7 instead of 3 so that we set the counter to
3883 * at least 1, otherwise the bdnz instruction will make
3884 * it negative and iterate billions of times.
3886 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3887 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3888 ppc_mtctr (code, ppc_r0);
3890 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3891 ppc_neg (code, ppc_r12, ppc_r12);
3892 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3894 /* FIXME: make this loop work in 8 byte
3895 increments on PPC64 */
3896 if (ins->flags & MONO_INST_INIT) {
3897 /* adjust the dest reg by -4 so we can use stwu */
3898 /* we actually adjust -8 because we let the loop
3899 * run at least once
3901 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3902 ppc_li (code, ppc_r12, 0);
3903 zero_loop_start = code;
3904 ppc_stwu (code, ppc_r12, 4, ins->dreg);
3905 zero_loop_jump = code;
3906 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3907 ppc_patch (zero_loop_jump, zero_loop_start);
3909 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3910 break;
3912 case OP_THROW: {
3913 //ppc_break (code);
3914 ppc_mr (code, ppc_r3, ins->sreg1);
3915 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_throw_exception));
3916 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3917 ppc_load_func (code, PPC_CALL_REG, 0);
3918 ppc_mtlr (code, PPC_CALL_REG);
3919 ppc_blrl (code);
3920 } else {
3921 ppc_bl (code, 0);
3923 break;
3925 case OP_RETHROW: {
3926 //ppc_break (code);
3927 ppc_mr (code, ppc_r3, ins->sreg1);
3928 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
3929 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_arch_rethrow_exception));
3930 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3931 ppc_load_func (code, PPC_CALL_REG, 0);
3932 ppc_mtlr (code, PPC_CALL_REG);
3933 ppc_blrl (code);
3934 } else {
3935 ppc_bl (code, 0);
3937 break;
3939 case OP_START_HANDLER: {
3940 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3941 g_assert (spvar->inst_basereg != ppc_sp);
3942 code = emit_reserve_param_area (cfg, code);
3943 ppc_mflr (code, ppc_r0);
3944 if (ppc_is_imm16 (spvar->inst_offset)) {
3945 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3946 } else {
3947 ppc_load (code, ppc_r12, spvar->inst_offset);
3948 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
3950 break;
3952 case OP_ENDFILTER: {
3953 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3954 g_assert (spvar->inst_basereg != ppc_sp);
3955 code = emit_unreserve_param_area (cfg, code);
3956 if (ins->sreg1 != ppc_r3)
3957 ppc_mr (code, ppc_r3, ins->sreg1);
3958 if (ppc_is_imm16 (spvar->inst_offset)) {
3959 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3960 } else {
3961 ppc_load (code, ppc_r12, spvar->inst_offset);
3962 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
3964 ppc_mtlr (code, ppc_r0);
3965 ppc_blr (code);
3966 break;
3968 case OP_ENDFINALLY: {
3969 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3970 g_assert (spvar->inst_basereg != ppc_sp);
3971 code = emit_unreserve_param_area (cfg, code);
3972 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3973 ppc_mtlr (code, ppc_r0);
3974 ppc_blr (code);
3975 break;
3977 case OP_CALL_HANDLER:
3978 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3979 ppc_bl (code, 0);
3980 for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
3981 mono_cfg_add_try_hole (cfg, ((MonoLeaveClause *) tmp->data)->clause, code, bb);
3982 break;
3983 case OP_LABEL:
3984 ins->inst_c0 = code - cfg->native_code;
3985 break;
3986 case OP_BR:
3987 /*if (ins->inst_target_bb->native_offset) {
3988 ppc_b (code, 0);
3989 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3990 } else*/ {
3991 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3992 ppc_b (code, 0);
3994 break;
3995 case OP_BR_REG:
3996 ppc_mtctr (code, ins->sreg1);
3997 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3998 break;
3999 case OP_ICNEQ:
4000 ppc_li (code, ins->dreg, 0);
4001 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 2);
4002 ppc_li (code, ins->dreg, 1);
4003 break;
4004 case OP_CEQ:
4005 case OP_ICEQ:
4006 CASE_PPC64 (OP_LCEQ)
4007 ppc_li (code, ins->dreg, 0);
4008 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4009 ppc_li (code, ins->dreg, 1);
4010 break;
4011 case OP_CLT:
4012 case OP_CLT_UN:
4013 case OP_ICLT:
4014 case OP_ICLT_UN:
4015 CASE_PPC64 (OP_LCLT)
4016 CASE_PPC64 (OP_LCLT_UN)
4017 ppc_li (code, ins->dreg, 1);
4018 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4019 ppc_li (code, ins->dreg, 0);
4020 break;
4021 case OP_ICGE:
4022 case OP_ICGE_UN:
4023 ppc_li (code, ins->dreg, 1);
4024 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 2);
4025 ppc_li (code, ins->dreg, 0);
4026 break;
4027 case OP_CGT:
4028 case OP_CGT_UN:
4029 case OP_ICGT:
4030 case OP_ICGT_UN:
4031 CASE_PPC64 (OP_LCGT)
4032 CASE_PPC64 (OP_LCGT_UN)
4033 ppc_li (code, ins->dreg, 1);
4034 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4035 ppc_li (code, ins->dreg, 0);
4036 break;
4037 case OP_ICLE:
4038 case OP_ICLE_UN:
4039 ppc_li (code, ins->dreg, 1);
4040 ppc_bc (code, PPC_BR_FALSE, PPC_BR_GT, 2);
4041 ppc_li (code, ins->dreg, 0);
4042 break;
4043 case OP_COND_EXC_EQ:
4044 case OP_COND_EXC_NE_UN:
4045 case OP_COND_EXC_LT:
4046 case OP_COND_EXC_LT_UN:
4047 case OP_COND_EXC_GT:
4048 case OP_COND_EXC_GT_UN:
4049 case OP_COND_EXC_GE:
4050 case OP_COND_EXC_GE_UN:
4051 case OP_COND_EXC_LE:
4052 case OP_COND_EXC_LE_UN:
4053 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, (const char*)ins->inst_p1);
4054 break;
4055 case OP_COND_EXC_IEQ:
4056 case OP_COND_EXC_INE_UN:
4057 case OP_COND_EXC_ILT:
4058 case OP_COND_EXC_ILT_UN:
4059 case OP_COND_EXC_IGT:
4060 case OP_COND_EXC_IGT_UN:
4061 case OP_COND_EXC_IGE:
4062 case OP_COND_EXC_IGE_UN:
4063 case OP_COND_EXC_ILE:
4064 case OP_COND_EXC_ILE_UN:
4065 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, (const char*)ins->inst_p1);
4066 break;
4067 case OP_IBEQ:
4068 case OP_IBNE_UN:
4069 case OP_IBLT:
4070 case OP_IBLT_UN:
4071 case OP_IBGT:
4072 case OP_IBGT_UN:
4073 case OP_IBGE:
4074 case OP_IBGE_UN:
4075 case OP_IBLE:
4076 case OP_IBLE_UN:
4077 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4078 break;
4080 /* floating point opcodes */
4081 case OP_R8CONST:
4082 g_assert (cfg->compile_aot);
4084 /* FIXME: Optimize this */
4085 ppc_bl (code, 1);
4086 ppc_mflr (code, ppc_r12);
4087 ppc_b (code, 3);
4088 *(double*)code = *(double*)ins->inst_p0;
4089 code += 8;
4090 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4091 break;
4092 case OP_R4CONST:
4093 g_assert_not_reached ();
4094 break;
4095 case OP_STORER8_MEMBASE_REG:
4096 if (ppc_is_imm16 (ins->inst_offset)) {
4097 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4098 } else {
4099 if (ppc_is_imm32 (ins->inst_offset)) {
4100 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4101 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4102 } else {
4103 ppc_load (code, ppc_r0, ins->inst_offset);
4104 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4107 break;
4108 case OP_LOADR8_MEMBASE:
4109 if (ppc_is_imm16 (ins->inst_offset)) {
4110 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4111 } else {
4112 if (ppc_is_imm32 (ins->inst_offset)) {
4113 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4114 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4115 } else {
4116 ppc_load (code, ppc_r0, ins->inst_offset);
4117 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4120 break;
4121 case OP_STORER4_MEMBASE_REG:
4122 ppc_frsp (code, ins->sreg1, ins->sreg1);
4123 if (ppc_is_imm16 (ins->inst_offset)) {
4124 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4125 } else {
4126 if (ppc_is_imm32 (ins->inst_offset)) {
4127 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4128 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4129 } else {
4130 ppc_load (code, ppc_r0, ins->inst_offset);
4131 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4134 break;
4135 case OP_LOADR4_MEMBASE:
4136 if (ppc_is_imm16 (ins->inst_offset)) {
4137 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4138 } else {
4139 if (ppc_is_imm32 (ins->inst_offset)) {
4140 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4141 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4142 } else {
4143 ppc_load (code, ppc_r0, ins->inst_offset);
4144 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4147 break;
4148 case OP_LOADR4_MEMINDEX:
4149 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4150 break;
4151 case OP_LOADR8_MEMINDEX:
4152 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4153 break;
4154 case OP_STORER4_MEMINDEX:
4155 ppc_frsp (code, ins->sreg1, ins->sreg1);
4156 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4157 break;
4158 case OP_STORER8_MEMINDEX:
4159 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4160 break;
4161 case CEE_CONV_R_UN:
4162 case CEE_CONV_R4: /* FIXME: change precision */
4163 case CEE_CONV_R8:
4164 g_assert_not_reached ();
4165 case OP_FCONV_TO_I1:
4166 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4167 break;
4168 case OP_FCONV_TO_U1:
4169 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4170 break;
4171 case OP_FCONV_TO_I2:
4172 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4173 break;
4174 case OP_FCONV_TO_U2:
4175 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4176 break;
4177 case OP_FCONV_TO_I4:
4178 case OP_FCONV_TO_I:
4179 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4180 break;
4181 case OP_FCONV_TO_U4:
4182 case OP_FCONV_TO_U:
4183 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4184 break;
4185 case OP_LCONV_TO_R_UN:
4186 g_assert_not_reached ();
4187 /* Implemented as helper calls */
4188 break;
4189 case OP_LCONV_TO_OVF_I4_2:
4190 case OP_LCONV_TO_OVF_I: {
4191 #ifdef __mono_ppc64__
4192 NOT_IMPLEMENTED;
4193 #else
4194 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4195 // Check if its negative
4196 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4197 negative_branch = code;
4198 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4199 // Its positive msword == 0
4200 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4201 msword_positive_branch = code;
4202 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4204 ovf_ex_target = code;
4205 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4206 // Negative
4207 ppc_patch (negative_branch, code);
4208 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4209 msword_negative_branch = code;
4210 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4211 ppc_patch (msword_negative_branch, ovf_ex_target);
4213 ppc_patch (msword_positive_branch, code);
4214 if (ins->dreg != ins->sreg1)
4215 ppc_mr (code, ins->dreg, ins->sreg1);
4216 break;
4217 #endif
4219 case OP_ROUND:
4220 ppc_frind (code, ins->dreg, ins->sreg1);
4221 break;
4222 case OP_PPC_TRUNC:
4223 ppc_frizd (code, ins->dreg, ins->sreg1);
4224 break;
4225 case OP_PPC_CEIL:
4226 ppc_fripd (code, ins->dreg, ins->sreg1);
4227 break;
4228 case OP_PPC_FLOOR:
4229 ppc_frimd (code, ins->dreg, ins->sreg1);
4230 break;
4231 case OP_ABS:
4232 ppc_fabsd (code, ins->dreg, ins->sreg1);
4233 break;
4234 case OP_SQRTF:
4235 ppc_fsqrtsd (code, ins->dreg, ins->sreg1);
4236 break;
4237 case OP_SQRT:
4238 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4239 break;
4240 case OP_FADD:
4241 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4242 break;
4243 case OP_FSUB:
4244 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4245 break;
4246 case OP_FMUL:
4247 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4248 break;
4249 case OP_FDIV:
4250 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4251 break;
4252 case OP_FNEG:
4253 ppc_fneg (code, ins->dreg, ins->sreg1);
4254 break;
4255 case OP_FREM:
4256 /* emulated */
4257 g_assert_not_reached ();
4258 break;
4259 /* These min/max require POWER5 */
4260 case OP_IMIN:
4261 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
4262 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4263 break;
4264 case OP_IMIN_UN:
4265 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
4266 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4267 break;
4268 case OP_IMAX:
4269 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
4270 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4271 break;
4272 case OP_IMAX_UN:
4273 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
4274 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4275 break;
4276 CASE_PPC64 (OP_LMIN)
4277 ppc_cmp (code, 0, 1, ins->sreg1, ins->sreg2);
4278 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4279 break;
4280 CASE_PPC64 (OP_LMIN_UN)
4281 ppc_cmpl (code, 0, 1, ins->sreg1, ins->sreg2);
4282 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4283 break;
4284 CASE_PPC64 (OP_LMAX)
4285 ppc_cmp (code, 0, 1, ins->sreg1, ins->sreg2);
4286 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4287 break;
4288 CASE_PPC64 (OP_LMAX_UN)
4289 ppc_cmpl (code, 0, 1, ins->sreg1, ins->sreg2);
4290 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4291 break;
4292 case OP_FCOMPARE:
4293 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4294 break;
4295 case OP_FCEQ:
4296 case OP_FCNEQ:
4297 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4298 ppc_li (code, ins->dreg, 1);
4299 ppc_bc (code, ins->opcode == OP_FCEQ ? PPC_BR_TRUE : PPC_BR_FALSE, PPC_BR_EQ, 2);
4300 ppc_li (code, ins->dreg, 0);
4301 break;
4302 case OP_FCLT:
4303 case OP_FCGE:
4304 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4305 ppc_li (code, ins->dreg, 1);
4306 ppc_bc (code, ins->opcode == OP_FCLT ? PPC_BR_TRUE : PPC_BR_FALSE, PPC_BR_LT, 2);
4307 ppc_li (code, ins->dreg, 0);
4308 break;
4309 case OP_FCLT_UN:
4310 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4311 ppc_li (code, ins->dreg, 1);
4312 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4313 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4314 ppc_li (code, ins->dreg, 0);
4315 break;
4316 case OP_FCGT:
4317 case OP_FCLE:
4318 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4319 ppc_li (code, ins->dreg, 1);
4320 ppc_bc (code, ins->opcode == OP_FCGT ? PPC_BR_TRUE : PPC_BR_FALSE, PPC_BR_GT, 2);
4321 ppc_li (code, ins->dreg, 0);
4322 break;
4323 case OP_FCGT_UN:
4324 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4325 ppc_li (code, ins->dreg, 1);
4326 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4327 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4328 ppc_li (code, ins->dreg, 0);
4329 break;
4330 case OP_FBEQ:
4331 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4332 break;
4333 case OP_FBNE_UN:
4334 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4335 break;
4336 case OP_FBLT:
4337 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4338 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4339 break;
4340 case OP_FBLT_UN:
4341 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4342 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4343 break;
4344 case OP_FBGT:
4345 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4346 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4347 break;
4348 case OP_FBGT_UN:
4349 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4350 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4351 break;
4352 case OP_FBGE:
4353 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4354 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4355 break;
4356 case OP_FBGE_UN:
4357 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4358 break;
4359 case OP_FBLE:
4360 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4361 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4362 break;
4363 case OP_FBLE_UN:
4364 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4365 break;
4366 case OP_CKFINITE:
4367 g_assert_not_reached ();
4368 case OP_PPC_CHECK_FINITE: {
4369 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4370 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4371 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4372 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4373 break;
4374 case OP_JUMP_TABLE:
4375 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4376 #ifdef __mono_ppc64__
4377 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4378 #else
4379 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4380 #endif
4381 break;
4384 #ifdef __mono_ppc64__
4385 case OP_ICONV_TO_I4:
4386 case OP_SEXT_I4:
4387 ppc_extsw (code, ins->dreg, ins->sreg1);
4388 break;
4389 case OP_ICONV_TO_U4:
4390 case OP_ZEXT_I4:
4391 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4392 break;
4393 case OP_ICONV_TO_R4:
4394 case OP_ICONV_TO_R8:
4395 case OP_LCONV_TO_R4:
4396 case OP_LCONV_TO_R8: {
4397 int tmp;
4398 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4399 ppc_extsw (code, ppc_r0, ins->sreg1);
4400 tmp = ppc_r0;
4401 } else {
4402 tmp = ins->sreg1;
4404 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4405 ppc_mffgpr (code, ins->dreg, tmp);
4406 } else {
4407 ppc_str (code, tmp, -8, ppc_r1);
4408 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4410 ppc_fcfid (code, ins->dreg, ins->dreg);
4411 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4412 ppc_frsp (code, ins->dreg, ins->dreg);
4413 break;
4415 case OP_LSHR:
4416 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4417 break;
4418 case OP_LSHR_UN:
4419 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4420 break;
4421 case OP_COND_EXC_C:
4422 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4424 ppc_mfspr (code, ppc_r0, ppc_xer);
4425 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4426 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, (const char*)ins->inst_p1);
4427 break;
4428 case OP_COND_EXC_OV:
4429 ppc_mfspr (code, ppc_r0, ppc_xer);
4430 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4431 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, (const char*)ins->inst_p1);
4432 break;
4433 case OP_LBEQ:
4434 case OP_LBNE_UN:
4435 case OP_LBLT:
4436 case OP_LBLT_UN:
4437 case OP_LBGT:
4438 case OP_LBGT_UN:
4439 case OP_LBGE:
4440 case OP_LBGE_UN:
4441 case OP_LBLE:
4442 case OP_LBLE_UN:
4443 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4444 break;
4445 case OP_FCONV_TO_I8:
4446 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4447 break;
4448 case OP_FCONV_TO_U8:
4449 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4450 break;
4451 case OP_STOREI4_MEMBASE_REG:
4452 if (ppc_is_imm16 (ins->inst_offset)) {
4453 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4454 } else {
4455 ppc_load (code, ppc_r0, ins->inst_offset);
4456 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4458 break;
4459 case OP_STOREI4_MEMINDEX:
4460 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4461 break;
4462 case OP_ISHR_IMM:
4463 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4464 break;
4465 case OP_ISHR_UN_IMM:
4466 if (ins->inst_imm & 0x1f)
4467 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4468 else
4469 ppc_mr (code, ins->dreg, ins->sreg1);
4470 break;
4471 #else
4472 case OP_ICONV_TO_R4:
4473 case OP_ICONV_TO_R8: {
4474 if (cpu_hw_caps & PPC_ISA_64) {
4475 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4476 ppc_stw (code, ppc_r0, -8, ppc_r1);
4477 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4478 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4479 ppc_fcfid (code, ins->dreg, ins->dreg);
4480 if (ins->opcode == OP_ICONV_TO_R4)
4481 ppc_frsp (code, ins->dreg, ins->dreg);
4483 break;
4485 #endif
4487 case OP_ATOMIC_ADD_I4:
4488 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4489 int location = ins->inst_basereg;
4490 int addend = ins->sreg2;
4491 guint8 *loop, *branch;
4492 g_assert (ins->inst_offset == 0);
4494 loop = code;
4495 ppc_sync (code);
4496 if (ins->opcode == OP_ATOMIC_ADD_I4)
4497 ppc_lwarx (code, ppc_r0, 0, location);
4498 #ifdef __mono_ppc64__
4499 else
4500 ppc_ldarx (code, ppc_r0, 0, location);
4501 #endif
4503 ppc_add (code, ppc_r0, ppc_r0, addend);
4505 if (ins->opcode == OP_ATOMIC_ADD_I4)
4506 ppc_stwcxd (code, ppc_r0, 0, location);
4507 #ifdef __mono_ppc64__
4508 else
4509 ppc_stdcxd (code, ppc_r0, 0, location);
4510 #endif
4512 branch = code;
4513 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4514 ppc_patch (branch, loop);
4516 ppc_sync (code);
4517 ppc_mr (code, ins->dreg, ppc_r0);
4518 break;
4520 case OP_ATOMIC_CAS_I4:
4521 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4522 int location = ins->sreg1;
4523 int value = ins->sreg2;
4524 int comparand = ins->sreg3;
4525 guint8 *start, *not_equal, *lost_reservation;
4527 start = code;
4528 ppc_sync (code);
4529 if (ins->opcode == OP_ATOMIC_CAS_I4)
4530 ppc_lwarx (code, ppc_r0, 0, location);
4531 #ifdef __mono_ppc64__
4532 else
4533 ppc_ldarx (code, ppc_r0, 0, location);
4534 #endif
4536 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4537 not_equal = code;
4538 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4540 if (ins->opcode == OP_ATOMIC_CAS_I4)
4541 ppc_stwcxd (code, value, 0, location);
4542 #ifdef __mono_ppc64__
4543 else
4544 ppc_stdcxd (code, value, 0, location);
4545 #endif
4547 lost_reservation = code;
4548 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4549 ppc_patch (lost_reservation, start);
4550 ppc_patch (not_equal, code);
4552 ppc_sync (code);
4553 ppc_mr (code, ins->dreg, ppc_r0);
4554 break;
4556 case OP_LIVERANGE_START: {
4557 if (cfg->verbose_level > 1)
4558 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4559 MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4560 break;
4562 case OP_LIVERANGE_END: {
4563 if (cfg->verbose_level > 1)
4564 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4565 MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4566 break;
4568 case OP_GC_SAFE_POINT:
4569 break;
4571 default:
4572 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4573 g_assert_not_reached ();
4576 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4577 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4578 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4579 g_assert_not_reached ();
4582 cpos += max_len;
4584 last_ins = ins;
4587 set_code_cursor (cfg, code);
4589 #endif /* !DISABLE_JIT */
4591 void
4592 mono_arch_register_lowlevel_calls (void)
4594 /* The signature doesn't matter */
4595 mono_register_jit_icall (mono_ppc_throw_exception, mono_icall_sig_void, TRUE);
4598 #ifdef __mono_ppc64__
4599 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4600 #define patch_load_sequence(ip,val) do {\
4601 guint16 *__load = (guint16*)(ip); \
4602 g_assert (sizeof (val) == sizeof (gsize)); \
4603 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4604 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4605 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4606 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4607 } while (0)
4608 #elif G_BYTE_ORDER == G_BIG_ENDIAN
4609 #define patch_load_sequence(ip,val) do {\
4610 guint16 *__load = (guint16*)(ip); \
4611 g_assert (sizeof (val) == sizeof (gsize)); \
4612 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4613 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4614 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4615 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4616 } while (0)
4617 #else
4618 #error huh? No endianess defined by compiler
4619 #endif
4620 #else
4621 #define patch_load_sequence(ip,val) do {\
4622 guint16 *__lis_ori = (guint16*)(ip); \
4623 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4624 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4625 } while (0)
4626 #endif
4628 #ifndef DISABLE_JIT
4629 void
4630 mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
4632 unsigned char *ip = ji->ip.i + code;
4633 gboolean is_fd = FALSE;
4635 switch (ji->type) {
4636 case MONO_PATCH_INFO_IP:
4637 patch_load_sequence (ip, ip);
4638 break;
4639 case MONO_PATCH_INFO_SWITCH: {
4640 gpointer *table = (gpointer *)ji->data.table->table;
4641 int i;
4643 patch_load_sequence (ip, table);
4645 for (i = 0; i < ji->data.table->table_size; i++) {
4646 table [i] = (glong)ji->data.table->table [i] + code;
4648 /* we put into the table the absolute address, no need for ppc_patch in this case */
4649 break;
4651 case MONO_PATCH_INFO_METHODCONST:
4652 case MONO_PATCH_INFO_CLASS:
4653 case MONO_PATCH_INFO_IMAGE:
4654 case MONO_PATCH_INFO_FIELD:
4655 case MONO_PATCH_INFO_VTABLE:
4656 case MONO_PATCH_INFO_IID:
4657 case MONO_PATCH_INFO_SFLDA:
4658 case MONO_PATCH_INFO_LDSTR:
4659 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4660 case MONO_PATCH_INFO_LDTOKEN:
4661 /* from OP_AOTCONST : lis + ori */
4662 patch_load_sequence (ip, target);
4663 break;
4664 case MONO_PATCH_INFO_R4:
4665 case MONO_PATCH_INFO_R8:
4666 g_assert_not_reached ();
4667 *((gconstpointer *)(ip + 2)) = ji->data.target;
4668 break;
4669 case MONO_PATCH_INFO_EXC_NAME:
4670 g_assert_not_reached ();
4671 *((gconstpointer *)(ip + 1)) = ji->data.name;
4672 break;
4673 case MONO_PATCH_INFO_NONE:
4674 case MONO_PATCH_INFO_BB_OVF:
4675 case MONO_PATCH_INFO_EXC_OVF:
4676 /* everything is dealt with at epilog output time */
4677 break;
4678 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4679 case MONO_PATCH_INFO_JIT_ICALL_ID:
4680 case MONO_PATCH_INFO_ABS:
4681 case MONO_PATCH_INFO_RGCTX_FETCH:
4682 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4683 case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
4684 is_fd = TRUE;
4685 /* fall through */
4686 #endif
4687 default:
4688 ppc_patch_full (cfg, domain, ip, (const guchar*)target, is_fd);
4689 break;
4694 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4695 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4696 * the instruction offset immediate for all the registers.
4698 static guint8*
4699 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4701 int i;
4702 if (!save_lmf) {
4703 for (i = 13; i <= 31; i++) {
4704 if (used_int_regs & (1 << i)) {
4705 ppc_str (code, i, pos, base_reg);
4706 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4707 pos += sizeof (target_mgreg_t);
4710 } else {
4711 /* pos is the start of the MonoLMF structure */
4712 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4713 for (i = 13; i <= 31; i++) {
4714 ppc_str (code, i, offset, base_reg);
4715 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4716 offset += sizeof (target_mgreg_t);
4718 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4719 for (i = 14; i < 32; i++) {
4720 ppc_stfd (code, i, offset, base_reg);
4721 offset += sizeof (gdouble);
4724 return code;
4728 * Stack frame layout:
4730 * ------------------- sp
4731 * MonoLMF structure or saved registers
4732 * -------------------
4733 * spilled regs
4734 * -------------------
4735 * locals
4736 * -------------------
4737 * param area size is cfg->param_area
4738 * -------------------
4739 * linkage area size is PPC_STACK_PARAM_OFFSET
4740 * ------------------- sp
4741 * red zone
4743 guint8 *
4744 mono_arch_emit_prolog (MonoCompile *cfg)
4746 MonoMethod *method = cfg->method;
4747 MonoBasicBlock *bb;
4748 MonoMethodSignature *sig;
4749 MonoInst *inst;
4750 long alloc_size, pos, max_offset, cfa_offset;
4751 int i;
4752 guint8 *code;
4753 CallInfo *cinfo;
4754 int lmf_offset = 0;
4755 int tailcall_struct_index;
4757 sig = mono_method_signature_internal (method);
4758 cfg->code_size = 512 + sig->param_count * 32;
4759 code = cfg->native_code = g_malloc (cfg->code_size);
4761 cfa_offset = 0;
4763 /* We currently emit unwind info for aot, but don't use it */
4764 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4766 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4767 ppc_mflr (code, ppc_r0);
4768 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4769 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4772 alloc_size = cfg->stack_offset;
4773 pos = 0;
4775 if (!method->save_lmf) {
4776 for (i = 31; i >= 13; --i) {
4777 if (cfg->used_int_regs & (1 << i)) {
4778 pos += sizeof (target_mgreg_t);
4781 } else {
4782 pos += sizeof (MonoLMF);
4783 lmf_offset = pos;
4785 alloc_size += pos;
4786 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4787 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4788 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4789 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4792 cfg->stack_usage = alloc_size;
4793 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4794 if (alloc_size) {
4795 if (ppc_is_imm16 (-alloc_size)) {
4796 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4797 cfa_offset = alloc_size;
4798 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4799 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4800 } else {
4801 if (pos)
4802 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4803 ppc_load (code, ppc_r0, -alloc_size);
4804 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4805 cfa_offset = alloc_size;
4806 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4807 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4810 if (cfg->frame_reg != ppc_sp) {
4811 ppc_mr (code, cfg->frame_reg, ppc_sp);
4812 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4815 /* store runtime generic context */
4816 if (cfg->rgctx_var) {
4817 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4818 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4820 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4823 /* compute max_offset in order to use short forward jumps
4824 * we always do it on ppc because the immediate displacement
4825 * for jumps is too small
4827 max_offset = 0;
4828 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4829 MonoInst *ins;
4830 bb->max_offset = max_offset;
4832 MONO_BB_FOR_EACH_INS (bb, ins)
4833 max_offset += ins_get_size (ins->opcode);
4836 /* load arguments allocated to register from the stack */
4837 pos = 0;
4839 cinfo = get_call_info (sig);
4841 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4842 ArgInfo *ainfo = &cinfo->ret;
4844 inst = cfg->vret_addr;
4845 g_assert (inst);
4847 if (ppc_is_imm16 (inst->inst_offset)) {
4848 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4849 } else {
4850 ppc_load (code, ppc_r12, inst->inst_offset);
4851 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4855 tailcall_struct_index = 0;
4856 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4857 ArgInfo *ainfo = cinfo->args + i;
4858 inst = cfg->args [pos];
4860 if (cfg->verbose_level > 2)
4861 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4862 if (inst->opcode == OP_REGVAR) {
4863 if (ainfo->regtype == RegTypeGeneral)
4864 ppc_mr (code, inst->dreg, ainfo->reg);
4865 else if (ainfo->regtype == RegTypeFP)
4866 ppc_fmr (code, inst->dreg, ainfo->reg);
4867 else if (ainfo->regtype == RegTypeBase) {
4868 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4869 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4870 } else
4871 g_assert_not_reached ();
4873 if (cfg->verbose_level > 2)
4874 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4875 } else {
4876 /* the argument should be put on the stack: FIXME handle size != word */
4877 if (ainfo->regtype == RegTypeGeneral) {
4878 switch (ainfo->size) {
4879 case 1:
4880 if (ppc_is_imm16 (inst->inst_offset)) {
4881 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4882 } else {
4883 if (ppc_is_imm32 (inst->inst_offset)) {
4884 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4885 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4886 } else {
4887 ppc_load (code, ppc_r12, inst->inst_offset);
4888 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4891 break;
4892 case 2:
4893 if (ppc_is_imm16 (inst->inst_offset)) {
4894 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4895 } else {
4896 if (ppc_is_imm32 (inst->inst_offset)) {
4897 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4898 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4899 } else {
4900 ppc_load (code, ppc_r12, inst->inst_offset);
4901 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4904 break;
4905 #ifdef __mono_ppc64__
4906 case 4:
4907 if (ppc_is_imm16 (inst->inst_offset)) {
4908 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4909 } else {
4910 if (ppc_is_imm32 (inst->inst_offset)) {
4911 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4912 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
4913 } else {
4914 ppc_load (code, ppc_r12, inst->inst_offset);
4915 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4918 break;
4919 case 8:
4920 if (ppc_is_imm16 (inst->inst_offset)) {
4921 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4922 } else {
4923 ppc_load (code, ppc_r12, inst->inst_offset);
4924 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4926 break;
4927 #else
4928 case 8:
4929 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4930 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4931 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4932 } else {
4933 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4934 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4935 ppc_stw (code, ainfo->reg, 0, ppc_r12);
4936 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
4938 break;
4939 #endif
4940 default:
4941 if (ppc_is_imm16 (inst->inst_offset)) {
4942 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4943 } else {
4944 if (ppc_is_imm32 (inst->inst_offset)) {
4945 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4946 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
4947 } else {
4948 ppc_load (code, ppc_r12, inst->inst_offset);
4949 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4952 break;
4954 } else if (ainfo->regtype == RegTypeBase) {
4955 g_assert (ppc_is_imm16 (ainfo->offset));
4956 /* load the previous stack pointer in r12 */
4957 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4958 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
4959 switch (ainfo->size) {
4960 case 1:
4961 if (ppc_is_imm16 (inst->inst_offset)) {
4962 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4963 } else {
4964 if (ppc_is_imm32 (inst->inst_offset)) {
4965 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4966 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
4967 } else {
4968 ppc_load (code, ppc_r12, inst->inst_offset);
4969 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4972 break;
4973 case 2:
4974 if (ppc_is_imm16 (inst->inst_offset)) {
4975 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4976 } else {
4977 if (ppc_is_imm32 (inst->inst_offset)) {
4978 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4979 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
4980 } else {
4981 ppc_load (code, ppc_r12, inst->inst_offset);
4982 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4985 break;
4986 #ifdef __mono_ppc64__
4987 case 4:
4988 if (ppc_is_imm16 (inst->inst_offset)) {
4989 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4990 } else {
4991 if (ppc_is_imm32 (inst->inst_offset)) {
4992 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4993 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
4994 } else {
4995 ppc_load (code, ppc_r12, inst->inst_offset);
4996 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4999 break;
5000 case 8:
5001 if (ppc_is_imm16 (inst->inst_offset)) {
5002 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5003 } else {
5004 ppc_load (code, ppc_r12, inst->inst_offset);
5005 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5007 break;
5008 #else
5009 case 8:
5010 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5011 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5012 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5013 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5014 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5015 } else {
5016 /* use r11 to load the 2nd half of the long before we clobber r12. */
5017 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5018 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5019 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5020 ppc_stw (code, ppc_r0, 0, ppc_r12);
5021 ppc_stw (code, ppc_r11, 4, ppc_r12);
5023 break;
5024 #endif
5025 default:
5026 if (ppc_is_imm16 (inst->inst_offset)) {
5027 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5028 } else {
5029 if (ppc_is_imm32 (inst->inst_offset)) {
5030 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5031 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5032 } else {
5033 ppc_load (code, ppc_r12, inst->inst_offset);
5034 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5037 break;
5039 } else if (ainfo->regtype == RegTypeFP) {
5040 g_assert (ppc_is_imm16 (inst->inst_offset));
5041 if (ainfo->size == 8)
5042 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5043 else if (ainfo->size == 4)
5044 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5045 else
5046 g_assert_not_reached ();
5047 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5048 int doffset = inst->inst_offset;
5049 int soffset = 0;
5050 int cur_reg;
5051 int size = 0;
5052 g_assert (ppc_is_imm16 (inst->inst_offset));
5053 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (target_mgreg_t)));
5054 /* FIXME: what if there is no class? */
5055 if (sig->pinvoke && mono_class_from_mono_type_internal (inst->inst_vtype))
5056 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), NULL);
5057 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5058 if (ainfo->size == 4) {
5059 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5060 } else {
5061 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5063 soffset += ainfo->size;
5064 doffset += ainfo->size;
5066 } else if (ainfo->regtype == RegTypeStructByVal) {
5067 int doffset = inst->inst_offset;
5068 int soffset = 0;
5069 int cur_reg;
5070 int size = 0;
5071 g_assert (ppc_is_imm16 (inst->inst_offset));
5072 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (target_mgreg_t)));
5073 /* FIXME: what if there is no class? */
5074 if (sig->pinvoke && mono_class_from_mono_type_internal (inst->inst_vtype))
5075 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), NULL);
5076 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5077 #if __APPLE__
5079 * Darwin handles 1 and 2 byte
5080 * structs specially by
5081 * loading h/b into the arg
5082 * register. Only done for
5083 * pinvokes.
5085 if (size == 2)
5086 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5087 else if (size == 1)
5088 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5089 else
5090 #endif
5092 #ifdef __mono_ppc64__
5093 if (ainfo->bytes) {
5094 g_assert (cur_reg == 0);
5095 #if G_BYTE_ORDER == G_BIG_ENDIAN
5096 ppc_sldi (code, ppc_r0, ainfo->reg,
5097 (sizeof (target_mgreg_t) - ainfo->bytes) * 8);
5098 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5099 #else
5100 if (mono_class_native_size (inst->klass, NULL) == 1) {
5101 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5102 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5103 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5104 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5105 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5106 } else {
5107 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5109 #endif
5110 } else
5111 #endif
5113 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5114 inst->inst_basereg);
5117 soffset += sizeof (target_mgreg_t);
5118 doffset += sizeof (target_mgreg_t);
5120 if (ainfo->vtsize) {
5121 /* FIXME: we need to do the shifting here, too */
5122 if (ainfo->bytes)
5123 NOT_IMPLEMENTED;
5124 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5125 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5126 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5127 code = emit_memcpy (code, size - soffset,
5128 inst->inst_basereg, doffset,
5129 ppc_r12, ainfo->offset + soffset);
5130 } else {
5131 code = emit_memcpy (code, ainfo->vtsize * sizeof (target_mgreg_t),
5132 inst->inst_basereg, doffset,
5133 ppc_r12, ainfo->offset + soffset);
5136 } else if (ainfo->regtype == RegTypeStructByAddr) {
5137 /* if it was originally a RegTypeBase */
5138 if (ainfo->offset) {
5139 /* load the previous stack pointer in r12 */
5140 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5141 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5142 } else {
5143 ppc_mr (code, ppc_r12, ainfo->reg);
5146 g_assert (ppc_is_imm16 (inst->inst_offset));
5147 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5148 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5149 } else
5150 g_assert_not_reached ();
5152 pos++;
5155 if (method->save_lmf) {
5156 if (cfg->compile_aot) {
5157 /* Compute the got address which is needed by the PLT entry */
5158 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5160 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID,
5161 GUINT_TO_POINTER (MONO_JIT_ICALL_mono_tls_get_lmf_addr_extern));
5162 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5163 ppc_load_func (code, PPC_CALL_REG, 0);
5164 ppc_mtlr (code, PPC_CALL_REG);
5165 ppc_blrl (code);
5166 } else {
5167 ppc_bl (code, 0);
5169 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5170 /* lmf_offset is the offset from the previous stack pointer,
5171 * alloc_size is the total stack space allocated, so the offset
5172 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5173 * The pointer to the struct is put in ppc_r12 (new_lmf).
5174 * The callee-saved registers are already in the MonoLMF structure
5176 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5177 /* ppc_r3 is the result from mono_get_lmf_addr () */
5178 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5179 /* new_lmf->previous_lmf = *lmf_addr */
5180 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5181 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5182 /* *(lmf_addr) = r12 */
5183 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5184 /* save method info */
5185 if (cfg->compile_aot)
5186 // FIXME:
5187 ppc_load (code, ppc_r0, 0);
5188 else
5189 ppc_load_ptr (code, ppc_r0, method);
5190 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5191 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5192 /* save the current IP */
5193 if (cfg->compile_aot) {
5194 ppc_bl (code, 1);
5195 ppc_mflr (code, ppc_r0);
5196 } else {
5197 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5198 #ifdef __mono_ppc64__
5199 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5200 #else
5201 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5202 #endif
5204 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5207 set_code_cursor (cfg, code);
5208 g_free (cinfo);
5210 return code;
5213 void
5214 mono_arch_emit_epilog (MonoCompile *cfg)
5216 MonoMethod *method = cfg->method;
5217 int pos, i;
5218 int max_epilog_size = 16 + 20*4;
5219 guint8 *code;
5221 if (cfg->method->save_lmf)
5222 max_epilog_size += 128;
5224 code = realloc_code (cfg, max_epilog_size);
5226 pos = 0;
5228 if (method->save_lmf) {
5229 int lmf_offset;
5230 pos += sizeof (MonoLMF);
5231 lmf_offset = pos;
5232 /* save the frame reg in r8 */
5233 ppc_mr (code, ppc_r8, cfg->frame_reg);
5234 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5235 /* r5 = previous_lmf */
5236 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5237 /* r6 = lmf_addr */
5238 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5239 /* *(lmf_addr) = previous_lmf */
5240 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5241 /* FIXME: speedup: there is no actual need to restore the registers if
5242 * we didn't actually change them (idea from Zoltan).
5244 /* restore iregs */
5245 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5246 /* restore fregs */
5247 /*for (i = 14; i < 32; i++) {
5248 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5250 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5251 /* use the saved copy of the frame reg in r8 */
5252 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5253 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5254 ppc_mtlr (code, ppc_r0);
5256 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5257 } else {
5258 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5259 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5260 if (ppc_is_imm16 (return_offset)) {
5261 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5262 } else {
5263 ppc_load (code, ppc_r12, return_offset);
5264 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5266 ppc_mtlr (code, ppc_r0);
5268 if (ppc_is_imm16 (cfg->stack_usage)) {
5269 int offset = cfg->stack_usage;
5270 for (i = 13; i <= 31; i++) {
5271 if (cfg->used_int_regs & (1 << i))
5272 offset -= sizeof (target_mgreg_t);
5274 if (cfg->frame_reg != ppc_sp)
5275 ppc_mr (code, ppc_r12, cfg->frame_reg);
5276 /* note r31 (possibly the frame register) is restored last */
5277 for (i = 13; i <= 31; i++) {
5278 if (cfg->used_int_regs & (1 << i)) {
5279 ppc_ldr (code, i, offset, cfg->frame_reg);
5280 offset += sizeof (target_mgreg_t);
5283 if (cfg->frame_reg != ppc_sp)
5284 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5285 else
5286 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5287 } else {
5288 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5289 if (cfg->used_int_regs) {
5290 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5291 for (i = 31; i >= 13; --i) {
5292 if (cfg->used_int_regs & (1 << i)) {
5293 pos += sizeof (target_mgreg_t);
5294 ppc_ldr (code, i, -pos, ppc_r12);
5297 ppc_mr (code, ppc_sp, ppc_r12);
5298 } else {
5299 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5303 ppc_blr (code);
5305 set_code_cursor (cfg, code);
5308 #endif /* ifndef DISABLE_JIT */
5310 /* remove once throw_exception_by_name is eliminated */
5311 static int
5312 exception_id_by_name (const char *name)
5314 if (strcmp (name, "IndexOutOfRangeException") == 0)
5315 return MONO_EXC_INDEX_OUT_OF_RANGE;
5316 if (strcmp (name, "OverflowException") == 0)
5317 return MONO_EXC_OVERFLOW;
5318 if (strcmp (name, "ArithmeticException") == 0)
5319 return MONO_EXC_ARITHMETIC;
5320 if (strcmp (name, "DivideByZeroException") == 0)
5321 return MONO_EXC_DIVIDE_BY_ZERO;
5322 if (strcmp (name, "InvalidCastException") == 0)
5323 return MONO_EXC_INVALID_CAST;
5324 if (strcmp (name, "NullReferenceException") == 0)
5325 return MONO_EXC_NULL_REF;
5326 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5327 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5328 if (strcmp (name, "ArgumentException") == 0)
5329 return MONO_EXC_ARGUMENT;
5330 g_error ("Unknown intrinsic exception %s\n", name);
5331 return 0;
5334 #ifndef DISABLE_JIT
5335 void
5336 mono_arch_emit_exceptions (MonoCompile *cfg)
5338 MonoJumpInfo *patch_info;
5339 int i;
5340 guint8 *code;
5341 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5342 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5343 int max_epilog_size = 50;
5345 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5346 exc_throw_pos [i] = NULL;
5347 exc_throw_found [i] = 0;
5350 /* count the number of exception infos */
5353 * make sure we have enough space for exceptions
5355 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5356 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5357 i = exception_id_by_name ((const char*)patch_info->data.target);
5358 if (!exc_throw_found [i]) {
5359 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5360 exc_throw_found [i] = TRUE;
5362 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5363 max_epilog_size += 12;
5364 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5365 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5366 i = exception_id_by_name (ovfj->data.exception);
5367 if (!exc_throw_found [i]) {
5368 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5369 exc_throw_found [i] = TRUE;
5371 max_epilog_size += 8;
5375 code = realloc_code (cfg, max_epilog_size);
5377 /* add code to raise exceptions */
5378 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5379 switch (patch_info->type) {
5380 case MONO_PATCH_INFO_BB_OVF: {
5381 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5382 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5383 /* patch the initial jump */
5384 ppc_patch (ip, code);
5385 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5386 ppc_b (code, 0);
5387 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5388 /* jump back to the true target */
5389 ppc_b (code, 0);
5390 ip = ovfj->data.bb->native_offset + cfg->native_code;
5391 ppc_patch (code - 4, ip);
5392 patch_info->type = MONO_PATCH_INFO_NONE;
5393 break;
5395 case MONO_PATCH_INFO_EXC_OVF: {
5396 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5397 MonoJumpInfo *newji;
5398 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5399 unsigned char *bcl = code;
5400 /* patch the initial jump: we arrived here with a call */
5401 ppc_patch (ip, code);
5402 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5403 ppc_b (code, 0);
5404 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5405 /* patch the conditional jump to the right handler */
5406 /* make it processed next */
5407 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5408 newji->type = MONO_PATCH_INFO_EXC;
5409 newji->ip.i = bcl - cfg->native_code;
5410 newji->data.target = ovfj->data.exception;
5411 newji->next = patch_info->next;
5412 patch_info->next = newji;
5413 patch_info->type = MONO_PATCH_INFO_NONE;
5414 break;
5416 case MONO_PATCH_INFO_EXC: {
5417 MonoClass *exc_class;
5419 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5420 i = exception_id_by_name ((const char*)patch_info->data.target);
5421 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5422 ppc_patch (ip, exc_throw_pos [i]);
5423 patch_info->type = MONO_PATCH_INFO_NONE;
5424 break;
5425 } else {
5426 exc_throw_pos [i] = code;
5429 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5431 ppc_patch (ip, code);
5432 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5433 ppc_load (code, ppc_r3, m_class_get_type_token (exc_class));
5434 /* we got here from a conditional call, so the calling ip is set in lr */
5435 ppc_mflr (code, ppc_r4);
5436 patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ID;
5437 patch_info->data.jit_icall_id = MONO_JIT_ICALL_mono_arch_throw_corlib_exception;
5438 patch_info->ip.i = code - cfg->native_code;
5439 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5440 ppc_load_func (code, PPC_CALL_REG, 0);
5441 ppc_mtctr (code, PPC_CALL_REG);
5442 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5443 } else {
5444 ppc_bl (code, 0);
5446 break;
5448 default:
5449 /* do nothing */
5450 break;
5454 set_code_cursor (cfg, code);
5456 #endif
5458 #if DEAD_CODE
5459 static int
5460 try_offset_access (void *value, guint32 idx)
5462 register void* me __asm__ ("r2");
5463 void ***p = (void***)((char*)me + 284);
5464 int idx1 = idx / 32;
5465 int idx2 = idx % 32;
5466 if (!p [idx1])
5467 return 0;
5468 if (value != p[idx1][idx2])
5469 return 0;
5470 return 1;
5472 #endif
5474 void
5475 mono_arch_finish_init (void)
5479 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5480 #define BR_SIZE 4
5481 #define LOADSTORE_SIZE 4
5482 #define JUMP_IMM_SIZE 12
5483 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5484 #define ENABLE_WRONG_METHOD_CHECK 0
5487 * LOCKING: called with the domain lock held
5489 gpointer
5490 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5491 gpointer fail_tramp)
5493 int i;
5494 int size = 0;
5495 guint8 *code, *start;
5497 for (i = 0; i < count; ++i) {
5498 MonoIMTCheckItem *item = imt_entries [i];
5499 if (item->is_equals) {
5500 if (item->check_target_idx) {
5501 if (!item->compare_done)
5502 item->chunk_size += CMP_SIZE;
5503 if (item->has_target_code)
5504 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5505 else
5506 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5507 } else {
5508 if (fail_tramp) {
5509 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5510 if (!item->has_target_code)
5511 item->chunk_size += LOADSTORE_SIZE;
5512 } else {
5513 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5514 #if ENABLE_WRONG_METHOD_CHECK
5515 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5516 #endif
5519 } else {
5520 item->chunk_size += CMP_SIZE + BR_SIZE;
5521 imt_entries [item->check_target_idx]->compare_done = TRUE;
5523 size += item->chunk_size;
5525 /* the initial load of the vtable address */
5526 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5527 if (fail_tramp) {
5528 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5529 } else {
5530 code = mono_domain_code_reserve (domain, size);
5532 start = code;
5535 * We need to save and restore r12 because it might be
5536 * used by the caller as the vtable register, so
5537 * clobbering it will trip up the magic trampoline.
5539 * FIXME: Get rid of this by making sure that r12 is
5540 * not used as the vtable register in interface calls.
5542 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5543 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5545 for (i = 0; i < count; ++i) {
5546 MonoIMTCheckItem *item = imt_entries [i];
5547 item->code_target = code;
5548 if (item->is_equals) {
5549 if (item->check_target_idx) {
5550 if (!item->compare_done) {
5551 ppc_load (code, ppc_r0, (gsize)item->key);
5552 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5554 item->jmp_code = code;
5555 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5556 if (item->has_target_code) {
5557 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5558 } else {
5559 ppc_ldptr (code, ppc_r0, (sizeof (target_mgreg_t) * item->value.vtable_slot), ppc_r12);
5560 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5562 ppc_mtctr (code, ppc_r0);
5563 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5564 } else {
5565 if (fail_tramp) {
5566 ppc_load (code, ppc_r0, (gulong)item->key);
5567 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5568 item->jmp_code = code;
5569 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5570 if (item->has_target_code) {
5571 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5572 } else {
5573 g_assert (vtable);
5574 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5575 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5577 ppc_mtctr (code, ppc_r0);
5578 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5579 ppc_patch (item->jmp_code, code);
5580 ppc_load_ptr (code, ppc_r0, fail_tramp);
5581 ppc_mtctr (code, ppc_r0);
5582 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5583 item->jmp_code = NULL;
5584 } else {
5585 /* enable the commented code to assert on wrong method */
5586 #if ENABLE_WRONG_METHOD_CHECK
5587 ppc_load (code, ppc_r0, (guint32)item->key);
5588 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5589 item->jmp_code = code;
5590 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5591 #endif
5592 ppc_ldptr (code, ppc_r0, (sizeof (target_mgreg_t) * item->value.vtable_slot), ppc_r12);
5593 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5594 ppc_mtctr (code, ppc_r0);
5595 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5596 #if ENABLE_WRONG_METHOD_CHECK
5597 ppc_patch (item->jmp_code, code);
5598 ppc_break (code);
5599 item->jmp_code = NULL;
5600 #endif
5603 } else {
5604 ppc_load (code, ppc_r0, (gulong)item->key);
5605 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5606 item->jmp_code = code;
5607 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5610 /* patch the branches to get to the target items */
5611 for (i = 0; i < count; ++i) {
5612 MonoIMTCheckItem *item = imt_entries [i];
5613 if (item->jmp_code) {
5614 if (item->check_target_idx) {
5615 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5620 if (!fail_tramp)
5621 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
5622 g_assert (code - start <= size);
5623 mono_arch_flush_icache (start, size);
5624 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
5626 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5628 return start;
5631 MonoMethod*
5632 mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
5634 host_mgreg_t *r = (host_mgreg_t*)regs;
5636 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5639 MonoVTable*
5640 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
5642 return (MonoVTable*)(gsize) regs [MONO_ARCH_RGCTX_REG];
5645 GSList*
5646 mono_arch_get_cie_program (void)
5648 GSList *l = NULL;
5650 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5652 return l;
5655 MonoInst*
5656 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5658 MonoInst *ins = NULL;
5659 int opcode = 0;
5661 if (cmethod->klass == mono_class_try_get_math_class ()) {
5662 if (strcmp (cmethod->name, "Sqrt") == 0) {
5663 opcode = OP_SQRT;
5664 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5665 opcode = OP_ABS;
5668 if (opcode && fsig->param_count == 1) {
5669 MONO_INST_NEW (cfg, ins, opcode);
5670 ins->type = STACK_R8;
5671 ins->dreg = mono_alloc_freg (cfg);
5672 ins->sreg1 = args [0]->dreg;
5673 MONO_ADD_INS (cfg->cbb, ins);
5676 /* Check for Min/Max for (u)int(32|64) */
5677 opcode = 0;
5678 if (cpu_hw_caps & PPC_ISA_2_03) {
5679 if (strcmp (cmethod->name, "Min") == 0) {
5680 if (fsig->params [0]->type == MONO_TYPE_I4)
5681 opcode = OP_IMIN;
5682 if (fsig->params [0]->type == MONO_TYPE_U4)
5683 opcode = OP_IMIN_UN;
5684 #ifdef __mono_ppc64__
5685 else if (fsig->params [0]->type == MONO_TYPE_I8)
5686 opcode = OP_LMIN;
5687 else if (fsig->params [0]->type == MONO_TYPE_U8)
5688 opcode = OP_LMIN_UN;
5689 #endif
5690 } else if (strcmp (cmethod->name, "Max") == 0) {
5691 if (fsig->params [0]->type == MONO_TYPE_I4)
5692 opcode = OP_IMAX;
5693 if (fsig->params [0]->type == MONO_TYPE_U4)
5694 opcode = OP_IMAX_UN;
5695 #ifdef __mono_ppc64__
5696 else if (fsig->params [0]->type == MONO_TYPE_I8)
5697 opcode = OP_LMAX;
5698 else if (fsig->params [0]->type == MONO_TYPE_U8)
5699 opcode = OP_LMAX_UN;
5700 #endif
5703 * TODO: Floating point version with fsel, but fsel has
5704 * some peculiarities (need a scratch reg unless
5705 * comparing with 0, NaN/Inf behaviour (then MathF too)
5709 if (opcode && fsig->param_count == 2) {
5710 MONO_INST_NEW (cfg, ins, opcode);
5711 ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5712 ins->dreg = mono_alloc_ireg (cfg);
5713 ins->sreg1 = args [0]->dreg;
5714 ins->sreg2 = args [1]->dreg;
5715 MONO_ADD_INS (cfg->cbb, ins);
5718 /* Rounding instructions */
5719 opcode = 0;
5720 if ((cpu_hw_caps & PPC_ISA_2X) && (fsig->param_count == 1) && (fsig->params [0]->type == MONO_TYPE_R8)) {
5722 * XXX: sysmath.c and the POWER ISA documentation for
5723 * frin[.] imply rounding is a little more complicated
5724 * than expected; the semantics are slightly different,
5725 * so just "frin." isn't a drop-in replacement. Floor,
5726 * Truncate, and Ceiling seem to work normally though.
5727 * (also, no float versions of these ops, but frsp
5728 * could be preprended?)
5730 //if (!strcmp (cmethod->name, "Round"))
5731 // opcode = OP_ROUND;
5732 if (!strcmp (cmethod->name, "Floor"))
5733 opcode = OP_PPC_FLOOR;
5734 else if (!strcmp (cmethod->name, "Ceiling"))
5735 opcode = OP_PPC_CEIL;
5736 else if (!strcmp (cmethod->name, "Truncate"))
5737 opcode = OP_PPC_TRUNC;
5738 if (opcode != 0) {
5739 MONO_INST_NEW (cfg, ins, opcode);
5740 ins->type = STACK_R8;
5741 ins->dreg = mono_alloc_freg (cfg);
5742 ins->sreg1 = args [0]->dreg;
5743 MONO_ADD_INS (cfg->cbb, ins);
5747 if (cmethod->klass == mono_class_try_get_mathf_class ()) {
5748 if (strcmp (cmethod->name, "Sqrt") == 0) {
5749 opcode = OP_SQRTF;
5750 } /* XXX: POWER has no single-precision normal FPU abs? */
5752 if (opcode && fsig->param_count == 1) {
5753 MONO_INST_NEW (cfg, ins, opcode);
5754 ins->type = STACK_R4;
5755 ins->dreg = mono_alloc_freg (cfg);
5756 ins->sreg1 = args [0]->dreg;
5757 MONO_ADD_INS (cfg->cbb, ins);
5760 return ins;
5763 host_mgreg_t
5764 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5766 if (reg == ppc_r1)
5767 return (host_mgreg_t)(gsize)MONO_CONTEXT_GET_SP (ctx);
5769 return ctx->regs [reg];
5772 guint32
5773 mono_arch_get_patch_offset (guint8 *code)
5775 return 0;
5779 * mono_aot_emit_load_got_addr:
5781 * Emit code to load the got address.
5782 * On PPC, the result is placed into r30.
5784 guint8*
5785 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5787 ppc_bl (code, 1);
5788 ppc_mflr (code, ppc_r30);
5789 if (cfg)
5790 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5791 else
5792 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5793 /* arch_emit_got_address () patches this */
5794 #if defined(TARGET_POWERPC64)
5795 ppc_nop (code);
5796 ppc_nop (code);
5797 ppc_nop (code);
5798 ppc_nop (code);
5799 #else
5800 ppc_load32 (code, ppc_r0, 0);
5801 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5802 #endif
5804 set_code_cursor (cfg, code);
5805 return code;
5809 * mono_ppc_emit_load_aotconst:
5811 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5812 * TARGET from the mscorlib GOT in full-aot code.
5813 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5814 * r12.
5816 guint8*
5817 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
5819 /* Load the mscorlib got address */
5820 ppc_ldptr (code, ppc_r12, sizeof (target_mgreg_t), ppc_r30);
5821 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5822 /* arch_emit_got_access () patches this */
5823 ppc_load32 (code, ppc_r0, 0);
5824 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5826 return code;
5829 /* Soft Debug support */
5830 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5833 * BREAKPOINTS
5837 * mono_arch_set_breakpoint:
5839 * See mini-amd64.c for docs.
5841 void
5842 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5844 guint8 *code = ip;
5845 guint8 *orig_code = code;
5847 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
5848 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
5850 g_assert (code - orig_code == BREAKPOINT_SIZE);
5852 mono_arch_flush_icache (orig_code, code - orig_code);
5856 * mono_arch_clear_breakpoint:
5858 * See mini-amd64.c for docs.
5860 void
5861 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5863 guint8 *code = ip;
5864 int i;
5866 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5867 ppc_nop (code);
5869 mono_arch_flush_icache (ip, code - ip);
5873 * mono_arch_is_breakpoint_event:
5875 * See mini-amd64.c for docs.
5877 gboolean
5878 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5880 siginfo_t* sinfo = (siginfo_t*) info;
5881 /* Sometimes the address is off by 4 */
5882 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5883 return TRUE;
5884 else
5885 return FALSE;
5889 * mono_arch_skip_breakpoint:
5891 * See mini-amd64.c for docs.
5893 void
5894 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5896 /* skip the ldptr */
5897 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5901 * SINGLE STEPPING
5905 * mono_arch_start_single_stepping:
5907 * See mini-amd64.c for docs.
5909 void
5910 mono_arch_start_single_stepping (void)
5912 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5916 * mono_arch_stop_single_stepping:
5918 * See mini-amd64.c for docs.
5920 void
5921 mono_arch_stop_single_stepping (void)
5923 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5927 * mono_arch_is_single_step_event:
5929 * See mini-amd64.c for docs.
5931 gboolean
5932 mono_arch_is_single_step_event (void *info, void *sigctx)
5934 siginfo_t* sinfo = (siginfo_t*) info;
5935 /* Sometimes the address is off by 4 */
5936 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5937 return TRUE;
5938 else
5939 return FALSE;
5943 * mono_arch_skip_single_step:
5945 * See mini-amd64.c for docs.
5947 void
5948 mono_arch_skip_single_step (MonoContext *ctx)
5950 /* skip the ldptr */
5951 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5955 * mono_arch_create_seq_point_info:
5957 * See mini-amd64.c for docs.
5959 SeqPointInfo*
5960 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5962 NOT_IMPLEMENTED;
5963 return NULL;
5966 #endif
5968 gboolean
5969 mono_arch_opcode_supported (int opcode)
5971 switch (opcode) {
5972 case OP_ATOMIC_ADD_I4:
5973 case OP_ATOMIC_CAS_I4:
5974 #ifdef TARGET_POWERPC64
5975 case OP_ATOMIC_ADD_I8:
5976 case OP_ATOMIC_CAS_I8:
5977 #endif
5978 return TRUE;
5979 default:
5980 return FALSE;
5984 gpointer
5985 mono_arch_load_function (MonoJitICallId jit_icall_id)
5987 gpointer target = NULL;
5988 switch (jit_icall_id) {
5989 #undef MONO_AOT_ICALL
5990 #define MONO_AOT_ICALL(x) case MONO_JIT_ICALL_ ## x: target = (gpointer)x; break;
5991 MONO_AOT_ICALL (mono_ppc_throw_exception)
5993 return target;