PPC JIT optimizations (System.Math instruction inlining) (#11964)
[mono-project.git] / mono / mini / mini-ppc.c
blob7e96dce6025740a6b1f95f6cf596d76f74830b6e
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>
24 #include "mini-ppc.h"
25 #ifdef TARGET_POWERPC64
26 #include "cpu-ppc64.h"
27 #else
28 #include "cpu-ppc.h"
29 #endif
30 #include "ir-emit.h"
31 #include "aot-runtime.h"
32 #include "mini-runtime.h"
33 #ifdef __APPLE__
34 #include <sys/sysctl.h>
35 #endif
36 #ifdef __linux__
37 #include <unistd.h>
38 #endif
39 #ifdef _AIX
40 #include <sys/systemcfg.h>
41 #endif
43 static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math")
44 static GENERATE_TRY_GET_CLASS_WITH_CACHE (mathf, "System", "MathF")
46 #define FORCE_INDIR_CALL 1
48 enum {
49 TLS_MODE_DETECT,
50 TLS_MODE_FAILED,
51 TLS_MODE_LTHREADS,
52 TLS_MODE_NPTL,
53 TLS_MODE_DARWIN_G4,
54 TLS_MODE_DARWIN_G5
57 /* cpu_hw_caps contains the flags defined below */
58 static int cpu_hw_caps = 0;
59 static int cachelinesize = 0;
60 static int cachelineinc = 0;
61 enum {
62 PPC_ICACHE_SNOOP = 1 << 0,
63 PPC_MULTIPLE_LS_UNITS = 1 << 1,
64 PPC_SMP_CAPABLE = 1 << 2,
65 PPC_ISA_2X = 1 << 3,
66 PPC_ISA_64 = 1 << 4,
67 PPC_MOVE_FPR_GPR = 1 << 5,
68 PPC_ISA_2_03 = 1 << 6,
69 PPC_HW_CAP_END
72 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
74 /* This mutex protects architecture specific caches */
75 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
76 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
77 static mono_mutex_t mini_arch_mutex;
80 * The code generated for sequence points reads from this location, which is
81 * made read-only when single stepping is enabled.
83 static gpointer ss_trigger_page;
85 /* Enabled breakpoints read from this trigger page */
86 static gpointer bp_trigger_page;
88 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
89 MonoInst *inst; \
90 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
91 inst->type = STACK_R8; \
92 inst->dreg = (dr); \
93 inst->inst_p0 = (void*)(addr); \
94 mono_bblock_add_inst (cfg->cbb, inst); \
95 } while (0)
97 const char*
98 mono_arch_regname (int reg) {
99 static const char rnames[][4] = {
100 "r0", "sp", "r2", "r3", "r4",
101 "r5", "r6", "r7", "r8", "r9",
102 "r10", "r11", "r12", "r13", "r14",
103 "r15", "r16", "r17", "r18", "r19",
104 "r20", "r21", "r22", "r23", "r24",
105 "r25", "r26", "r27", "r28", "r29",
106 "r30", "r31"
108 if (reg >= 0 && reg < 32)
109 return rnames [reg];
110 return "unknown";
113 const char*
114 mono_arch_fregname (int reg) {
115 static const char rnames[][4] = {
116 "f0", "f1", "f2", "f3", "f4",
117 "f5", "f6", "f7", "f8", "f9",
118 "f10", "f11", "f12", "f13", "f14",
119 "f15", "f16", "f17", "f18", "f19",
120 "f20", "f21", "f22", "f23", "f24",
121 "f25", "f26", "f27", "f28", "f29",
122 "f30", "f31"
124 if (reg >= 0 && reg < 32)
125 return rnames [reg];
126 return "unknown";
129 /* this function overwrites r0, r11, r12 */
130 static guint8*
131 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
133 /* unrolled, use the counter in big */
134 if (size > sizeof (target_mgreg_t) * 5) {
135 long shifted = size / TARGET_SIZEOF_VOID_P;
136 guint8 *copy_loop_start, *copy_loop_jump;
138 ppc_load (code, ppc_r0, shifted);
139 ppc_mtctr (code, ppc_r0);
140 //g_assert (sreg == ppc_r12);
141 ppc_addi (code, ppc_r11, dreg, (doffset - sizeof (target_mgreg_t)));
142 ppc_addi (code, ppc_r12, sreg, (soffset - sizeof (target_mgreg_t)));
143 copy_loop_start = code;
144 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (target_mgreg_t), ppc_r12);
145 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (target_mgreg_t), ppc_r11);
146 copy_loop_jump = code;
147 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
148 ppc_patch (copy_loop_jump, copy_loop_start);
149 size -= shifted * sizeof (target_mgreg_t);
150 doffset = soffset = 0;
151 dreg = ppc_r11;
153 #ifdef __mono_ppc64__
154 /* the hardware has multiple load/store units and the move is long
155 enough to use more then one register, then use load/load/store/store
156 to execute 2 instructions per cycle. */
157 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
158 while (size >= 16) {
159 ppc_ldptr (code, ppc_r0, soffset, sreg);
160 ppc_ldptr (code, ppc_r11, soffset+8, sreg);
161 ppc_stptr (code, ppc_r0, doffset, dreg);
162 ppc_stptr (code, ppc_r11, doffset+8, dreg);
163 size -= 16;
164 soffset += 16;
165 doffset += 16;
168 while (size >= 8) {
169 ppc_ldr (code, ppc_r0, soffset, sreg);
170 ppc_str (code, ppc_r0, doffset, dreg);
171 size -= 8;
172 soffset += 8;
173 doffset += 8;
175 #else
176 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
177 while (size >= 8) {
178 ppc_lwz (code, ppc_r0, soffset, sreg);
179 ppc_lwz (code, ppc_r11, soffset+4, sreg);
180 ppc_stw (code, ppc_r0, doffset, dreg);
181 ppc_stw (code, ppc_r11, doffset+4, dreg);
182 size -= 8;
183 soffset += 8;
184 doffset += 8;
187 #endif
188 while (size >= 4) {
189 ppc_lwz (code, ppc_r0, soffset, sreg);
190 ppc_stw (code, ppc_r0, doffset, dreg);
191 size -= 4;
192 soffset += 4;
193 doffset += 4;
195 while (size >= 2) {
196 ppc_lhz (code, ppc_r0, soffset, sreg);
197 ppc_sth (code, ppc_r0, doffset, dreg);
198 size -= 2;
199 soffset += 2;
200 doffset += 2;
202 while (size >= 1) {
203 ppc_lbz (code, ppc_r0, soffset, sreg);
204 ppc_stb (code, ppc_r0, doffset, dreg);
205 size -= 1;
206 soffset += 1;
207 doffset += 1;
209 return code;
213 * mono_arch_get_argument_info:
214 * @csig: a method signature
215 * @param_count: the number of parameters to consider
216 * @arg_info: an array to store the result infos
218 * Gathers information on parameters such as size, alignment and
219 * padding. arg_info should be large enought to hold param_count + 1 entries.
221 * Returns the size of the activation frame.
224 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
226 #ifdef __mono_ppc64__
227 NOT_IMPLEMENTED;
228 return -1;
229 #else
230 int k, frame_size = 0;
231 int size, align, pad;
232 int offset = 8;
234 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
235 frame_size += sizeof (target_mgreg_t);
236 offset += 4;
239 arg_info [0].offset = offset;
241 if (csig->hasthis) {
242 frame_size += sizeof (target_mgreg_t);
243 offset += 4;
246 arg_info [0].size = frame_size;
248 for (k = 0; k < param_count; k++) {
250 if (csig->pinvoke)
251 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
252 else
253 size = mini_type_stack_size (csig->params [k], &align);
255 /* ignore alignment for now */
256 align = 1;
258 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
259 arg_info [k].pad = pad;
260 frame_size += size;
261 arg_info [k + 1].pad = 0;
262 arg_info [k + 1].size = size;
263 offset += pad;
264 arg_info [k + 1].offset = offset;
265 offset += size;
268 align = MONO_ARCH_FRAME_ALIGNMENT;
269 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
270 arg_info [k].pad = pad;
272 return frame_size;
273 #endif
276 #ifdef __mono_ppc64__
277 static gboolean
278 is_load_sequence (guint32 *seq)
280 return ppc_opcode (seq [0]) == 15 && /* lis */
281 ppc_opcode (seq [1]) == 24 && /* ori */
282 ppc_opcode (seq [2]) == 30 && /* sldi */
283 ppc_opcode (seq [3]) == 25 && /* oris */
284 ppc_opcode (seq [4]) == 24; /* ori */
287 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
288 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
289 #endif
291 /* ld || lwz */
292 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
294 /* code must point to the blrl */
295 gboolean
296 mono_ppc_is_direct_call_sequence (guint32 *code)
298 #ifdef __mono_ppc64__
299 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
301 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
302 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
303 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
304 if (!is_load_sequence (&code [-8]))
305 return FALSE;
306 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
307 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (target_mgreg_t)) ||
308 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (target_mgreg_t));
310 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
311 return is_load_sequence (&code [-8]);
312 else
313 return is_load_sequence (&code [-6]);
315 return FALSE;
316 #else
317 g_assert(*code == 0x4e800021);
319 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
320 return ppc_opcode (code [-1]) == 31 &&
321 ppc_opcode (code [-2]) == 24 &&
322 ppc_opcode (code [-3]) == 15;
323 #endif
326 #define MAX_ARCH_DELEGATE_PARAMS 7
328 static guint8*
329 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
331 guint8 *code, *start;
333 if (has_target) {
334 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
336 start = code = mono_global_codeman_reserve (size);
337 if (!aot)
338 code = mono_ppc_create_pre_code_ftnptr (code);
340 /* Replace the this argument with the target */
341 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
342 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
343 /* it's a function descriptor */
344 /* Can't use ldptr as it doesn't work with r0 */
345 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
346 #endif
347 ppc_mtctr (code, ppc_r0);
348 ppc_ldptr (code, ppc_r3, MONO_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
349 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
351 g_assert ((code - start) <= size);
353 mono_arch_flush_icache (start, size);
354 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
355 } else {
356 int size, i;
358 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
359 start = code = mono_global_codeman_reserve (size);
360 if (!aot)
361 code = mono_ppc_create_pre_code_ftnptr (code);
363 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
364 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
365 /* it's a function descriptor */
366 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
367 #endif
368 ppc_mtctr (code, ppc_r0);
369 /* slide down the arguments */
370 for (i = 0; i < param_count; ++i) {
371 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
373 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
375 g_assert ((code - start) <= size);
377 mono_arch_flush_icache (start, size);
378 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
381 if (has_target) {
382 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
383 } else {
384 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
385 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
386 g_free (name);
389 return start;
392 GSList*
393 mono_arch_get_delegate_invoke_impls (void)
395 GSList *res = NULL;
396 MonoTrampInfo *info;
397 int i;
399 get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
400 res = g_slist_prepend (res, info);
402 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
403 get_delegate_invoke_impl (&info, FALSE, i, TRUE);
404 res = g_slist_prepend (res, info);
407 return res;
410 gpointer
411 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
413 guint8 *code, *start;
415 /* FIXME: Support more cases */
416 if (MONO_TYPE_ISSTRUCT (sig->ret))
417 return NULL;
419 if (has_target) {
420 static guint8* cached = NULL;
422 if (cached)
423 return cached;
425 if (mono_ee_features.use_aot_trampolines) {
426 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
427 } else {
428 MonoTrampInfo *info;
429 start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
430 mono_tramp_info_register (info, NULL);
432 mono_memory_barrier ();
434 cached = start;
435 } else {
436 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
437 int i;
439 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
440 return NULL;
441 for (i = 0; i < sig->param_count; ++i)
442 if (!mono_is_regsize_var (sig->params [i]))
443 return NULL;
446 code = cache [sig->param_count];
447 if (code)
448 return code;
450 if (mono_ee_features.use_aot_trampolines) {
451 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
452 start = mono_aot_get_trampoline (name);
453 g_free (name);
454 } else {
455 MonoTrampInfo *info;
456 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
457 mono_tramp_info_register (info, NULL);
460 mono_memory_barrier ();
462 cache [sig->param_count] = start;
464 return start;
467 gpointer
468 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
470 return NULL;
473 gpointer
474 mono_arch_get_this_arg_from_call (host_mgreg_t *r, guint8 *code)
476 return (gpointer)(gsize)r [ppc_r3];
479 typedef struct {
480 long int type;
481 long int value;
482 } AuxVec;
484 #define MAX_AUX_ENTRIES 128
486 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
487 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
489 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
491 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
492 #define ISA_64 0x40000000
494 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
495 #define ISA_MOVE_FPR_GPR 0x00000200
497 * Initialize the cpu to execute managed code.
499 void
500 mono_arch_cpu_init (void)
505 * Initialize architecture specific code.
507 void
508 mono_arch_init (void)
510 #if defined(MONO_CROSS_COMPILE)
511 #elif defined(__APPLE__)
512 int mib [3];
513 size_t len = sizeof (cachelinesize);
515 mib [0] = CTL_HW;
516 mib [1] = HW_CACHELINE;
518 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
519 perror ("sysctl");
520 cachelinesize = 128;
521 } else {
522 cachelineinc = cachelinesize;
524 #elif defined(__linux__)
525 AuxVec vec [MAX_AUX_ENTRIES];
526 int i, vec_entries = 0;
527 /* sadly this will work only with 2.6 kernels... */
528 FILE* f = fopen ("/proc/self/auxv", "rb");
530 if (f) {
531 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
532 fclose (f);
535 for (i = 0; i < vec_entries; i++) {
536 int type = vec [i].type;
538 if (type == 19) { /* AT_DCACHEBSIZE */
539 cachelinesize = vec [i].value;
540 continue;
543 #elif defined(G_COMPILER_CODEWARRIOR)
544 cachelinesize = 32;
545 cachelineinc = 32;
546 #elif defined(_AIX)
547 /* FIXME: use block instead? */
548 cachelinesize = _system_configuration.icache_line;
549 cachelineinc = _system_configuration.icache_line;
550 #else
551 //#error Need a way to get cache line size
552 #endif
554 if (mono_hwcap_ppc_has_icache_snoop)
555 cpu_hw_caps |= PPC_ICACHE_SNOOP;
557 if (mono_hwcap_ppc_is_isa_2x)
558 cpu_hw_caps |= PPC_ISA_2X;
560 if (mono_hwcap_ppc_is_isa_2_03)
561 cpu_hw_caps |= PPC_ISA_2_03;
563 if (mono_hwcap_ppc_is_isa_64)
564 cpu_hw_caps |= PPC_ISA_64;
566 if (mono_hwcap_ppc_has_move_fpr_gpr)
567 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
569 if (mono_hwcap_ppc_has_multiple_ls_units)
570 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
572 if (!cachelinesize)
573 cachelinesize = 32;
575 if (!cachelineinc)
576 cachelineinc = cachelinesize;
578 if (mono_cpu_count () > 1)
579 cpu_hw_caps |= PPC_SMP_CAPABLE;
581 mono_os_mutex_init_recursive (&mini_arch_mutex);
583 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
584 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
585 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
587 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
589 // FIXME: Fix partial sharing for power and remove this
590 mono_set_partial_sharing_supported (FALSE);
594 * Cleanup architecture specific code.
596 void
597 mono_arch_cleanup (void)
599 mono_os_mutex_destroy (&mini_arch_mutex);
602 gboolean
603 mono_arch_have_fast_tls (void)
605 return FALSE;
609 * This function returns the optimizations supported on this cpu.
611 guint32
612 mono_arch_cpu_optimizations (guint32 *exclude_mask)
614 guint32 opts = 0;
616 /* no ppc-specific optimizations yet */
617 *exclude_mask = 0;
618 return opts;
622 * This function test for all SIMD functions supported.
624 * Returns a bitmask corresponding to all supported versions.
627 guint32
628 mono_arch_cpu_enumerate_simd_versions (void)
630 /* SIMD is currently unimplemented */
631 return 0;
634 #ifdef __mono_ppc64__
635 #define CASE_PPC32(c)
636 #define CASE_PPC64(c) case c:
637 #else
638 #define CASE_PPC32(c) case c:
639 #define CASE_PPC64(c)
640 #endif
642 static gboolean
643 is_regsize_var (MonoType *t) {
644 if (t->byref)
645 return TRUE;
646 t = mini_get_underlying_type (t);
647 switch (t->type) {
648 case MONO_TYPE_I4:
649 case MONO_TYPE_U4:
650 CASE_PPC64 (MONO_TYPE_I8)
651 CASE_PPC64 (MONO_TYPE_U8)
652 case MONO_TYPE_I:
653 case MONO_TYPE_U:
654 case MONO_TYPE_PTR:
655 case MONO_TYPE_FNPTR:
656 return TRUE;
657 case MONO_TYPE_OBJECT:
658 case MONO_TYPE_STRING:
659 case MONO_TYPE_CLASS:
660 case MONO_TYPE_SZARRAY:
661 case MONO_TYPE_ARRAY:
662 return TRUE;
663 case MONO_TYPE_GENERICINST:
664 if (!mono_type_generic_inst_is_valuetype (t))
665 return TRUE;
666 return FALSE;
667 case MONO_TYPE_VALUETYPE:
668 return FALSE;
670 return FALSE;
673 #ifndef DISABLE_JIT
674 GList *
675 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
677 GList *vars = NULL;
678 int i;
680 for (i = 0; i < cfg->num_varinfo; i++) {
681 MonoInst *ins = cfg->varinfo [i];
682 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
684 /* unused vars */
685 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
686 continue;
688 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
689 continue;
691 /* we can only allocate 32 bit values */
692 if (is_regsize_var (ins->inst_vtype)) {
693 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
694 g_assert (i == vmv->idx);
695 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
699 return vars;
701 #endif /* ifndef DISABLE_JIT */
703 GList *
704 mono_arch_get_global_int_regs (MonoCompile *cfg)
706 GList *regs = NULL;
707 int i, top = 32;
708 if (cfg->frame_reg != ppc_sp)
709 top = 31;
710 /* ppc_r13 is used by the system on PPC EABI */
711 for (i = 14; i < top; ++i) {
713 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
714 * since the trampolines can clobber r12.
716 if (!(cfg->compile_aot && i == 29))
717 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
720 return regs;
724 * mono_arch_regalloc_cost:
726 * Return the cost, in number of memory references, of the action of
727 * allocating the variable VMV into a register during global register
728 * allocation.
730 guint32
731 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
733 /* FIXME: */
734 return 2;
737 void
738 mono_arch_flush_icache (guint8 *code, gint size)
740 #ifdef MONO_CROSS_COMPILE
741 /* do nothing */
742 #else
743 register guint8 *p;
744 guint8 *endp, *start;
746 p = start = code;
747 endp = p + size;
748 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
749 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
750 #if defined(G_COMPILER_CODEWARRIOR)
751 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
752 for (p = start; p < endp; p += cachelineinc) {
753 asm { dcbf 0, p };
755 } else {
756 for (p = start; p < endp; p += cachelineinc) {
757 asm { dcbst 0, p };
760 asm { sync };
761 p = code;
762 for (p = start; p < endp; p += cachelineinc) {
763 asm {
764 icbi 0, p
765 sync
768 asm {
769 sync
770 isync
772 #else
773 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
774 * The sync is required to insure that the store queue is completely empty.
775 * While the icbi performs no cache operations, icbi/isync is required to
776 * kill local prefetch.
778 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
779 asm ("sync");
780 asm ("icbi 0,%0;" : : "r"(code) : "memory");
781 asm ("isync");
782 return;
784 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
785 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
786 for (p = start; p < endp; p += cachelineinc) {
787 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
789 } else {
790 for (p = start; p < endp; p += cachelineinc) {
791 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
794 asm ("sync");
795 p = code;
796 for (p = start; p < endp; p += cachelineinc) {
797 /* for ISA2.0+ implementations we should not need any extra sync between the
798 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
799 * So I am not sure which chip had this problem but its not an issue on
800 * of the ISA V2 chips.
802 if (cpu_hw_caps & PPC_ISA_2X)
803 asm ("icbi 0,%0;" : : "r"(p) : "memory");
804 else
805 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
807 if (!(cpu_hw_caps & PPC_ISA_2X))
808 asm ("sync");
809 asm ("isync");
810 #endif
811 #endif
814 void
815 mono_arch_flush_register_windows (void)
819 #ifdef __APPLE__
820 #define ALWAYS_ON_STACK(s) s
821 #define FP_ALSO_IN_REG(s) s
822 #else
823 #ifdef __mono_ppc64__
824 #define ALWAYS_ON_STACK(s) s
825 #define FP_ALSO_IN_REG(s) s
826 #else
827 #define ALWAYS_ON_STACK(s)
828 #define FP_ALSO_IN_REG(s)
829 #endif
830 #define ALIGN_DOUBLES
831 #endif
833 enum {
834 RegTypeGeneral,
835 RegTypeBase,
836 RegTypeFP,
837 RegTypeStructByVal,
838 RegTypeStructByAddr,
839 RegTypeFPStructByVal, // For the v2 ABI, floats should be passed in FRs instead of GRs. Only valid for ABI v2!
842 typedef struct {
843 gint32 offset;
844 guint32 vtsize; /* in param area */
845 guint8 reg;
846 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal/RegTypeFPStructByVal */
847 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
848 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal/RegTypeFPStructByVal */
849 guint8 bytes : 4; /* size in bytes - only valid for
850 RegTypeStructByVal/RegTypeFPStructByVal if the struct fits
851 in one word, otherwise it's 0*/
852 } ArgInfo;
854 struct CallInfo {
855 int nargs;
856 guint32 stack_usage;
857 guint32 struct_ret;
858 ArgInfo ret;
859 ArgInfo sig_cookie;
860 gboolean vtype_retaddr;
861 int vret_arg_index;
862 ArgInfo args [1];
865 #define DEBUG(a)
868 #if PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS
870 // Test if a structure is completely composed of either float XOR double fields and has fewer than
871 // PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTER members.
872 // If this is true the structure can be returned directly via float registers instead of by a hidden parameter
873 // pointing to where the return value should be stored.
874 // This is as per the ELF ABI v2.
876 static gboolean
877 is_float_struct_returnable_via_regs (MonoType *type, int* member_cnt, int* member_size)
879 int local_member_cnt, local_member_size;
880 if (!member_cnt) {
881 member_cnt = &local_member_cnt;
883 if (!member_size) {
884 member_size = &local_member_size;
887 gboolean is_all_floats = mini_type_is_hfa(type, member_cnt, member_size);
888 return is_all_floats && (*member_cnt <= PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTERS);
890 #else
892 #define is_float_struct_returnable_via_regs(a,b,c) (FALSE)
894 #endif
896 #if PPC_RETURN_SMALL_STRUCTS_IN_REGS
898 // Test if a structure is smaller in size than 2 doublewords (PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS) and is
899 // completely composed of fields all of basic types.
900 // If this is true the structure can be returned directly via registers r3/r4 instead of by a hidden parameter
901 // pointing to where the return value should be stored.
902 // This is as per the ELF ABI v2.
904 static gboolean
905 is_struct_returnable_via_regs (MonoClass *klass, gboolean is_pinvoke)
907 gboolean has_a_field = FALSE;
908 int size = 0;
909 if (klass) {
910 gpointer iter = NULL;
911 MonoClassField *f;
912 if (is_pinvoke)
913 size = mono_type_native_stack_size (m_class_get_byval_arg (klass), 0);
914 else
915 size = mini_type_stack_size (m_class_get_byval_arg (klass), 0);
916 if (size == 0)
917 return TRUE;
918 if (size > PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS)
919 return FALSE;
920 while ((f = mono_class_get_fields_internal (klass, &iter))) {
921 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
922 // TBD: Is there a better way to check for the basic types?
923 if (f->type->byref) {
924 return FALSE;
925 } else if ((f->type->type >= MONO_TYPE_BOOLEAN) && (f->type->type <= MONO_TYPE_R8)) {
926 has_a_field = TRUE;
927 } else if (MONO_TYPE_ISSTRUCT (f->type)) {
928 MonoClass *klass = mono_class_from_mono_type_internal (f->type);
929 if (is_struct_returnable_via_regs(klass, is_pinvoke)) {
930 has_a_field = TRUE;
931 } else {
932 return FALSE;
934 } else {
935 return FALSE;
940 return has_a_field;
942 #else
944 #define is_struct_returnable_via_regs(a,b) (FALSE)
946 #endif
948 static void inline
949 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
951 #ifdef __mono_ppc64__
952 g_assert (simple);
953 #endif
955 if (simple) {
956 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
957 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
958 ainfo->reg = ppc_sp; /* in the caller */
959 ainfo->regtype = RegTypeBase;
960 *stack_size += sizeof (target_mgreg_t);
961 } else {
962 ALWAYS_ON_STACK (*stack_size += sizeof (target_mgreg_t));
963 ainfo->reg = *gr;
965 } else {
966 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
967 #ifdef ALIGN_DOUBLES
968 //*stack_size += (*stack_size % 8);
969 #endif
970 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
971 ainfo->reg = ppc_sp; /* in the caller */
972 ainfo->regtype = RegTypeBase;
973 *stack_size += 8;
974 } else {
975 #ifdef ALIGN_DOUBLES
976 if (!((*gr) & 1))
977 (*gr) ++;
978 #endif
979 ALWAYS_ON_STACK (*stack_size += 8);
980 ainfo->reg = *gr;
982 (*gr) ++;
984 (*gr) ++;
987 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
988 static gboolean
989 has_only_a_r48_field (MonoClass *klass)
991 gpointer iter;
992 MonoClassField *f;
993 gboolean have_field = FALSE;
994 iter = NULL;
995 while ((f = mono_class_get_fields_internal (klass, &iter))) {
996 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
997 if (have_field)
998 return FALSE;
999 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
1000 have_field = TRUE;
1001 else
1002 return FALSE;
1005 return have_field;
1007 #endif
1009 static CallInfo*
1010 get_call_info (MonoMethodSignature *sig)
1012 guint i, fr, gr, pstart;
1013 int n = sig->hasthis + sig->param_count;
1014 MonoType *simpletype;
1015 guint32 stack_size = 0;
1016 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1017 gboolean is_pinvoke = sig->pinvoke;
1019 fr = PPC_FIRST_FPARG_REG;
1020 gr = PPC_FIRST_ARG_REG;
1022 if (mini_type_is_vtype (sig->ret)) {
1023 cinfo->vtype_retaddr = TRUE;
1026 pstart = 0;
1027 n = 0;
1029 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1030 * the first argument, allowing 'this' to be always passed in the first arg reg.
1031 * Also do this if the first argument is a reference type, since virtual calls
1032 * are sometimes made using calli without sig->hasthis set, like in the delegate
1033 * invoke wrappers.
1035 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1036 if (sig->hasthis) {
1037 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1038 n ++;
1039 } else {
1040 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1041 pstart = 1;
1042 n ++;
1044 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1045 cinfo->struct_ret = cinfo->ret.reg;
1046 cinfo->vret_arg_index = 1;
1047 } else {
1048 /* this */
1049 if (sig->hasthis) {
1050 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1051 n ++;
1054 if (cinfo->vtype_retaddr) {
1055 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1056 cinfo->struct_ret = cinfo->ret.reg;
1060 DEBUG(printf("params: %d\n", sig->param_count));
1061 for (i = pstart; i < sig->param_count; ++i) {
1062 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1063 /* Prevent implicit arguments and sig_cookie from
1064 being passed in registers */
1065 gr = PPC_LAST_ARG_REG + 1;
1066 /* FIXME: don't we have to set fr, too? */
1067 /* Emit the signature cookie just before the implicit arguments */
1068 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1070 DEBUG(printf("param %d: ", i));
1071 if (sig->params [i]->byref) {
1072 DEBUG(printf("byref\n"));
1073 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1074 n++;
1075 continue;
1077 simpletype = mini_get_underlying_type (sig->params [i]);
1078 switch (simpletype->type) {
1079 case MONO_TYPE_BOOLEAN:
1080 case MONO_TYPE_I1:
1081 case MONO_TYPE_U1:
1082 cinfo->args [n].size = 1;
1083 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1084 n++;
1085 break;
1086 case MONO_TYPE_CHAR:
1087 case MONO_TYPE_I2:
1088 case MONO_TYPE_U2:
1089 cinfo->args [n].size = 2;
1090 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1091 n++;
1092 break;
1093 case MONO_TYPE_I4:
1094 case MONO_TYPE_U4:
1095 cinfo->args [n].size = 4;
1096 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1097 n++;
1098 break;
1099 case MONO_TYPE_I:
1100 case MONO_TYPE_U:
1101 case MONO_TYPE_PTR:
1102 case MONO_TYPE_FNPTR:
1103 case MONO_TYPE_CLASS:
1104 case MONO_TYPE_OBJECT:
1105 case MONO_TYPE_STRING:
1106 case MONO_TYPE_SZARRAY:
1107 case MONO_TYPE_ARRAY:
1108 cinfo->args [n].size = sizeof (target_mgreg_t);
1109 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1110 n++;
1111 break;
1112 case MONO_TYPE_GENERICINST:
1113 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1114 cinfo->args [n].size = sizeof (target_mgreg_t);
1115 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1116 n++;
1117 break;
1119 /* Fall through */
1120 case MONO_TYPE_VALUETYPE:
1121 case MONO_TYPE_TYPEDBYREF: {
1122 gint size;
1123 MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]);
1124 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1125 size = MONO_ABI_SIZEOF (MonoTypedRef);
1126 else if (is_pinvoke)
1127 size = mono_class_native_size (klass, NULL);
1128 else
1129 size = mono_class_value_size (klass, NULL);
1131 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1132 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1133 cinfo->args [n].size = size;
1135 /* It was 7, now it is 8 in LinuxPPC */
1136 if (fr <= PPC_LAST_FPARG_REG) {
1137 cinfo->args [n].regtype = RegTypeFP;
1138 cinfo->args [n].reg = fr;
1139 fr ++;
1140 FP_ALSO_IN_REG (gr ++);
1141 #if !defined(__mono_ppc64__)
1142 if (size == 8)
1143 FP_ALSO_IN_REG (gr ++);
1144 #endif
1145 ALWAYS_ON_STACK (stack_size += size);
1146 } else {
1147 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1148 cinfo->args [n].regtype = RegTypeBase;
1149 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1150 stack_size += 8;
1152 n++;
1153 break;
1155 #endif
1156 DEBUG(printf ("load %d bytes struct\n",
1157 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1159 #if PPC_PASS_STRUCTS_BY_VALUE
1161 int align_size = size;
1162 int nregs = 0;
1163 int rest = PPC_LAST_ARG_REG - gr + 1;
1164 int n_in_regs = 0;
1166 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1167 int mbr_cnt = 0;
1168 int mbr_size = 0;
1169 gboolean is_all_floats = is_float_struct_returnable_via_regs (sig->params [i], &mbr_cnt, &mbr_size);
1171 if (is_all_floats) {
1172 rest = PPC_LAST_FPARG_REG - fr + 1;
1174 // Pass small (<= 8 member) structures entirely made up of either float or double members
1175 // in FR registers. There have to be at least mbr_cnt registers left.
1176 if (is_all_floats &&
1177 (rest >= mbr_cnt)) {
1178 nregs = mbr_cnt;
1179 n_in_regs = MIN (rest, nregs);
1180 cinfo->args [n].regtype = RegTypeFPStructByVal;
1181 cinfo->args [n].vtregs = n_in_regs;
1182 cinfo->args [n].size = mbr_size;
1183 cinfo->args [n].vtsize = nregs - n_in_regs;
1184 cinfo->args [n].reg = fr;
1185 fr += n_in_regs;
1186 if (mbr_size == 4) {
1187 // floats
1188 FP_ALSO_IN_REG (gr += (n_in_regs+1)/2);
1189 } else {
1190 // doubles
1191 FP_ALSO_IN_REG (gr += (n_in_regs));
1193 } else
1194 #endif
1196 align_size += (sizeof (target_mgreg_t) - 1);
1197 align_size &= ~(sizeof (target_mgreg_t) - 1);
1198 nregs = (align_size + sizeof (target_mgreg_t) -1 ) / sizeof (target_mgreg_t);
1199 n_in_regs = MIN (rest, nregs);
1200 if (n_in_regs < 0)
1201 n_in_regs = 0;
1202 #ifdef __APPLE__
1203 /* FIXME: check this */
1204 if (size >= 3 && size % 4 != 0)
1205 n_in_regs = 0;
1206 #endif
1207 cinfo->args [n].regtype = RegTypeStructByVal;
1208 cinfo->args [n].vtregs = n_in_regs;
1209 cinfo->args [n].size = n_in_regs;
1210 cinfo->args [n].vtsize = nregs - n_in_regs;
1211 cinfo->args [n].reg = gr;
1212 gr += n_in_regs;
1215 #ifdef __mono_ppc64__
1216 if (nregs == 1 && is_pinvoke)
1217 cinfo->args [n].bytes = size;
1218 else
1219 #endif
1220 cinfo->args [n].bytes = 0;
1221 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1222 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1223 stack_size += nregs * sizeof (target_mgreg_t);
1225 #else
1226 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1227 cinfo->args [n].regtype = RegTypeStructByAddr;
1228 cinfo->args [n].vtsize = size;
1229 #endif
1230 n++;
1231 break;
1233 case MONO_TYPE_U8:
1234 case MONO_TYPE_I8:
1235 cinfo->args [n].size = 8;
1236 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1237 n++;
1238 break;
1239 case MONO_TYPE_R4:
1240 cinfo->args [n].size = 4;
1242 /* It was 7, now it is 8 in LinuxPPC */
1243 if (fr <= PPC_LAST_FPARG_REG
1244 // For non-native vararg calls the parms must go in storage
1245 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1247 cinfo->args [n].regtype = RegTypeFP;
1248 cinfo->args [n].reg = fr;
1249 fr ++;
1250 FP_ALSO_IN_REG (gr ++);
1251 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1252 } else {
1253 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1254 cinfo->args [n].regtype = RegTypeBase;
1255 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1256 stack_size += SIZEOF_REGISTER;
1258 n++;
1259 break;
1260 case MONO_TYPE_R8:
1261 cinfo->args [n].size = 8;
1262 /* It was 7, now it is 8 in LinuxPPC */
1263 if (fr <= PPC_LAST_FPARG_REG
1264 // For non-native vararg calls the parms must go in storage
1265 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1267 cinfo->args [n].regtype = RegTypeFP;
1268 cinfo->args [n].reg = fr;
1269 fr ++;
1270 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1271 ALWAYS_ON_STACK (stack_size += 8);
1272 } else {
1273 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1274 cinfo->args [n].regtype = RegTypeBase;
1275 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1276 stack_size += 8;
1278 n++;
1279 break;
1280 default:
1281 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1284 cinfo->nargs = n;
1286 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1287 /* Prevent implicit arguments and sig_cookie from
1288 being passed in registers */
1289 gr = PPC_LAST_ARG_REG + 1;
1290 /* Emit the signature cookie just before the implicit arguments */
1291 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1295 simpletype = mini_get_underlying_type (sig->ret);
1296 switch (simpletype->type) {
1297 case MONO_TYPE_BOOLEAN:
1298 case MONO_TYPE_I1:
1299 case MONO_TYPE_U1:
1300 case MONO_TYPE_I2:
1301 case MONO_TYPE_U2:
1302 case MONO_TYPE_CHAR:
1303 case MONO_TYPE_I4:
1304 case MONO_TYPE_U4:
1305 case MONO_TYPE_I:
1306 case MONO_TYPE_U:
1307 case MONO_TYPE_PTR:
1308 case MONO_TYPE_FNPTR:
1309 case MONO_TYPE_CLASS:
1310 case MONO_TYPE_OBJECT:
1311 case MONO_TYPE_SZARRAY:
1312 case MONO_TYPE_ARRAY:
1313 case MONO_TYPE_STRING:
1314 cinfo->ret.reg = ppc_r3;
1315 break;
1316 case MONO_TYPE_U8:
1317 case MONO_TYPE_I8:
1318 cinfo->ret.reg = ppc_r3;
1319 break;
1320 case MONO_TYPE_R4:
1321 case MONO_TYPE_R8:
1322 cinfo->ret.reg = ppc_f1;
1323 cinfo->ret.regtype = RegTypeFP;
1324 break;
1325 case MONO_TYPE_GENERICINST:
1326 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1327 cinfo->ret.reg = ppc_r3;
1328 break;
1330 break;
1331 case MONO_TYPE_VALUETYPE:
1332 break;
1333 case MONO_TYPE_TYPEDBYREF:
1334 case MONO_TYPE_VOID:
1335 break;
1336 default:
1337 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1341 /* align stack size to 16 */
1342 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1343 stack_size = (stack_size + 15) & ~15;
1345 cinfo->stack_usage = stack_size;
1346 return cinfo;
1349 #ifndef DISABLE_JIT
1351 gboolean
1352 mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_)
1354 CallInfo *caller_info = get_call_info (caller_sig);
1355 CallInfo *callee_info = get_call_info (callee_sig);
1357 gboolean res = IS_SUPPORTED_TAILCALL (callee_info->stack_usage <= caller_info->stack_usage)
1358 && IS_SUPPORTED_TAILCALL (memcmp (&callee_info->ret, &caller_info->ret, sizeof (caller_info->ret)) == 0);
1360 // FIXME ABIs vary as to if this local is in the parameter area or not,
1361 // so this check might not be needed.
1362 for (int i = 0; res && i < callee_info->nargs; ++i) {
1363 res = IS_SUPPORTED_TAILCALL (callee_info->args [i].regtype != RegTypeStructByAddr);
1364 /* An address on the callee's stack is passed as the argument */
1367 g_free (caller_info);
1368 g_free (callee_info);
1370 return res;
1373 #endif
1376 * Set var information according to the calling convention. ppc version.
1377 * The locals var stuff should most likely be split in another method.
1379 void
1380 mono_arch_allocate_vars (MonoCompile *m)
1382 MonoMethodSignature *sig;
1383 MonoMethodHeader *header;
1384 MonoInst *inst;
1385 int i, offset, size, align, curinst;
1386 int frame_reg = ppc_sp;
1387 gint32 *offsets;
1388 guint32 locals_stack_size, locals_stack_align;
1390 m->flags |= MONO_CFG_HAS_SPILLUP;
1392 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1393 * call convs needs to be handled this way.
1395 if (m->flags & MONO_CFG_HAS_VARARGS)
1396 m->param_area = MAX (m->param_area, sizeof (target_mgreg_t)*8);
1397 /* gtk-sharp and other broken code will dllimport vararg functions even with
1398 * non-varargs signatures. Since there is little hope people will get this right
1399 * we assume they won't.
1401 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1402 m->param_area = MAX (m->param_area, sizeof (target_mgreg_t)*8);
1404 header = m->header;
1407 * We use the frame register also for any method that has
1408 * exception clauses. This way, when the handlers are called,
1409 * the code will reference local variables using the frame reg instead of
1410 * the stack pointer: if we had to restore the stack pointer, we'd
1411 * corrupt the method frames that are already on the stack (since
1412 * filters get called before stack unwinding happens) when the filter
1413 * code would call any method (this also applies to finally etc.).
1415 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1416 frame_reg = ppc_r31;
1417 m->frame_reg = frame_reg;
1418 if (frame_reg != ppc_sp) {
1419 m->used_int_regs |= 1 << frame_reg;
1422 sig = mono_method_signature_internal (m->method);
1424 offset = 0;
1425 curinst = 0;
1426 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1427 m->ret->opcode = OP_REGVAR;
1428 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1429 } else {
1430 /* FIXME: handle long values? */
1431 switch (mini_get_underlying_type (sig->ret)->type) {
1432 case MONO_TYPE_VOID:
1433 break;
1434 case MONO_TYPE_R4:
1435 case MONO_TYPE_R8:
1436 m->ret->opcode = OP_REGVAR;
1437 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1438 break;
1439 default:
1440 m->ret->opcode = OP_REGVAR;
1441 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1442 break;
1445 /* local vars are at a positive offset from the stack pointer */
1447 * also note that if the function uses alloca, we use ppc_r31
1448 * to point at the local variables.
1450 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1451 /* align the offset to 16 bytes: not sure this is needed here */
1452 //offset += 16 - 1;
1453 //offset &= ~(16 - 1);
1455 /* add parameter area size for called functions */
1456 offset += m->param_area;
1457 offset += 16 - 1;
1458 offset &= ~(16 - 1);
1460 /* the MonoLMF structure is stored just below the stack pointer */
1461 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1462 offset += sizeof(gpointer) - 1;
1463 offset &= ~(sizeof(gpointer) - 1);
1465 m->vret_addr->opcode = OP_REGOFFSET;
1466 m->vret_addr->inst_basereg = frame_reg;
1467 m->vret_addr->inst_offset = offset;
1469 if (G_UNLIKELY (m->verbose_level > 1)) {
1470 printf ("vret_addr =");
1471 mono_print_ins (m->vret_addr);
1474 offset += sizeof(gpointer);
1477 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1478 if (locals_stack_align) {
1479 offset += (locals_stack_align - 1);
1480 offset &= ~(locals_stack_align - 1);
1482 for (i = m->locals_start; i < m->num_varinfo; i++) {
1483 if (offsets [i] != -1) {
1484 MonoInst *inst = m->varinfo [i];
1485 inst->opcode = OP_REGOFFSET;
1486 inst->inst_basereg = frame_reg;
1487 inst->inst_offset = offset + offsets [i];
1489 g_print ("allocating local %d (%s) to %d\n",
1490 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1494 offset += locals_stack_size;
1496 curinst = 0;
1497 if (sig->hasthis) {
1498 inst = m->args [curinst];
1499 if (inst->opcode != OP_REGVAR) {
1500 inst->opcode = OP_REGOFFSET;
1501 inst->inst_basereg = frame_reg;
1502 offset += sizeof (target_mgreg_t) - 1;
1503 offset &= ~(sizeof (target_mgreg_t) - 1);
1504 inst->inst_offset = offset;
1505 offset += sizeof (target_mgreg_t);
1507 curinst++;
1510 for (i = 0; i < sig->param_count; ++i) {
1511 inst = m->args [curinst];
1512 if (inst->opcode != OP_REGVAR) {
1513 inst->opcode = OP_REGOFFSET;
1514 inst->inst_basereg = frame_reg;
1515 if (sig->pinvoke) {
1516 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1517 inst->backend.is_pinvoke = 1;
1518 } else {
1519 size = mono_type_size (sig->params [i], &align);
1521 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (target_mgreg_t))
1522 size = align = sizeof (target_mgreg_t);
1524 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1525 * they are saved using std in the prolog.
1527 align = sizeof (target_mgreg_t);
1528 offset += align - 1;
1529 offset &= ~(align - 1);
1530 inst->inst_offset = offset;
1531 offset += size;
1533 curinst++;
1536 /* some storage for fp conversions */
1537 offset += 8 - 1;
1538 offset &= ~(8 - 1);
1539 m->arch.fp_conv_var_offset = offset;
1540 offset += 8;
1542 /* align the offset to 16 bytes */
1543 offset += 16 - 1;
1544 offset &= ~(16 - 1);
1546 /* change sign? */
1547 m->stack_offset = offset;
1549 if (sig->call_convention == MONO_CALL_VARARG) {
1550 CallInfo *cinfo = get_call_info (m->method->signature);
1552 m->sig_cookie = cinfo->sig_cookie.offset;
1554 g_free(cinfo);
1558 void
1559 mono_arch_create_vars (MonoCompile *cfg)
1561 MonoMethodSignature *sig = mono_method_signature_internal (cfg->method);
1563 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1564 cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG);
1568 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1569 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1572 static void
1573 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1575 int sig_reg = mono_alloc_ireg (cfg);
1577 /* FIXME: Add support for signature tokens to AOT */
1578 cfg->disable_aot = TRUE;
1580 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1581 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1582 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1585 void
1586 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1588 MonoInst *in, *ins;
1589 MonoMethodSignature *sig;
1590 int i, n;
1591 CallInfo *cinfo;
1593 sig = call->signature;
1594 n = sig->param_count + sig->hasthis;
1596 cinfo = get_call_info (sig);
1598 for (i = 0; i < n; ++i) {
1599 ArgInfo *ainfo = cinfo->args + i;
1600 MonoType *t;
1602 if (i >= sig->hasthis)
1603 t = sig->params [i - sig->hasthis];
1604 else
1605 t = mono_get_int_type ();
1606 t = mini_get_underlying_type (t);
1608 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1609 emit_sig_cookie (cfg, call, cinfo);
1611 in = call->args [i];
1613 if (ainfo->regtype == RegTypeGeneral) {
1614 #ifndef __mono_ppc64__
1615 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1616 MONO_INST_NEW (cfg, ins, OP_MOVE);
1617 ins->dreg = mono_alloc_ireg (cfg);
1618 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1619 MONO_ADD_INS (cfg->cbb, ins);
1620 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1622 MONO_INST_NEW (cfg, ins, OP_MOVE);
1623 ins->dreg = mono_alloc_ireg (cfg);
1624 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1625 MONO_ADD_INS (cfg->cbb, ins);
1626 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1627 } else
1628 #endif
1630 MONO_INST_NEW (cfg, ins, OP_MOVE);
1631 ins->dreg = mono_alloc_ireg (cfg);
1632 ins->sreg1 = in->dreg;
1633 MONO_ADD_INS (cfg->cbb, ins);
1635 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1637 } else if (ainfo->regtype == RegTypeStructByAddr) {
1638 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1639 ins->opcode = OP_OUTARG_VT;
1640 ins->sreg1 = in->dreg;
1641 ins->klass = in->klass;
1642 ins->inst_p0 = call;
1643 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1644 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1645 MONO_ADD_INS (cfg->cbb, ins);
1646 } else if (ainfo->regtype == RegTypeStructByVal) {
1647 /* this is further handled in mono_arch_emit_outarg_vt () */
1648 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1649 ins->opcode = OP_OUTARG_VT;
1650 ins->sreg1 = in->dreg;
1651 ins->klass = in->klass;
1652 ins->inst_p0 = call;
1653 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1654 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1655 MONO_ADD_INS (cfg->cbb, ins);
1656 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1657 /* this is further handled in mono_arch_emit_outarg_vt () */
1658 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1659 ins->opcode = OP_OUTARG_VT;
1660 ins->sreg1 = in->dreg;
1661 ins->klass = in->klass;
1662 ins->inst_p0 = call;
1663 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1664 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1665 MONO_ADD_INS (cfg->cbb, ins);
1666 cfg->flags |= MONO_CFG_HAS_FPOUT;
1667 } else if (ainfo->regtype == RegTypeBase) {
1668 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1669 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1670 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1671 if (t->type == MONO_TYPE_R8)
1672 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1673 else
1674 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1675 } else {
1676 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1678 } else if (ainfo->regtype == RegTypeFP) {
1679 if (t->type == MONO_TYPE_VALUETYPE) {
1680 /* this is further handled in mono_arch_emit_outarg_vt () */
1681 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1682 ins->opcode = OP_OUTARG_VT;
1683 ins->sreg1 = in->dreg;
1684 ins->klass = in->klass;
1685 ins->inst_p0 = call;
1686 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1687 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1688 MONO_ADD_INS (cfg->cbb, ins);
1690 cfg->flags |= MONO_CFG_HAS_FPOUT;
1691 } else {
1692 int dreg = mono_alloc_freg (cfg);
1694 if (ainfo->size == 4) {
1695 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1696 } else {
1697 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1698 ins->dreg = dreg;
1699 ins->sreg1 = in->dreg;
1700 MONO_ADD_INS (cfg->cbb, ins);
1703 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1704 cfg->flags |= MONO_CFG_HAS_FPOUT;
1706 } else {
1707 g_assert_not_reached ();
1711 /* Emit the signature cookie in the case that there is no
1712 additional argument */
1713 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1714 emit_sig_cookie (cfg, call, cinfo);
1716 if (cinfo->struct_ret) {
1717 MonoInst *vtarg;
1719 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1720 vtarg->sreg1 = call->vret_var->dreg;
1721 vtarg->dreg = mono_alloc_preg (cfg);
1722 MONO_ADD_INS (cfg->cbb, vtarg);
1724 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1727 call->stack_usage = cinfo->stack_usage;
1728 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1729 cfg->flags |= MONO_CFG_HAS_CALLS;
1731 g_free (cinfo);
1734 #ifndef DISABLE_JIT
1736 void
1737 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1739 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1740 ArgInfo *ainfo = ins->inst_p1;
1741 int ovf_size = ainfo->vtsize;
1742 int doffset = ainfo->offset;
1743 int i, soffset, dreg;
1745 if (ainfo->regtype == RegTypeStructByVal) {
1746 #ifdef __APPLE__
1747 guint32 size = 0;
1748 #endif
1749 soffset = 0;
1750 #ifdef __APPLE__
1752 * Darwin pinvokes needs some special handling for 1
1753 * and 2 byte arguments
1755 g_assert (ins->klass);
1756 if (call->signature->pinvoke)
1757 size = mono_class_native_size (ins->klass, NULL);
1758 if (size == 2 || size == 1) {
1759 int tmpr = mono_alloc_ireg (cfg);
1760 if (size == 1)
1761 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1762 else
1763 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1764 dreg = mono_alloc_ireg (cfg);
1765 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1766 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1767 } else
1768 #endif
1769 for (i = 0; i < ainfo->vtregs; ++i) {
1770 dreg = mono_alloc_ireg (cfg);
1771 #if G_BYTE_ORDER == G_BIG_ENDIAN
1772 int antipadding = 0;
1773 if (ainfo->bytes) {
1774 g_assert (i == 0);
1775 antipadding = sizeof (target_mgreg_t) - ainfo->bytes;
1777 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1778 if (antipadding)
1779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1780 #else
1781 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1782 #endif
1783 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1784 soffset += sizeof (target_mgreg_t);
1786 if (ovf_size != 0)
1787 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (target_mgreg_t), TARGET_SIZEOF_VOID_P);
1788 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1789 soffset = 0;
1790 for (i = 0; i < ainfo->vtregs; ++i) {
1791 int tmpr = mono_alloc_freg (cfg);
1792 if (ainfo->size == 4)
1793 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, soffset);
1794 else // ==8
1795 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, soffset);
1796 dreg = mono_alloc_freg (cfg);
1797 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1798 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg+i, TRUE);
1799 soffset += ainfo->size;
1801 if (ovf_size != 0)
1802 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (target_mgreg_t), TARGET_SIZEOF_VOID_P);
1803 } else if (ainfo->regtype == RegTypeFP) {
1804 int tmpr = mono_alloc_freg (cfg);
1805 if (ainfo->size == 4)
1806 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1807 else
1808 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1809 dreg = mono_alloc_freg (cfg);
1810 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1811 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1812 } else {
1813 MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL);
1814 MonoInst *load;
1815 guint32 size;
1817 /* FIXME: alignment? */
1818 if (call->signature->pinvoke) {
1819 size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL);
1820 vtcopy->backend.is_pinvoke = 1;
1821 } else {
1822 size = mini_type_stack_size (m_class_get_byval_arg (src->klass), NULL);
1824 if (size > 0)
1825 g_assert (ovf_size > 0);
1827 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1828 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, TARGET_SIZEOF_VOID_P);
1830 if (ainfo->offset)
1831 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1832 else
1833 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1837 void
1838 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1840 MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret);
1841 if (!ret->byref) {
1842 #ifndef __mono_ppc64__
1843 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1844 MonoInst *ins;
1846 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1847 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1848 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1849 MONO_ADD_INS (cfg->cbb, ins);
1850 return;
1852 #endif
1853 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1854 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1855 return;
1858 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1861 gboolean
1862 mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm)
1864 return TRUE;
1867 #endif /* DISABLE_JIT */
1870 * Conditional branches have a small offset, so if it is likely overflowed,
1871 * we do a branch to the end of the method (uncond branches have much larger
1872 * offsets) where we perform the conditional and jump back unconditionally.
1873 * It's slightly slower, since we add two uncond branches, but it's very simple
1874 * with the current patch implementation and such large methods are likely not
1875 * going to be perf critical anyway.
1877 typedef struct {
1878 union {
1879 MonoBasicBlock *bb;
1880 const char *exception;
1881 } data;
1882 guint32 ip_offset;
1883 guint16 b0_cond;
1884 guint16 b1_cond;
1885 } MonoOvfJump;
1887 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1888 if (0 && ins->inst_true_bb->native_offset) { \
1889 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1890 } else { \
1891 int br_disp = ins->inst_true_bb->max_offset - offset; \
1892 if (!ppc_is_imm16 (br_disp + 8 * 1024) || !ppc_is_imm16 (br_disp - 8 * 1024)) { \
1893 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1894 ovfj->data.bb = ins->inst_true_bb; \
1895 ovfj->ip_offset = 0; \
1896 ovfj->b0_cond = (b0); \
1897 ovfj->b1_cond = (b1); \
1898 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1899 ppc_b (code, 0); \
1900 } else { \
1901 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1902 ppc_bc (code, (b0), (b1), 0); \
1906 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1908 /* emit an exception if condition is fail
1910 * We assign the extra code used to throw the implicit exceptions
1911 * to cfg->bb_exit as far as the big branch handling is concerned
1913 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1914 do { \
1915 int br_disp = cfg->bb_exit->max_offset - offset; \
1916 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1917 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1918 ovfj->data.exception = (exc_name); \
1919 ovfj->ip_offset = code - cfg->native_code; \
1920 ovfj->b0_cond = (b0); \
1921 ovfj->b1_cond = (b1); \
1922 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1923 ppc_bl (code, 0); \
1924 cfg->bb_exit->max_offset += 24; \
1925 } else { \
1926 mono_add_patch_info (cfg, code - cfg->native_code, \
1927 MONO_PATCH_INFO_EXC, exc_name); \
1928 ppc_bcl (code, (b0), (b1), 0); \
1930 } while (0);
1932 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1934 void
1935 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1939 static int
1940 normalize_opcode (int opcode)
1942 switch (opcode) {
1943 #ifndef MONO_ARCH_ILP32
1944 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1945 return OP_LOAD_MEMBASE;
1946 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1947 return OP_LOAD_MEMINDEX;
1948 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1949 return OP_STORE_MEMBASE_REG;
1950 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1951 return OP_STORE_MEMBASE_IMM;
1952 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1953 return OP_STORE_MEMINDEX;
1954 #endif
1955 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
1956 return OP_SHR_IMM;
1957 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
1958 return OP_SHR_UN_IMM;
1959 default:
1960 return opcode;
1964 void
1965 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1967 MonoInst *ins, *n, *last_ins = NULL;
1969 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1970 switch (normalize_opcode (ins->opcode)) {
1971 case OP_MUL_IMM:
1972 /* remove unnecessary multiplication with 1 */
1973 if (ins->inst_imm == 1) {
1974 if (ins->dreg != ins->sreg1) {
1975 ins->opcode = OP_MOVE;
1976 } else {
1977 MONO_DELETE_INS (bb, ins);
1978 continue;
1980 } else {
1981 int power2 = mono_is_power_of_two (ins->inst_imm);
1982 if (power2 > 0) {
1983 ins->opcode = OP_SHL_IMM;
1984 ins->inst_imm = power2;
1987 break;
1988 case OP_LOAD_MEMBASE:
1990 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1991 * OP_LOAD_MEMBASE offset(basereg), reg
1993 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
1994 ins->inst_basereg == last_ins->inst_destbasereg &&
1995 ins->inst_offset == last_ins->inst_offset) {
1996 if (ins->dreg == last_ins->sreg1) {
1997 MONO_DELETE_INS (bb, ins);
1998 continue;
1999 } else {
2000 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2001 ins->opcode = OP_MOVE;
2002 ins->sreg1 = last_ins->sreg1;
2006 * Note: reg1 must be different from the basereg in the second load
2007 * OP_LOAD_MEMBASE offset(basereg), reg1
2008 * OP_LOAD_MEMBASE offset(basereg), reg2
2009 * -->
2010 * OP_LOAD_MEMBASE offset(basereg), reg1
2011 * OP_MOVE reg1, reg2
2013 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2014 ins->inst_basereg != last_ins->dreg &&
2015 ins->inst_basereg == last_ins->inst_basereg &&
2016 ins->inst_offset == last_ins->inst_offset) {
2018 if (ins->dreg == last_ins->dreg) {
2019 MONO_DELETE_INS (bb, ins);
2020 continue;
2021 } else {
2022 ins->opcode = OP_MOVE;
2023 ins->sreg1 = last_ins->dreg;
2026 //g_assert_not_reached ();
2028 #if 0
2030 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2031 * OP_LOAD_MEMBASE offset(basereg), reg
2032 * -->
2033 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2034 * OP_ICONST reg, imm
2036 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2037 ins->inst_basereg == last_ins->inst_destbasereg &&
2038 ins->inst_offset == last_ins->inst_offset) {
2039 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2040 ins->opcode = OP_ICONST;
2041 ins->inst_c0 = last_ins->inst_imm;
2042 g_assert_not_reached (); // check this rule
2043 #endif
2045 break;
2046 case OP_LOADU1_MEMBASE:
2047 case OP_LOADI1_MEMBASE:
2048 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2049 ins->inst_basereg == last_ins->inst_destbasereg &&
2050 ins->inst_offset == last_ins->inst_offset) {
2051 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2052 ins->sreg1 = last_ins->sreg1;
2054 break;
2055 case OP_LOADU2_MEMBASE:
2056 case OP_LOADI2_MEMBASE:
2057 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2058 ins->inst_basereg == last_ins->inst_destbasereg &&
2059 ins->inst_offset == last_ins->inst_offset) {
2060 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2061 ins->sreg1 = last_ins->sreg1;
2063 break;
2064 #ifdef __mono_ppc64__
2065 case OP_LOADU4_MEMBASE:
2066 case OP_LOADI4_MEMBASE:
2067 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2068 ins->inst_basereg == last_ins->inst_destbasereg &&
2069 ins->inst_offset == last_ins->inst_offset) {
2070 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2071 ins->sreg1 = last_ins->sreg1;
2073 break;
2074 #endif
2075 case OP_MOVE:
2076 ins->opcode = OP_MOVE;
2078 * OP_MOVE reg, reg
2080 if (ins->dreg == ins->sreg1) {
2081 MONO_DELETE_INS (bb, ins);
2082 continue;
2085 * OP_MOVE sreg, dreg
2086 * OP_MOVE dreg, sreg
2088 if (last_ins && last_ins->opcode == OP_MOVE &&
2089 ins->sreg1 == last_ins->dreg &&
2090 ins->dreg == last_ins->sreg1) {
2091 MONO_DELETE_INS (bb, ins);
2092 continue;
2094 break;
2096 last_ins = ins;
2097 ins = ins->next;
2099 bb->last_ins = last_ins;
2102 void
2103 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2105 switch (ins->opcode) {
2106 case OP_ICONV_TO_R_UN: {
2107 // This value is OK as-is for both big and little endian because of how it is stored
2108 static const guint64 adjust_val = 0x4330000000000000ULL;
2109 int msw_reg = mono_alloc_ireg (cfg);
2110 int adj_reg = mono_alloc_freg (cfg);
2111 int tmp_reg = mono_alloc_freg (cfg);
2112 int basereg = ppc_sp;
2113 int offset = -8;
2114 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2115 if (!ppc_is_imm16 (offset + 4)) {
2116 basereg = mono_alloc_ireg (cfg);
2117 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2119 #if G_BYTE_ORDER == G_BIG_ENDIAN
2120 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2121 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2122 #else
2123 // For little endian the words are reversed
2124 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2125 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2126 #endif
2127 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2128 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2129 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2130 ins->opcode = OP_NOP;
2131 break;
2133 #ifndef __mono_ppc64__
2134 case OP_ICONV_TO_R4:
2135 case OP_ICONV_TO_R8: {
2136 /* If we have a PPC_FEATURE_64 machine we can avoid
2137 this and use the fcfid instruction. Otherwise
2138 on an old 32-bit chip and we have to do this the
2139 hard way. */
2140 if (!(cpu_hw_caps & PPC_ISA_64)) {
2141 /* FIXME: change precision for CEE_CONV_R4 */
2142 static const guint64 adjust_val = 0x4330000080000000ULL;
2143 int msw_reg = mono_alloc_ireg (cfg);
2144 int xored = mono_alloc_ireg (cfg);
2145 int adj_reg = mono_alloc_freg (cfg);
2146 int tmp_reg = mono_alloc_freg (cfg);
2147 int basereg = ppc_sp;
2148 int offset = -8;
2149 if (!ppc_is_imm16 (offset + 4)) {
2150 basereg = mono_alloc_ireg (cfg);
2151 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2153 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2154 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2155 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2156 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2157 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2158 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2159 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2160 if (ins->opcode == OP_ICONV_TO_R4)
2161 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2162 ins->opcode = OP_NOP;
2164 break;
2166 #endif
2167 case OP_CKFINITE: {
2168 int msw_reg = mono_alloc_ireg (cfg);
2169 int basereg = ppc_sp;
2170 int offset = -8;
2171 if (!ppc_is_imm16 (offset + 4)) {
2172 basereg = mono_alloc_ireg (cfg);
2173 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2175 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2176 #if G_BYTE_ORDER == G_BIG_ENDIAN
2177 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2178 #else
2179 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2180 #endif
2181 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_CHECK_FINITE, -1, msw_reg);
2182 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2183 ins->opcode = OP_NOP;
2184 break;
2186 #ifdef __mono_ppc64__
2187 case OP_IADD_OVF:
2188 case OP_IADD_OVF_UN:
2189 case OP_ISUB_OVF: {
2190 int shifted1_reg = mono_alloc_ireg (cfg);
2191 int shifted2_reg = mono_alloc_ireg (cfg);
2192 int result_shifted_reg = mono_alloc_ireg (cfg);
2194 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2195 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2196 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2197 if (ins->opcode == OP_IADD_OVF_UN)
2198 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2199 else
2200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2201 ins->opcode = OP_NOP;
2202 break;
2204 #endif
2205 default:
2206 break;
2210 void
2211 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2213 switch (ins->opcode) {
2214 case OP_LADD_OVF:
2215 /* ADC sets the condition code */
2216 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2217 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2218 NULLIFY_INS (ins);
2219 break;
2220 case OP_LADD_OVF_UN:
2221 /* ADC sets the condition code */
2222 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2223 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2224 NULLIFY_INS (ins);
2225 break;
2226 case OP_LSUB_OVF:
2227 /* SBB sets the condition code */
2228 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2229 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2230 NULLIFY_INS (ins);
2231 break;
2232 case OP_LSUB_OVF_UN:
2233 /* SBB sets the condition code */
2234 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2235 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2236 NULLIFY_INS (ins);
2237 break;
2238 case OP_LNEG:
2239 /* From gcc generated code */
2240 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), 0);
2241 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1));
2242 NULLIFY_INS (ins);
2243 break;
2244 default:
2245 break;
2250 * the branch_b0_table should maintain the order of these
2251 * opcodes.
2252 case CEE_BEQ:
2253 case CEE_BGE:
2254 case CEE_BGT:
2255 case CEE_BLE:
2256 case CEE_BLT:
2257 case CEE_BNE_UN:
2258 case CEE_BGE_UN:
2259 case CEE_BGT_UN:
2260 case CEE_BLE_UN:
2261 case CEE_BLT_UN:
2263 static const guchar
2264 branch_b0_table [] = {
2265 PPC_BR_TRUE,
2266 PPC_BR_FALSE,
2267 PPC_BR_TRUE,
2268 PPC_BR_FALSE,
2269 PPC_BR_TRUE,
2271 PPC_BR_FALSE,
2272 PPC_BR_FALSE,
2273 PPC_BR_TRUE,
2274 PPC_BR_FALSE,
2275 PPC_BR_TRUE
2278 static const guchar
2279 branch_b1_table [] = {
2280 PPC_BR_EQ,
2281 PPC_BR_LT,
2282 PPC_BR_GT,
2283 PPC_BR_GT,
2284 PPC_BR_LT,
2286 PPC_BR_EQ,
2287 PPC_BR_LT,
2288 PPC_BR_GT,
2289 PPC_BR_GT,
2290 PPC_BR_LT
2293 #define NEW_INS(cfg,dest,op) do { \
2294 MONO_INST_NEW((cfg), (dest), (op)); \
2295 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2296 } while (0)
2298 static int
2299 map_to_reg_reg_op (int op)
2301 switch (op) {
2302 case OP_ADD_IMM:
2303 return OP_IADD;
2304 case OP_SUB_IMM:
2305 return OP_ISUB;
2306 case OP_AND_IMM:
2307 return OP_IAND;
2308 case OP_COMPARE_IMM:
2309 return OP_COMPARE;
2310 case OP_ICOMPARE_IMM:
2311 return OP_ICOMPARE;
2312 case OP_LCOMPARE_IMM:
2313 return OP_LCOMPARE;
2314 case OP_ADDCC_IMM:
2315 return OP_IADDCC;
2316 case OP_ADC_IMM:
2317 return OP_IADC;
2318 case OP_SUBCC_IMM:
2319 return OP_ISUBCC;
2320 case OP_SBB_IMM:
2321 return OP_ISBB;
2322 case OP_OR_IMM:
2323 return OP_IOR;
2324 case OP_XOR_IMM:
2325 return OP_IXOR;
2326 case OP_MUL_IMM:
2327 return OP_IMUL;
2328 case OP_LMUL_IMM:
2329 return OP_LMUL;
2330 case OP_LOAD_MEMBASE:
2331 return OP_LOAD_MEMINDEX;
2332 case OP_LOADI4_MEMBASE:
2333 return OP_LOADI4_MEMINDEX;
2334 case OP_LOADU4_MEMBASE:
2335 return OP_LOADU4_MEMINDEX;
2336 case OP_LOADI8_MEMBASE:
2337 return OP_LOADI8_MEMINDEX;
2338 case OP_LOADU1_MEMBASE:
2339 return OP_LOADU1_MEMINDEX;
2340 case OP_LOADI2_MEMBASE:
2341 return OP_LOADI2_MEMINDEX;
2342 case OP_LOADU2_MEMBASE:
2343 return OP_LOADU2_MEMINDEX;
2344 case OP_LOADI1_MEMBASE:
2345 return OP_LOADI1_MEMINDEX;
2346 case OP_LOADR4_MEMBASE:
2347 return OP_LOADR4_MEMINDEX;
2348 case OP_LOADR8_MEMBASE:
2349 return OP_LOADR8_MEMINDEX;
2350 case OP_STOREI1_MEMBASE_REG:
2351 return OP_STOREI1_MEMINDEX;
2352 case OP_STOREI2_MEMBASE_REG:
2353 return OP_STOREI2_MEMINDEX;
2354 case OP_STOREI4_MEMBASE_REG:
2355 return OP_STOREI4_MEMINDEX;
2356 case OP_STOREI8_MEMBASE_REG:
2357 return OP_STOREI8_MEMINDEX;
2358 case OP_STORE_MEMBASE_REG:
2359 return OP_STORE_MEMINDEX;
2360 case OP_STORER4_MEMBASE_REG:
2361 return OP_STORER4_MEMINDEX;
2362 case OP_STORER8_MEMBASE_REG:
2363 return OP_STORER8_MEMINDEX;
2364 case OP_STORE_MEMBASE_IMM:
2365 return OP_STORE_MEMBASE_REG;
2366 case OP_STOREI1_MEMBASE_IMM:
2367 return OP_STOREI1_MEMBASE_REG;
2368 case OP_STOREI2_MEMBASE_IMM:
2369 return OP_STOREI2_MEMBASE_REG;
2370 case OP_STOREI4_MEMBASE_IMM:
2371 return OP_STOREI4_MEMBASE_REG;
2372 case OP_STOREI8_MEMBASE_IMM:
2373 return OP_STOREI8_MEMBASE_REG;
2375 if (mono_op_imm_to_op (op) == -1)
2376 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2377 return mono_op_imm_to_op (op);
2380 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2382 #define compare_opcode_is_unsigned(opcode) \
2383 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2384 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2385 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2386 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2387 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2388 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2389 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2390 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2393 * Remove from the instruction list the instructions that can't be
2394 * represented with very simple instructions with no register
2395 * requirements.
2397 void
2398 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2400 MonoInst *ins, *next, *temp, *last_ins = NULL;
2401 int imm;
2403 MONO_BB_FOR_EACH_INS (bb, ins) {
2404 loop_start:
2405 switch (ins->opcode) {
2406 case OP_IDIV_UN_IMM:
2407 case OP_IDIV_IMM:
2408 case OP_IREM_IMM:
2409 case OP_IREM_UN_IMM:
2410 CASE_PPC64 (OP_LREM_IMM) {
2411 NEW_INS (cfg, temp, OP_ICONST);
2412 temp->inst_c0 = ins->inst_imm;
2413 temp->dreg = mono_alloc_ireg (cfg);
2414 ins->sreg2 = temp->dreg;
2415 if (ins->opcode == OP_IDIV_IMM)
2416 ins->opcode = OP_IDIV;
2417 else if (ins->opcode == OP_IREM_IMM)
2418 ins->opcode = OP_IREM;
2419 else if (ins->opcode == OP_IDIV_UN_IMM)
2420 ins->opcode = OP_IDIV_UN;
2421 else if (ins->opcode == OP_IREM_UN_IMM)
2422 ins->opcode = OP_IREM_UN;
2423 else if (ins->opcode == OP_LREM_IMM)
2424 ins->opcode = OP_LREM;
2425 last_ins = temp;
2426 /* handle rem separately */
2427 goto loop_start;
2429 case OP_IREM:
2430 case OP_IREM_UN:
2431 CASE_PPC64 (OP_LREM)
2432 CASE_PPC64 (OP_LREM_UN) {
2433 MonoInst *mul;
2434 /* we change a rem dest, src1, src2 to
2435 * div temp1, src1, src2
2436 * mul temp2, temp1, src2
2437 * sub dest, src1, temp2
2439 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2440 NEW_INS (cfg, mul, OP_IMUL);
2441 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2442 ins->opcode = OP_ISUB;
2443 } else {
2444 NEW_INS (cfg, mul, OP_LMUL);
2445 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2446 ins->opcode = OP_LSUB;
2448 temp->sreg1 = ins->sreg1;
2449 temp->sreg2 = ins->sreg2;
2450 temp->dreg = mono_alloc_ireg (cfg);
2451 mul->sreg1 = temp->dreg;
2452 mul->sreg2 = ins->sreg2;
2453 mul->dreg = mono_alloc_ireg (cfg);
2454 ins->sreg2 = mul->dreg;
2455 break;
2457 case OP_IADD_IMM:
2458 CASE_PPC64 (OP_LADD_IMM)
2459 case OP_ADD_IMM:
2460 case OP_ADDCC_IMM:
2461 if (!ppc_is_imm16 (ins->inst_imm)) {
2462 NEW_INS (cfg, temp, OP_ICONST);
2463 temp->inst_c0 = ins->inst_imm;
2464 temp->dreg = mono_alloc_ireg (cfg);
2465 ins->sreg2 = temp->dreg;
2466 ins->opcode = map_to_reg_reg_op (ins->opcode);
2468 break;
2469 case OP_ISUB_IMM:
2470 CASE_PPC64 (OP_LSUB_IMM)
2471 case OP_SUB_IMM:
2472 if (!ppc_is_imm16 (-ins->inst_imm)) {
2473 NEW_INS (cfg, temp, OP_ICONST);
2474 temp->inst_c0 = ins->inst_imm;
2475 temp->dreg = mono_alloc_ireg (cfg);
2476 ins->sreg2 = temp->dreg;
2477 ins->opcode = map_to_reg_reg_op (ins->opcode);
2479 break;
2480 case OP_IAND_IMM:
2481 case OP_IOR_IMM:
2482 case OP_IXOR_IMM:
2483 case OP_LAND_IMM:
2484 case OP_LOR_IMM:
2485 case OP_LXOR_IMM:
2486 case OP_AND_IMM:
2487 case OP_OR_IMM:
2488 case OP_XOR_IMM: {
2489 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2490 #ifdef __mono_ppc64__
2491 if (ins->inst_imm & 0xffffffff00000000ULL)
2492 is_imm = TRUE;
2493 #endif
2494 if (is_imm) {
2495 NEW_INS (cfg, temp, OP_ICONST);
2496 temp->inst_c0 = ins->inst_imm;
2497 temp->dreg = mono_alloc_ireg (cfg);
2498 ins->sreg2 = temp->dreg;
2499 ins->opcode = map_to_reg_reg_op (ins->opcode);
2501 break;
2503 case OP_ISBB_IMM:
2504 case OP_IADC_IMM:
2505 case OP_SBB_IMM:
2506 case OP_SUBCC_IMM:
2507 case OP_ADC_IMM:
2508 NEW_INS (cfg, temp, OP_ICONST);
2509 temp->inst_c0 = ins->inst_imm;
2510 temp->dreg = mono_alloc_ireg (cfg);
2511 ins->sreg2 = temp->dreg;
2512 ins->opcode = map_to_reg_reg_op (ins->opcode);
2513 break;
2514 case OP_COMPARE_IMM:
2515 case OP_ICOMPARE_IMM:
2516 CASE_PPC64 (OP_LCOMPARE_IMM)
2517 next = ins->next;
2518 /* Branch opts can eliminate the branch */
2519 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2520 ins->opcode = OP_NOP;
2521 break;
2523 g_assert(next);
2524 if (compare_opcode_is_unsigned (next->opcode)) {
2525 if (!ppc_is_uimm16 (ins->inst_imm)) {
2526 NEW_INS (cfg, temp, OP_ICONST);
2527 temp->inst_c0 = ins->inst_imm;
2528 temp->dreg = mono_alloc_ireg (cfg);
2529 ins->sreg2 = temp->dreg;
2530 ins->opcode = map_to_reg_reg_op (ins->opcode);
2532 } else {
2533 if (!ppc_is_imm16 (ins->inst_imm)) {
2534 NEW_INS (cfg, temp, OP_ICONST);
2535 temp->inst_c0 = ins->inst_imm;
2536 temp->dreg = mono_alloc_ireg (cfg);
2537 ins->sreg2 = temp->dreg;
2538 ins->opcode = map_to_reg_reg_op (ins->opcode);
2541 break;
2542 case OP_IMUL_IMM:
2543 case OP_MUL_IMM:
2544 CASE_PPC64 (OP_LMUL_IMM)
2545 if (ins->inst_imm == 1) {
2546 ins->opcode = OP_MOVE;
2547 break;
2549 if (ins->inst_imm == 0) {
2550 ins->opcode = OP_ICONST;
2551 ins->inst_c0 = 0;
2552 break;
2554 imm = mono_is_power_of_two (ins->inst_imm);
2555 if (imm > 0) {
2556 ins->opcode = OP_SHL_IMM;
2557 ins->inst_imm = imm;
2558 break;
2560 if (!ppc_is_imm16 (ins->inst_imm)) {
2561 NEW_INS (cfg, temp, OP_ICONST);
2562 temp->inst_c0 = ins->inst_imm;
2563 temp->dreg = mono_alloc_ireg (cfg);
2564 ins->sreg2 = temp->dreg;
2565 ins->opcode = map_to_reg_reg_op (ins->opcode);
2567 break;
2568 case OP_LOCALLOC_IMM:
2569 NEW_INS (cfg, temp, OP_ICONST);
2570 temp->inst_c0 = ins->inst_imm;
2571 temp->dreg = mono_alloc_ireg (cfg);
2572 ins->sreg1 = temp->dreg;
2573 ins->opcode = OP_LOCALLOC;
2574 break;
2575 case OP_LOAD_MEMBASE:
2576 case OP_LOADI4_MEMBASE:
2577 CASE_PPC64 (OP_LOADI8_MEMBASE)
2578 case OP_LOADU4_MEMBASE:
2579 case OP_LOADI2_MEMBASE:
2580 case OP_LOADU2_MEMBASE:
2581 case OP_LOADI1_MEMBASE:
2582 case OP_LOADU1_MEMBASE:
2583 case OP_LOADR4_MEMBASE:
2584 case OP_LOADR8_MEMBASE:
2585 case OP_STORE_MEMBASE_REG:
2586 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2587 case OP_STOREI4_MEMBASE_REG:
2588 case OP_STOREI2_MEMBASE_REG:
2589 case OP_STOREI1_MEMBASE_REG:
2590 case OP_STORER4_MEMBASE_REG:
2591 case OP_STORER8_MEMBASE_REG:
2592 /* we can do two things: load the immed in a register
2593 * and use an indexed load, or see if the immed can be
2594 * represented as an ad_imm + a load with a smaller offset
2595 * that fits. We just do the first for now, optimize later.
2597 if (ppc_is_imm16 (ins->inst_offset))
2598 break;
2599 NEW_INS (cfg, temp, OP_ICONST);
2600 temp->inst_c0 = ins->inst_offset;
2601 temp->dreg = mono_alloc_ireg (cfg);
2602 ins->sreg2 = temp->dreg;
2603 ins->opcode = map_to_reg_reg_op (ins->opcode);
2604 break;
2605 case OP_STORE_MEMBASE_IMM:
2606 case OP_STOREI1_MEMBASE_IMM:
2607 case OP_STOREI2_MEMBASE_IMM:
2608 case OP_STOREI4_MEMBASE_IMM:
2609 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2610 NEW_INS (cfg, temp, OP_ICONST);
2611 temp->inst_c0 = ins->inst_imm;
2612 temp->dreg = mono_alloc_ireg (cfg);
2613 ins->sreg1 = temp->dreg;
2614 ins->opcode = map_to_reg_reg_op (ins->opcode);
2615 last_ins = temp;
2616 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2617 case OP_R8CONST:
2618 case OP_R4CONST:
2619 if (cfg->compile_aot) {
2620 /* Keep these in the aot case */
2621 break;
2623 NEW_INS (cfg, temp, OP_ICONST);
2624 temp->inst_c0 = (gulong)ins->inst_p0;
2625 temp->dreg = mono_alloc_ireg (cfg);
2626 ins->inst_basereg = temp->dreg;
2627 ins->inst_offset = 0;
2628 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2629 last_ins = temp;
2630 /* make it handle the possibly big ins->inst_offset
2631 * later optimize to use lis + load_membase
2633 goto loop_start;
2635 last_ins = ins;
2637 bb->last_ins = last_ins;
2638 bb->max_vreg = cfg->next_vreg;
2641 static guchar*
2642 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2644 long offset = cfg->arch.fp_conv_var_offset;
2645 long sub_offset;
2646 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2647 #ifdef __mono_ppc64__
2648 if (size == 8) {
2649 ppc_fctidz (code, ppc_f0, sreg);
2650 sub_offset = 0;
2651 } else
2652 #endif
2654 ppc_fctiwz (code, ppc_f0, sreg);
2655 sub_offset = 4;
2657 if (ppc_is_imm16 (offset + sub_offset)) {
2658 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2659 if (size == 8)
2660 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2661 else
2662 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2663 } else {
2664 ppc_load (code, dreg, offset);
2665 ppc_add (code, dreg, dreg, cfg->frame_reg);
2666 ppc_stfd (code, ppc_f0, 0, dreg);
2667 if (size == 8)
2668 ppc_ldr (code, dreg, sub_offset, dreg);
2669 else
2670 ppc_lwz (code, dreg, sub_offset, dreg);
2672 if (!is_signed) {
2673 if (size == 1)
2674 ppc_andid (code, dreg, dreg, 0xff);
2675 else if (size == 2)
2676 ppc_andid (code, dreg, dreg, 0xffff);
2677 #ifdef __mono_ppc64__
2678 else if (size == 4)
2679 ppc_clrldi (code, dreg, dreg, 32);
2680 #endif
2681 } else {
2682 if (size == 1)
2683 ppc_extsb (code, dreg, dreg);
2684 else if (size == 2)
2685 ppc_extsh (code, dreg, dreg);
2686 #ifdef __mono_ppc64__
2687 else if (size == 4)
2688 ppc_extsw (code, dreg, dreg);
2689 #endif
2691 return code;
2694 static void
2695 emit_thunk (guint8 *code, gconstpointer target)
2697 guint8 *p = code;
2699 /* 2 bytes on 32bit, 5 bytes on 64bit */
2700 ppc_load_sequence (code, ppc_r0, target);
2702 ppc_mtctr (code, ppc_r0);
2703 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2705 mono_arch_flush_icache (p, code - p);
2708 static void
2709 handle_thunk (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
2711 MonoJitInfo *ji = NULL;
2712 MonoThunkJitInfo *info;
2713 guint8 *thunks, *p;
2714 int thunks_size;
2715 guint8 *orig_target;
2716 guint8 *target_thunk;
2718 if (!domain)
2719 domain = mono_domain_get ();
2721 if (cfg) {
2723 * This can be called multiple times during JITting,
2724 * save the current position in cfg->arch to avoid
2725 * doing a O(n^2) search.
2727 if (!cfg->arch.thunks) {
2728 cfg->arch.thunks = cfg->thunks;
2729 cfg->arch.thunks_size = cfg->thunk_area;
2731 thunks = cfg->arch.thunks;
2732 thunks_size = cfg->arch.thunks_size;
2733 if (!thunks_size) {
2734 g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, mono_method_full_name (cfg->method, TRUE));
2735 g_assert_not_reached ();
2738 g_assert (*(guint32*)thunks == 0);
2739 emit_thunk (thunks, target);
2740 ppc_patch (code, thunks);
2742 cfg->arch.thunks += THUNK_SIZE;
2743 cfg->arch.thunks_size -= THUNK_SIZE;
2744 } else {
2745 ji = mini_jit_info_table_find (domain, (char *) code, NULL);
2746 g_assert (ji);
2747 info = mono_jit_info_get_thunk_info (ji);
2748 g_assert (info);
2750 thunks = (guint8 *) ji->code_start + info->thunks_offset;
2751 thunks_size = info->thunks_size;
2753 orig_target = mono_arch_get_call_target (code + 4);
2755 mono_mini_arch_lock ();
2757 target_thunk = NULL;
2758 if (orig_target >= thunks && orig_target < thunks + thunks_size) {
2759 /* The call already points to a thunk, because of trampolines etc. */
2760 target_thunk = orig_target;
2761 } else {
2762 for (p = thunks; p < thunks + thunks_size; p += THUNK_SIZE) {
2763 if (((guint32 *) p) [0] == 0) {
2764 /* Free entry */
2765 target_thunk = p;
2766 break;
2767 } else {
2768 /* ppc64 requires 5 instructions, 32bit two instructions */
2769 #ifdef __mono_ppc64__
2770 const int const_load_size = 5;
2771 #else
2772 const int const_load_size = 2;
2773 #endif
2774 guint32 load [const_load_size];
2775 guchar *templ = (guchar *) load;
2776 ppc_load_sequence (templ, ppc_r0, target);
2777 if (!memcmp (p, load, const_load_size)) {
2778 /* Thunk already points to target */
2779 target_thunk = p;
2780 break;
2786 // g_print ("THUNK: %p %p %p\n", code, target, target_thunk);
2788 if (!target_thunk) {
2789 mono_mini_arch_unlock ();
2790 g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, cfg ? mono_method_full_name (cfg->method, TRUE) : mono_method_full_name (jinfo_get_method (ji), TRUE));
2791 g_assert_not_reached ();
2794 emit_thunk (target_thunk, target);
2795 ppc_patch (code, target_thunk);
2797 mono_mini_arch_unlock ();
2801 static void
2802 patch_ins (guint8 *code, guint32 ins)
2804 *(guint32*)code = ins;
2805 mono_arch_flush_icache (code, 4);
2808 static void
2809 ppc_patch_full (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target, gboolean is_fd)
2811 guint32 ins = *(guint32*)code;
2812 guint32 prim = ins >> 26;
2813 guint32 ovf;
2815 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2816 if (prim == 18) {
2817 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2818 gint diff = target - code;
2819 g_assert (!is_fd);
2820 if (diff >= 0){
2821 if (diff <= 33554431){
2822 ins = (18 << 26) | (diff) | (ins & 1);
2823 patch_ins (code, ins);
2824 return;
2826 } else {
2827 /* diff between 0 and -33554432 */
2828 if (diff >= -33554432){
2829 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2830 patch_ins (code, ins);
2831 return;
2835 if ((glong)target >= 0){
2836 if ((glong)target <= 33554431){
2837 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2838 patch_ins (code, ins);
2839 return;
2841 } else {
2842 if ((glong)target >= -33554432){
2843 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2844 patch_ins (code, ins);
2845 return;
2849 handle_thunk (cfg, domain, code, target);
2850 return;
2852 g_assert_not_reached ();
2856 if (prim == 16) {
2857 g_assert (!is_fd);
2858 // absolute address
2859 if (ins & 2) {
2860 guint32 li = (gulong)target;
2861 ins = (ins & 0xffff0000) | (ins & 3);
2862 ovf = li & 0xffff0000;
2863 if (ovf != 0 && ovf != 0xffff0000)
2864 g_assert_not_reached ();
2865 li &= 0xffff;
2866 ins |= li;
2867 // FIXME: assert the top bits of li are 0
2868 } else {
2869 gint diff = target - code;
2870 ins = (ins & 0xffff0000) | (ins & 3);
2871 ovf = diff & 0xffff0000;
2872 if (ovf != 0 && ovf != 0xffff0000)
2873 g_assert_not_reached ();
2874 diff &= 0xffff;
2875 ins |= diff;
2877 patch_ins (code, ins);
2878 return;
2881 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2882 #ifdef __mono_ppc64__
2883 guint32 *seq = (guint32*)code;
2884 guint32 *branch_ins;
2886 /* the trampoline code will try to patch the blrl, blr, bcctr */
2887 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2888 branch_ins = seq;
2889 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2890 code -= 32;
2891 else
2892 code -= 24;
2893 } else {
2894 if (ppc_is_load_op (seq [5])
2895 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2896 /* With function descs we need to do more careful
2897 matches. */
2898 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
2899 #endif
2901 branch_ins = seq + 8;
2902 else
2903 branch_ins = seq + 6;
2906 seq = (guint32*)code;
2907 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2908 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2910 if (ppc_is_load_op (seq [5])) {
2911 g_assert (ppc_is_load_op (seq [6]));
2913 if (!is_fd) {
2914 guint8 *buf = (guint8*)&seq [5];
2915 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
2916 ppc_nop (buf);
2918 } else {
2919 if (is_fd)
2920 target = mono_get_addr_from_ftnptr ((gpointer)target);
2923 /* FIXME: make this thread safe */
2924 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2925 /* FIXME: we're assuming we're using r12 here */
2926 ppc_load_ptr_sequence (code, ppc_r12, target);
2927 #else
2928 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
2929 #endif
2930 mono_arch_flush_icache ((guint8*)seq, 28);
2931 #else
2932 guint32 *seq;
2933 /* the trampoline code will try to patch the blrl, blr, bcctr */
2934 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2935 code -= 12;
2937 /* this is the lis/ori/mtlr/blrl sequence */
2938 seq = (guint32*)code;
2939 g_assert ((seq [0] >> 26) == 15);
2940 g_assert ((seq [1] >> 26) == 24);
2941 g_assert ((seq [2] >> 26) == 31);
2942 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2943 /* FIXME: make this thread safe */
2944 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
2945 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
2946 mono_arch_flush_icache (code - 8, 8);
2947 #endif
2948 } else {
2949 g_assert_not_reached ();
2951 // g_print ("patched with 0x%08x\n", ins);
2954 void
2955 ppc_patch (guchar *code, const guchar *target)
2957 ppc_patch_full (NULL, NULL, code, target, FALSE);
2960 void
2961 mono_ppc_patch (guchar *code, const guchar *target)
2963 ppc_patch (code, target);
2966 static guint8*
2967 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2969 switch (ins->opcode) {
2970 case OP_FCALL:
2971 case OP_FCALL_REG:
2972 case OP_FCALL_MEMBASE:
2973 if (ins->dreg != ppc_f1)
2974 ppc_fmr (code, ins->dreg, ppc_f1);
2975 break;
2978 return code;
2981 static guint8*
2982 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2984 long size = cfg->param_area;
2986 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2987 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2989 if (!size)
2990 return code;
2992 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
2993 if (ppc_is_imm16 (-size)) {
2994 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
2995 } else {
2996 ppc_load (code, ppc_r12, -size);
2997 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3000 return code;
3003 static guint8*
3004 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3006 long size = cfg->param_area;
3008 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3009 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3011 if (!size)
3012 return code;
3014 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3015 if (ppc_is_imm16 (size)) {
3016 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3017 } else {
3018 ppc_load (code, ppc_r12, size);
3019 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3022 return code;
3025 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3027 #ifndef DISABLE_JIT
3028 void
3029 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3031 MonoInst *ins, *next;
3032 MonoCallInst *call;
3033 guint8 *code = cfg->native_code + cfg->code_len;
3034 MonoInst *last_ins = NULL;
3035 int max_len, cpos;
3036 int L;
3038 /* we don't align basic blocks of loops on ppc */
3040 if (cfg->verbose_level > 2)
3041 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3043 cpos = bb->max_offset;
3045 MONO_BB_FOR_EACH_INS (bb, ins) {
3046 const guint offset = code - cfg->native_code;
3047 set_code_cursor (cfg, code);
3048 max_len = ins_get_size (ins->opcode);
3049 code = realloc_code (cfg, max_len);
3050 // if (ins->cil_code)
3051 // g_print ("cil code\n");
3052 mono_debug_record_line_number (cfg, ins, offset);
3054 switch (normalize_opcode (ins->opcode)) {
3055 case OP_RELAXED_NOP:
3056 case OP_NOP:
3057 case OP_DUMMY_USE:
3058 case OP_DUMMY_ICONST:
3059 case OP_DUMMY_I8CONST:
3060 case OP_DUMMY_R8CONST:
3061 case OP_DUMMY_R4CONST:
3062 case OP_NOT_REACHED:
3063 case OP_NOT_NULL:
3064 break;
3065 case OP_IL_SEQ_POINT:
3066 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3067 break;
3068 case OP_SEQ_POINT: {
3069 int i;
3071 if (cfg->compile_aot)
3072 NOT_IMPLEMENTED;
3075 * Read from the single stepping trigger page. This will cause a
3076 * SIGSEGV when single stepping is enabled.
3077 * We do this _before_ the breakpoint, so single stepping after
3078 * a breakpoint is hit will step to the next IL offset.
3080 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3081 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3082 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3085 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3088 * A placeholder for a possible breakpoint inserted by
3089 * mono_arch_set_breakpoint ().
3091 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3092 ppc_nop (code);
3093 break;
3095 case OP_BIGMUL:
3096 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3097 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3098 ppc_mr (code, ppc_r4, ppc_r0);
3099 break;
3100 case OP_BIGMUL_UN:
3101 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3102 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3103 ppc_mr (code, ppc_r4, ppc_r0);
3104 break;
3105 case OP_MEMORY_BARRIER:
3106 ppc_sync (code);
3107 break;
3108 case OP_STOREI1_MEMBASE_REG:
3109 if (ppc_is_imm16 (ins->inst_offset)) {
3110 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3111 } else {
3112 if (ppc_is_imm32 (ins->inst_offset)) {
3113 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3114 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3115 } else {
3116 ppc_load (code, ppc_r0, ins->inst_offset);
3117 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3120 break;
3121 case OP_STOREI2_MEMBASE_REG:
3122 if (ppc_is_imm16 (ins->inst_offset)) {
3123 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3124 } else {
3125 if (ppc_is_imm32 (ins->inst_offset)) {
3126 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3127 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3128 } else {
3129 ppc_load (code, ppc_r0, ins->inst_offset);
3130 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3133 break;
3134 case OP_STORE_MEMBASE_REG:
3135 if (ppc_is_imm16 (ins->inst_offset)) {
3136 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3137 } else {
3138 if (ppc_is_imm32 (ins->inst_offset)) {
3139 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3140 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3141 } else {
3142 ppc_load (code, ppc_r0, ins->inst_offset);
3143 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3146 break;
3147 #ifdef MONO_ARCH_ILP32
3148 case OP_STOREI8_MEMBASE_REG:
3149 if (ppc_is_imm16 (ins->inst_offset)) {
3150 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3151 } else {
3152 ppc_load (code, ppc_r0, ins->inst_offset);
3153 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3155 break;
3156 #endif
3157 case OP_STOREI1_MEMINDEX:
3158 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3159 break;
3160 case OP_STOREI2_MEMINDEX:
3161 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3162 break;
3163 case OP_STORE_MEMINDEX:
3164 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3165 break;
3166 case OP_LOADU4_MEM:
3167 g_assert_not_reached ();
3168 break;
3169 case OP_LOAD_MEMBASE:
3170 if (ppc_is_imm16 (ins->inst_offset)) {
3171 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3172 } else {
3173 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3174 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3175 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3176 } else {
3177 ppc_load (code, ppc_r0, ins->inst_offset);
3178 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3181 break;
3182 case OP_LOADI4_MEMBASE:
3183 #ifdef __mono_ppc64__
3184 if (ppc_is_imm16 (ins->inst_offset)) {
3185 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3186 } else {
3187 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3188 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3189 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3190 } else {
3191 ppc_load (code, ppc_r0, ins->inst_offset);
3192 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3195 break;
3196 #endif
3197 case OP_LOADU4_MEMBASE:
3198 if (ppc_is_imm16 (ins->inst_offset)) {
3199 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3200 } else {
3201 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3202 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3203 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3204 } else {
3205 ppc_load (code, ppc_r0, ins->inst_offset);
3206 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3209 break;
3210 case OP_LOADI1_MEMBASE:
3211 case OP_LOADU1_MEMBASE:
3212 if (ppc_is_imm16 (ins->inst_offset)) {
3213 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3214 } else {
3215 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3216 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3217 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3218 } else {
3219 ppc_load (code, ppc_r0, ins->inst_offset);
3220 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3223 if (ins->opcode == OP_LOADI1_MEMBASE)
3224 ppc_extsb (code, ins->dreg, ins->dreg);
3225 break;
3226 case OP_LOADU2_MEMBASE:
3227 if (ppc_is_imm16 (ins->inst_offset)) {
3228 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3229 } else {
3230 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3231 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3232 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3233 } else {
3234 ppc_load (code, ppc_r0, ins->inst_offset);
3235 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3238 break;
3239 case OP_LOADI2_MEMBASE:
3240 if (ppc_is_imm16 (ins->inst_offset)) {
3241 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3242 } else {
3243 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3244 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3245 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3246 } else {
3247 ppc_load (code, ppc_r0, ins->inst_offset);
3248 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3251 break;
3252 #ifdef MONO_ARCH_ILP32
3253 case OP_LOADI8_MEMBASE:
3254 if (ppc_is_imm16 (ins->inst_offset)) {
3255 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3256 } else {
3257 ppc_load (code, ppc_r0, ins->inst_offset);
3258 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3260 break;
3261 #endif
3262 case OP_LOAD_MEMINDEX:
3263 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3264 break;
3265 case OP_LOADI4_MEMINDEX:
3266 #ifdef __mono_ppc64__
3267 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3268 break;
3269 #endif
3270 case OP_LOADU4_MEMINDEX:
3271 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3272 break;
3273 case OP_LOADU2_MEMINDEX:
3274 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3275 break;
3276 case OP_LOADI2_MEMINDEX:
3277 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3278 break;
3279 case OP_LOADU1_MEMINDEX:
3280 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3281 break;
3282 case OP_LOADI1_MEMINDEX:
3283 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3284 ppc_extsb (code, ins->dreg, ins->dreg);
3285 break;
3286 case OP_ICONV_TO_I1:
3287 CASE_PPC64 (OP_LCONV_TO_I1)
3288 ppc_extsb (code, ins->dreg, ins->sreg1);
3289 break;
3290 case OP_ICONV_TO_I2:
3291 CASE_PPC64 (OP_LCONV_TO_I2)
3292 ppc_extsh (code, ins->dreg, ins->sreg1);
3293 break;
3294 case OP_ICONV_TO_U1:
3295 CASE_PPC64 (OP_LCONV_TO_U1)
3296 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3297 break;
3298 case OP_ICONV_TO_U2:
3299 CASE_PPC64 (OP_LCONV_TO_U2)
3300 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3301 break;
3302 case OP_COMPARE:
3303 case OP_ICOMPARE:
3304 CASE_PPC64 (OP_LCOMPARE)
3305 L = (sizeof (target_mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3306 next = ins->next;
3307 if (next && compare_opcode_is_unsigned (next->opcode))
3308 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3309 else
3310 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3311 break;
3312 case OP_COMPARE_IMM:
3313 case OP_ICOMPARE_IMM:
3314 CASE_PPC64 (OP_LCOMPARE_IMM)
3315 L = (sizeof (target_mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3316 next = ins->next;
3317 if (next && compare_opcode_is_unsigned (next->opcode)) {
3318 if (ppc_is_uimm16 (ins->inst_imm)) {
3319 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3320 } else {
3321 g_assert_not_reached ();
3323 } else {
3324 if (ppc_is_imm16 (ins->inst_imm)) {
3325 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3326 } else {
3327 g_assert_not_reached ();
3330 break;
3331 case OP_BREAK:
3333 * gdb does not like encountering a trap in the debugged code. So
3334 * instead of emitting a trap, we emit a call a C function and place a
3335 * breakpoint there.
3337 //ppc_break (code);
3338 ppc_mr (code, ppc_r3, ins->sreg1);
3339 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL,
3340 (gpointer)"mono_break");
3341 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3342 ppc_load_func (code, PPC_CALL_REG, 0);
3343 ppc_mtlr (code, PPC_CALL_REG);
3344 ppc_blrl (code);
3345 } else {
3346 ppc_bl (code, 0);
3348 break;
3349 case OP_ADDCC:
3350 case OP_IADDCC:
3351 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3352 break;
3353 case OP_IADD:
3354 CASE_PPC64 (OP_LADD)
3355 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3356 break;
3357 case OP_ADC:
3358 case OP_IADC:
3359 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3360 break;
3361 case OP_ADDCC_IMM:
3362 if (ppc_is_imm16 (ins->inst_imm)) {
3363 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3364 } else {
3365 g_assert_not_reached ();
3367 break;
3368 case OP_ADD_IMM:
3369 case OP_IADD_IMM:
3370 CASE_PPC64 (OP_LADD_IMM)
3371 if (ppc_is_imm16 (ins->inst_imm)) {
3372 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3373 } else {
3374 g_assert_not_reached ();
3376 break;
3377 case OP_IADD_OVF:
3378 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3380 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3381 ppc_mfspr (code, ppc_r0, ppc_xer);
3382 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3383 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3384 break;
3385 case OP_IADD_OVF_UN:
3386 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3388 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3389 ppc_mfspr (code, ppc_r0, ppc_xer);
3390 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3391 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3392 break;
3393 case OP_ISUB_OVF:
3394 CASE_PPC64 (OP_LSUB_OVF)
3395 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3397 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3398 ppc_mfspr (code, ppc_r0, ppc_xer);
3399 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3400 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3401 break;
3402 case OP_ISUB_OVF_UN:
3403 CASE_PPC64 (OP_LSUB_OVF_UN)
3404 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3406 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3407 ppc_mfspr (code, ppc_r0, ppc_xer);
3408 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3409 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3410 break;
3411 case OP_ADD_OVF_CARRY:
3412 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3414 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3415 ppc_mfspr (code, ppc_r0, ppc_xer);
3416 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3417 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3418 break;
3419 case OP_ADD_OVF_UN_CARRY:
3420 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3422 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3423 ppc_mfspr (code, ppc_r0, ppc_xer);
3424 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3425 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3426 break;
3427 case OP_SUB_OVF_CARRY:
3428 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3430 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3431 ppc_mfspr (code, ppc_r0, ppc_xer);
3432 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3433 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3434 break;
3435 case OP_SUB_OVF_UN_CARRY:
3436 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3438 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3439 ppc_mfspr (code, ppc_r0, ppc_xer);
3440 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3441 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3442 break;
3443 case OP_SUBCC:
3444 case OP_ISUBCC:
3445 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3446 break;
3447 case OP_ISUB:
3448 CASE_PPC64 (OP_LSUB)
3449 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3450 break;
3451 case OP_SBB:
3452 case OP_ISBB:
3453 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3454 break;
3455 case OP_SUB_IMM:
3456 case OP_ISUB_IMM:
3457 CASE_PPC64 (OP_LSUB_IMM)
3458 // we add the negated value
3459 if (ppc_is_imm16 (-ins->inst_imm))
3460 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3461 else {
3462 g_assert_not_reached ();
3464 break;
3465 case OP_PPC_SUBFIC:
3466 g_assert (ppc_is_imm16 (ins->inst_imm));
3467 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3468 break;
3469 case OP_PPC_SUBFZE:
3470 ppc_subfze (code, ins->dreg, ins->sreg1);
3471 break;
3472 case OP_IAND:
3473 CASE_PPC64 (OP_LAND)
3474 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3475 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3476 break;
3477 case OP_AND_IMM:
3478 case OP_IAND_IMM:
3479 CASE_PPC64 (OP_LAND_IMM)
3480 if (!(ins->inst_imm & 0xffff0000)) {
3481 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3482 } else if (!(ins->inst_imm & 0xffff)) {
3483 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3484 } else {
3485 g_assert_not_reached ();
3487 break;
3488 case OP_IDIV:
3489 CASE_PPC64 (OP_LDIV) {
3490 guint8 *divisor_is_m1;
3491 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3493 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3494 divisor_is_m1 = code;
3495 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3496 ppc_lis (code, ppc_r0, 0x8000);
3497 #ifdef __mono_ppc64__
3498 if (ins->opcode == OP_LDIV)
3499 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3500 #endif
3501 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3502 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3503 ppc_patch (divisor_is_m1, code);
3504 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3506 if (ins->opcode == OP_IDIV)
3507 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3508 #ifdef __mono_ppc64__
3509 else
3510 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3511 #endif
3512 ppc_mfspr (code, ppc_r0, ppc_xer);
3513 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3514 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3515 break;
3517 case OP_IDIV_UN:
3518 CASE_PPC64 (OP_LDIV_UN)
3519 if (ins->opcode == OP_IDIV_UN)
3520 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3521 #ifdef __mono_ppc64__
3522 else
3523 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3524 #endif
3525 ppc_mfspr (code, ppc_r0, ppc_xer);
3526 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3527 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3528 break;
3529 case OP_DIV_IMM:
3530 case OP_IREM:
3531 case OP_IREM_UN:
3532 case OP_REM_IMM:
3533 g_assert_not_reached ();
3534 case OP_IOR:
3535 CASE_PPC64 (OP_LOR)
3536 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3537 break;
3538 case OP_OR_IMM:
3539 case OP_IOR_IMM:
3540 CASE_PPC64 (OP_LOR_IMM)
3541 if (!(ins->inst_imm & 0xffff0000)) {
3542 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3543 } else if (!(ins->inst_imm & 0xffff)) {
3544 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3545 } else {
3546 g_assert_not_reached ();
3548 break;
3549 case OP_IXOR:
3550 CASE_PPC64 (OP_LXOR)
3551 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3552 break;
3553 case OP_IXOR_IMM:
3554 case OP_XOR_IMM:
3555 CASE_PPC64 (OP_LXOR_IMM)
3556 if (!(ins->inst_imm & 0xffff0000)) {
3557 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3558 } else if (!(ins->inst_imm & 0xffff)) {
3559 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3560 } else {
3561 g_assert_not_reached ();
3563 break;
3564 case OP_ISHL:
3565 CASE_PPC64 (OP_LSHL)
3566 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3567 break;
3568 case OP_SHL_IMM:
3569 case OP_ISHL_IMM:
3570 CASE_PPC64 (OP_LSHL_IMM)
3571 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3572 break;
3573 case OP_ISHR:
3574 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3575 break;
3576 case OP_SHR_IMM:
3577 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3578 break;
3579 case OP_SHR_UN_IMM:
3580 if (MASK_SHIFT_IMM (ins->inst_imm))
3581 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3582 else
3583 ppc_mr (code, ins->dreg, ins->sreg1);
3584 break;
3585 case OP_ISHR_UN:
3586 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3587 break;
3588 case OP_INOT:
3589 CASE_PPC64 (OP_LNOT)
3590 ppc_not (code, ins->dreg, ins->sreg1);
3591 break;
3592 case OP_INEG:
3593 CASE_PPC64 (OP_LNEG)
3594 ppc_neg (code, ins->dreg, ins->sreg1);
3595 break;
3596 case OP_IMUL:
3597 CASE_PPC64 (OP_LMUL)
3598 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3599 break;
3600 case OP_IMUL_IMM:
3601 case OP_MUL_IMM:
3602 CASE_PPC64 (OP_LMUL_IMM)
3603 if (ppc_is_imm16 (ins->inst_imm)) {
3604 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3605 } else {
3606 g_assert_not_reached ();
3608 break;
3609 case OP_IMUL_OVF:
3610 CASE_PPC64 (OP_LMUL_OVF)
3611 /* we annot use mcrxr, since it's not implemented on some processors
3612 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3614 if (ins->opcode == OP_IMUL_OVF)
3615 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3616 #ifdef __mono_ppc64__
3617 else
3618 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3619 #endif
3620 ppc_mfspr (code, ppc_r0, ppc_xer);
3621 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3622 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3623 break;
3624 case OP_IMUL_OVF_UN:
3625 CASE_PPC64 (OP_LMUL_OVF_UN)
3626 /* we first multiply to get the high word and compare to 0
3627 * to set the flags, then the result is discarded and then
3628 * we multiply to get the lower * bits result
3630 if (ins->opcode == OP_IMUL_OVF_UN)
3631 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3632 #ifdef __mono_ppc64__
3633 else
3634 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3635 #endif
3636 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3637 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3638 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3639 break;
3640 case OP_ICONST:
3641 ppc_load (code, ins->dreg, ins->inst_c0);
3642 break;
3643 case OP_I8CONST: {
3644 ppc_load (code, ins->dreg, ins->inst_l);
3645 break;
3647 case OP_LOAD_GOTADDR:
3648 /* The PLT implementation depends on this */
3649 g_assert (ins->dreg == ppc_r30);
3651 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3652 break;
3653 case OP_GOT_ENTRY:
3654 // FIXME: Fix max instruction length
3655 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3656 /* arch_emit_got_access () patches this */
3657 ppc_load32 (code, ppc_r0, 0);
3658 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3659 break;
3660 case OP_AOTCONST:
3661 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3662 ppc_load_sequence (code, ins->dreg, 0);
3663 break;
3664 CASE_PPC32 (OP_ICONV_TO_I4)
3665 CASE_PPC32 (OP_ICONV_TO_U4)
3666 case OP_MOVE:
3667 if (ins->dreg != ins->sreg1)
3668 ppc_mr (code, ins->dreg, ins->sreg1);
3669 break;
3670 case OP_SETLRET: {
3671 int saved = ins->sreg1;
3672 if (ins->sreg1 == ppc_r3) {
3673 ppc_mr (code, ppc_r0, ins->sreg1);
3674 saved = ppc_r0;
3676 if (ins->sreg2 != ppc_r3)
3677 ppc_mr (code, ppc_r3, ins->sreg2);
3678 if (saved != ppc_r4)
3679 ppc_mr (code, ppc_r4, saved);
3680 break;
3682 case OP_FMOVE:
3683 if (ins->dreg != ins->sreg1)
3684 ppc_fmr (code, ins->dreg, ins->sreg1);
3685 break;
3686 case OP_MOVE_F_TO_I4:
3687 ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3688 ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3689 break;
3690 case OP_MOVE_I4_TO_F:
3691 ppc_stw (code, ins->sreg1, -4, ppc_r1);
3692 ppc_lfs (code, ins->dreg, -4, ppc_r1);
3693 break;
3694 #ifdef __mono_ppc64__
3695 case OP_MOVE_F_TO_I8:
3696 ppc_stfd (code, ins->sreg1, -8, ppc_r1);
3697 ppc_ldptr (code, ins->dreg, -8, ppc_r1);
3698 break;
3699 case OP_MOVE_I8_TO_F:
3700 ppc_stptr (code, ins->sreg1, -8, ppc_r1);
3701 ppc_lfd (code, ins->dreg, -8, ppc_r1);
3702 break;
3703 #endif
3704 case OP_FCONV_TO_R4:
3705 ppc_frsp (code, ins->dreg, ins->sreg1);
3706 break;
3708 case OP_TAILCALL_PARAMETER:
3709 // This opcode helps compute sizes, i.e.
3710 // of the subsequent OP_TAILCALL, but contributes no code.
3711 g_assert (ins->next);
3712 break;
3714 case OP_TAILCALL: {
3715 int i, pos;
3716 MonoCallInst *call = (MonoCallInst*)ins;
3719 * Keep in sync with mono_arch_emit_epilog
3721 g_assert (!cfg->method->save_lmf);
3723 * Note: we can use ppc_r12 here because it is dead anyway:
3724 * we're leaving the method.
3726 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3727 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3728 if (ppc_is_imm16 (ret_offset)) {
3729 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3730 } else {
3731 ppc_load (code, ppc_r12, ret_offset);
3732 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3734 ppc_mtlr (code, ppc_r0);
3737 if (ppc_is_imm16 (cfg->stack_usage)) {
3738 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3739 } else {
3740 /* cfg->stack_usage is an int, so we can use
3741 * an addis/addi sequence here even in 64-bit. */
3742 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3743 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3745 if (!cfg->method->save_lmf) {
3746 pos = 0;
3747 for (i = 31; i >= 13; --i) {
3748 if (cfg->used_int_regs & (1 << i)) {
3749 pos += sizeof (target_mgreg_t);
3750 ppc_ldptr (code, i, -pos, ppc_r12);
3753 } else {
3754 /* FIXME restore from MonoLMF: though this can't happen yet */
3757 /* Copy arguments on the stack to our argument area */
3758 if (call->stack_usage) {
3759 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3760 /* r12 was clobbered */
3761 g_assert (cfg->frame_reg == ppc_sp);
3762 if (ppc_is_imm16 (cfg->stack_usage)) {
3763 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3764 } else {
3765 /* cfg->stack_usage is an int, so we can use
3766 * an addis/addi sequence here even in 64-bit. */
3767 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3768 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3772 ppc_mr (code, ppc_sp, ppc_r12);
3773 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3774 cfg->thunk_area += THUNK_SIZE;
3775 if (cfg->compile_aot) {
3776 /* arch_emit_got_access () patches this */
3777 ppc_load32 (code, ppc_r0, 0);
3778 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3779 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3780 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3781 #else
3782 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3783 #endif
3784 ppc_mtctr (code, ppc_r0);
3785 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3786 } else {
3787 ppc_b (code, 0);
3789 break;
3791 case OP_CHECK_THIS:
3792 /* ensure ins->sreg1 is not NULL */
3793 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3794 break;
3795 case OP_ARGLIST: {
3796 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3797 if (ppc_is_imm16 (cookie_offset)) {
3798 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3799 } else {
3800 ppc_load (code, ppc_r0, cookie_offset);
3801 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3803 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3804 break;
3806 case OP_FCALL:
3807 case OP_LCALL:
3808 case OP_VCALL:
3809 case OP_VCALL2:
3810 case OP_VOIDCALL:
3811 case OP_CALL:
3812 call = (MonoCallInst*)ins;
3813 if (ins->flags & MONO_INST_HAS_METHOD)
3814 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3815 else
3816 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3817 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3818 ppc_load_func (code, PPC_CALL_REG, 0);
3819 ppc_mtlr (code, PPC_CALL_REG);
3820 ppc_blrl (code);
3821 } else {
3822 ppc_bl (code, 0);
3824 /* FIXME: this should be handled somewhere else in the new jit */
3825 code = emit_move_return_value (cfg, ins, code);
3826 break;
3827 case OP_FCALL_REG:
3828 case OP_LCALL_REG:
3829 case OP_VCALL_REG:
3830 case OP_VCALL2_REG:
3831 case OP_VOIDCALL_REG:
3832 case OP_CALL_REG:
3833 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3834 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3835 /* FIXME: if we know that this is a method, we
3836 can omit this load */
3837 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3838 ppc_mtlr (code, ppc_r0);
3839 #else
3840 #if (_CALL_ELF == 2)
3841 if (ins->flags & MONO_INST_HAS_METHOD) {
3842 // Not a global entry point
3843 } else {
3844 // Need to set up r12 with function entry address for global entry point
3845 if (ppc_r12 != ins->sreg1) {
3846 ppc_mr(code,ppc_r12,ins->sreg1);
3849 #endif
3850 ppc_mtlr (code, ins->sreg1);
3851 #endif
3852 ppc_blrl (code);
3853 /* FIXME: this should be handled somewhere else in the new jit */
3854 code = emit_move_return_value (cfg, ins, code);
3855 break;
3856 case OP_FCALL_MEMBASE:
3857 case OP_LCALL_MEMBASE:
3858 case OP_VCALL_MEMBASE:
3859 case OP_VCALL2_MEMBASE:
3860 case OP_VOIDCALL_MEMBASE:
3861 case OP_CALL_MEMBASE:
3862 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3863 /* The trampolines clobber this */
3864 ppc_mr (code, ppc_r29, ins->sreg1);
3865 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3866 } else {
3867 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3869 ppc_mtlr (code, ppc_r0);
3870 ppc_blrl (code);
3871 /* FIXME: this should be handled somewhere else in the new jit */
3872 code = emit_move_return_value (cfg, ins, code);
3873 break;
3874 case OP_LOCALLOC: {
3875 guint8 * zero_loop_jump, * zero_loop_start;
3876 /* keep alignment */
3877 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3878 int area_offset = alloca_waste;
3879 area_offset &= ~31;
3880 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
3881 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3882 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
3883 /* use ctr to store the number of words to 0 if needed */
3884 if (ins->flags & MONO_INST_INIT) {
3885 /* we zero 4 bytes at a time:
3886 * we add 7 instead of 3 so that we set the counter to
3887 * at least 1, otherwise the bdnz instruction will make
3888 * it negative and iterate billions of times.
3890 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3891 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3892 ppc_mtctr (code, ppc_r0);
3894 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3895 ppc_neg (code, ppc_r12, ppc_r12);
3896 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3898 /* FIXME: make this loop work in 8 byte
3899 increments on PPC64 */
3900 if (ins->flags & MONO_INST_INIT) {
3901 /* adjust the dest reg by -4 so we can use stwu */
3902 /* we actually adjust -8 because we let the loop
3903 * run at least once
3905 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3906 ppc_li (code, ppc_r12, 0);
3907 zero_loop_start = code;
3908 ppc_stwu (code, ppc_r12, 4, ins->dreg);
3909 zero_loop_jump = code;
3910 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3911 ppc_patch (zero_loop_jump, zero_loop_start);
3913 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3914 break;
3916 case OP_THROW: {
3917 //ppc_break (code);
3918 ppc_mr (code, ppc_r3, ins->sreg1);
3919 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL,
3920 (gpointer)"mono_arch_throw_exception");
3921 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3922 ppc_load_func (code, PPC_CALL_REG, 0);
3923 ppc_mtlr (code, PPC_CALL_REG);
3924 ppc_blrl (code);
3925 } else {
3926 ppc_bl (code, 0);
3928 break;
3930 case OP_RETHROW: {
3931 //ppc_break (code);
3932 ppc_mr (code, ppc_r3, ins->sreg1);
3933 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL,
3934 (gpointer)"mono_arch_rethrow_exception");
3935 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3936 ppc_load_func (code, PPC_CALL_REG, 0);
3937 ppc_mtlr (code, PPC_CALL_REG);
3938 ppc_blrl (code);
3939 } else {
3940 ppc_bl (code, 0);
3942 break;
3944 case OP_START_HANDLER: {
3945 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3946 g_assert (spvar->inst_basereg != ppc_sp);
3947 code = emit_reserve_param_area (cfg, code);
3948 ppc_mflr (code, ppc_r0);
3949 if (ppc_is_imm16 (spvar->inst_offset)) {
3950 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3951 } else {
3952 ppc_load (code, ppc_r12, spvar->inst_offset);
3953 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
3955 break;
3957 case OP_ENDFILTER: {
3958 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3959 g_assert (spvar->inst_basereg != ppc_sp);
3960 code = emit_unreserve_param_area (cfg, code);
3961 if (ins->sreg1 != ppc_r3)
3962 ppc_mr (code, ppc_r3, ins->sreg1);
3963 if (ppc_is_imm16 (spvar->inst_offset)) {
3964 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3965 } else {
3966 ppc_load (code, ppc_r12, spvar->inst_offset);
3967 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
3969 ppc_mtlr (code, ppc_r0);
3970 ppc_blr (code);
3971 break;
3973 case OP_ENDFINALLY: {
3974 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3975 g_assert (spvar->inst_basereg != ppc_sp);
3976 code = emit_unreserve_param_area (cfg, code);
3977 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3978 ppc_mtlr (code, ppc_r0);
3979 ppc_blr (code);
3980 break;
3982 case OP_CALL_HANDLER:
3983 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3984 ppc_bl (code, 0);
3985 for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
3986 mono_cfg_add_try_hole (cfg, ((MonoLeaveClause *) tmp->data)->clause, code, bb);
3987 break;
3988 case OP_LABEL:
3989 ins->inst_c0 = code - cfg->native_code;
3990 break;
3991 case OP_BR:
3992 /*if (ins->inst_target_bb->native_offset) {
3993 ppc_b (code, 0);
3994 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3995 } else*/ {
3996 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3997 ppc_b (code, 0);
3999 break;
4000 case OP_BR_REG:
4001 ppc_mtctr (code, ins->sreg1);
4002 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4003 break;
4004 case OP_ICNEQ:
4005 ppc_li (code, ins->dreg, 0);
4006 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 2);
4007 ppc_li (code, ins->dreg, 1);
4008 break;
4009 case OP_CEQ:
4010 case OP_ICEQ:
4011 CASE_PPC64 (OP_LCEQ)
4012 ppc_li (code, ins->dreg, 0);
4013 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4014 ppc_li (code, ins->dreg, 1);
4015 break;
4016 case OP_CLT:
4017 case OP_CLT_UN:
4018 case OP_ICLT:
4019 case OP_ICLT_UN:
4020 CASE_PPC64 (OP_LCLT)
4021 CASE_PPC64 (OP_LCLT_UN)
4022 ppc_li (code, ins->dreg, 1);
4023 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4024 ppc_li (code, ins->dreg, 0);
4025 break;
4026 case OP_ICGE:
4027 case OP_ICGE_UN:
4028 ppc_li (code, ins->dreg, 1);
4029 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 2);
4030 ppc_li (code, ins->dreg, 0);
4031 break;
4032 case OP_CGT:
4033 case OP_CGT_UN:
4034 case OP_ICGT:
4035 case OP_ICGT_UN:
4036 CASE_PPC64 (OP_LCGT)
4037 CASE_PPC64 (OP_LCGT_UN)
4038 ppc_li (code, ins->dreg, 1);
4039 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4040 ppc_li (code, ins->dreg, 0);
4041 break;
4042 case OP_ICLE:
4043 case OP_ICLE_UN:
4044 ppc_li (code, ins->dreg, 1);
4045 ppc_bc (code, PPC_BR_FALSE, PPC_BR_GT, 2);
4046 ppc_li (code, ins->dreg, 0);
4047 break;
4048 case OP_COND_EXC_EQ:
4049 case OP_COND_EXC_NE_UN:
4050 case OP_COND_EXC_LT:
4051 case OP_COND_EXC_LT_UN:
4052 case OP_COND_EXC_GT:
4053 case OP_COND_EXC_GT_UN:
4054 case OP_COND_EXC_GE:
4055 case OP_COND_EXC_GE_UN:
4056 case OP_COND_EXC_LE:
4057 case OP_COND_EXC_LE_UN:
4058 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4059 break;
4060 case OP_COND_EXC_IEQ:
4061 case OP_COND_EXC_INE_UN:
4062 case OP_COND_EXC_ILT:
4063 case OP_COND_EXC_ILT_UN:
4064 case OP_COND_EXC_IGT:
4065 case OP_COND_EXC_IGT_UN:
4066 case OP_COND_EXC_IGE:
4067 case OP_COND_EXC_IGE_UN:
4068 case OP_COND_EXC_ILE:
4069 case OP_COND_EXC_ILE_UN:
4070 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4071 break;
4072 case OP_IBEQ:
4073 case OP_IBNE_UN:
4074 case OP_IBLT:
4075 case OP_IBLT_UN:
4076 case OP_IBGT:
4077 case OP_IBGT_UN:
4078 case OP_IBGE:
4079 case OP_IBGE_UN:
4080 case OP_IBLE:
4081 case OP_IBLE_UN:
4082 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4083 break;
4085 /* floating point opcodes */
4086 case OP_R8CONST:
4087 g_assert (cfg->compile_aot);
4089 /* FIXME: Optimize this */
4090 ppc_bl (code, 1);
4091 ppc_mflr (code, ppc_r12);
4092 ppc_b (code, 3);
4093 *(double*)code = *(double*)ins->inst_p0;
4094 code += 8;
4095 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4096 break;
4097 case OP_R4CONST:
4098 g_assert_not_reached ();
4099 break;
4100 case OP_STORER8_MEMBASE_REG:
4101 if (ppc_is_imm16 (ins->inst_offset)) {
4102 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4103 } else {
4104 if (ppc_is_imm32 (ins->inst_offset)) {
4105 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4106 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4107 } else {
4108 ppc_load (code, ppc_r0, ins->inst_offset);
4109 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4112 break;
4113 case OP_LOADR8_MEMBASE:
4114 if (ppc_is_imm16 (ins->inst_offset)) {
4115 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4116 } else {
4117 if (ppc_is_imm32 (ins->inst_offset)) {
4118 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4119 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4120 } else {
4121 ppc_load (code, ppc_r0, ins->inst_offset);
4122 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4125 break;
4126 case OP_STORER4_MEMBASE_REG:
4127 ppc_frsp (code, ins->sreg1, ins->sreg1);
4128 if (ppc_is_imm16 (ins->inst_offset)) {
4129 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4130 } else {
4131 if (ppc_is_imm32 (ins->inst_offset)) {
4132 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4133 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4134 } else {
4135 ppc_load (code, ppc_r0, ins->inst_offset);
4136 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4139 break;
4140 case OP_LOADR4_MEMBASE:
4141 if (ppc_is_imm16 (ins->inst_offset)) {
4142 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4143 } else {
4144 if (ppc_is_imm32 (ins->inst_offset)) {
4145 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4146 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4147 } else {
4148 ppc_load (code, ppc_r0, ins->inst_offset);
4149 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4152 break;
4153 case OP_LOADR4_MEMINDEX:
4154 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4155 break;
4156 case OP_LOADR8_MEMINDEX:
4157 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4158 break;
4159 case OP_STORER4_MEMINDEX:
4160 ppc_frsp (code, ins->sreg1, ins->sreg1);
4161 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4162 break;
4163 case OP_STORER8_MEMINDEX:
4164 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4165 break;
4166 case CEE_CONV_R_UN:
4167 case CEE_CONV_R4: /* FIXME: change precision */
4168 case CEE_CONV_R8:
4169 g_assert_not_reached ();
4170 case OP_FCONV_TO_I1:
4171 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4172 break;
4173 case OP_FCONV_TO_U1:
4174 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4175 break;
4176 case OP_FCONV_TO_I2:
4177 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4178 break;
4179 case OP_FCONV_TO_U2:
4180 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4181 break;
4182 case OP_FCONV_TO_I4:
4183 case OP_FCONV_TO_I:
4184 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4185 break;
4186 case OP_FCONV_TO_U4:
4187 case OP_FCONV_TO_U:
4188 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4189 break;
4190 case OP_LCONV_TO_R_UN:
4191 g_assert_not_reached ();
4192 /* Implemented as helper calls */
4193 break;
4194 case OP_LCONV_TO_OVF_I4_2:
4195 case OP_LCONV_TO_OVF_I: {
4196 #ifdef __mono_ppc64__
4197 NOT_IMPLEMENTED;
4198 #else
4199 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4200 // Check if its negative
4201 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4202 negative_branch = code;
4203 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4204 // Its positive msword == 0
4205 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4206 msword_positive_branch = code;
4207 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4209 ovf_ex_target = code;
4210 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4211 // Negative
4212 ppc_patch (negative_branch, code);
4213 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4214 msword_negative_branch = code;
4215 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4216 ppc_patch (msword_negative_branch, ovf_ex_target);
4218 ppc_patch (msword_positive_branch, code);
4219 if (ins->dreg != ins->sreg1)
4220 ppc_mr (code, ins->dreg, ins->sreg1);
4221 break;
4222 #endif
4224 case OP_ROUND:
4225 ppc_frind (code, ins->dreg, ins->sreg1);
4226 break;
4227 case OP_PPC_TRUNC:
4228 ppc_frizd (code, ins->dreg, ins->sreg1);
4229 break;
4230 case OP_PPC_CEIL:
4231 ppc_fripd (code, ins->dreg, ins->sreg1);
4232 break;
4233 case OP_PPC_FLOOR:
4234 ppc_frimd (code, ins->dreg, ins->sreg1);
4235 break;
4236 case OP_ABS:
4237 ppc_fabsd (code, ins->dreg, ins->sreg1);
4238 break;
4239 case OP_SQRTF:
4240 ppc_fsqrtsd (code, ins->dreg, ins->sreg1);
4241 break;
4242 case OP_SQRT:
4243 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4244 break;
4245 case OP_FADD:
4246 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4247 break;
4248 case OP_FSUB:
4249 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4250 break;
4251 case OP_FMUL:
4252 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4253 break;
4254 case OP_FDIV:
4255 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4256 break;
4257 case OP_FNEG:
4258 ppc_fneg (code, ins->dreg, ins->sreg1);
4259 break;
4260 case OP_FREM:
4261 /* emulated */
4262 g_assert_not_reached ();
4263 break;
4264 /* These min/max require POWER5 */
4265 case OP_IMIN:
4266 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
4267 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4268 break;
4269 case OP_IMIN_UN:
4270 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
4271 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4272 break;
4273 case OP_IMAX:
4274 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
4275 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4276 break;
4277 case OP_IMAX_UN:
4278 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
4279 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4280 break;
4281 CASE_PPC64 (OP_LMIN)
4282 ppc_cmpl (code, 0, 1, ins->sreg1, ins->sreg2);
4283 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4284 break;
4285 CASE_PPC64 (OP_LMIN_UN)
4286 ppc_cmpl (code, 0, 1, ins->sreg1, ins->sreg2);
4287 ppc_isellt (code, ins->dreg, ins->sreg1, ins->sreg2);
4288 break;
4289 CASE_PPC64 (OP_LMAX)
4290 ppc_cmp (code, 0, 1, ins->sreg1, ins->sreg2);
4291 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4292 break;
4293 CASE_PPC64 (OP_LMAX_UN)
4294 ppc_cmpl (code, 0, 1, ins->sreg1, ins->sreg2);
4295 ppc_iselgt (code, ins->dreg, ins->sreg1, ins->sreg2);
4296 break;
4297 case OP_FCOMPARE:
4298 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4299 break;
4300 case OP_FCEQ:
4301 case OP_FCNEQ:
4302 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4303 ppc_li (code, ins->dreg, 1);
4304 ppc_bc (code, ins->opcode == OP_FCEQ ? PPC_BR_TRUE : PPC_BR_FALSE, PPC_BR_EQ, 2);
4305 ppc_li (code, ins->dreg, 0);
4306 break;
4307 case OP_FCLT:
4308 case OP_FCGE:
4309 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4310 ppc_li (code, ins->dreg, 1);
4311 ppc_bc (code, ins->opcode == OP_FCLT ? PPC_BR_TRUE : PPC_BR_FALSE, PPC_BR_LT, 2);
4312 ppc_li (code, ins->dreg, 0);
4313 break;
4314 case OP_FCLT_UN:
4315 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4316 ppc_li (code, ins->dreg, 1);
4317 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4318 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4319 ppc_li (code, ins->dreg, 0);
4320 break;
4321 case OP_FCGT:
4322 case OP_FCLE:
4323 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4324 ppc_li (code, ins->dreg, 1);
4325 ppc_bc (code, ins->opcode == OP_FCGT ? PPC_BR_TRUE : PPC_BR_FALSE, PPC_BR_GT, 2);
4326 ppc_li (code, ins->dreg, 0);
4327 break;
4328 case OP_FCGT_UN:
4329 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4330 ppc_li (code, ins->dreg, 1);
4331 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4332 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4333 ppc_li (code, ins->dreg, 0);
4334 break;
4335 case OP_FBEQ:
4336 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4337 break;
4338 case OP_FBNE_UN:
4339 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4340 break;
4341 case OP_FBLT:
4342 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4343 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4344 break;
4345 case OP_FBLT_UN:
4346 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4347 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4348 break;
4349 case OP_FBGT:
4350 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4351 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4352 break;
4353 case OP_FBGT_UN:
4354 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4355 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4356 break;
4357 case OP_FBGE:
4358 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4359 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4360 break;
4361 case OP_FBGE_UN:
4362 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4363 break;
4364 case OP_FBLE:
4365 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4366 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4367 break;
4368 case OP_FBLE_UN:
4369 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4370 break;
4371 case OP_CKFINITE:
4372 g_assert_not_reached ();
4373 case OP_PPC_CHECK_FINITE: {
4374 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4375 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4376 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4377 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4378 break;
4379 case OP_JUMP_TABLE:
4380 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4381 #ifdef __mono_ppc64__
4382 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4383 #else
4384 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4385 #endif
4386 break;
4389 #ifdef __mono_ppc64__
4390 case OP_ICONV_TO_I4:
4391 case OP_SEXT_I4:
4392 ppc_extsw (code, ins->dreg, ins->sreg1);
4393 break;
4394 case OP_ICONV_TO_U4:
4395 case OP_ZEXT_I4:
4396 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4397 break;
4398 case OP_ICONV_TO_R4:
4399 case OP_ICONV_TO_R8:
4400 case OP_LCONV_TO_R4:
4401 case OP_LCONV_TO_R8: {
4402 int tmp;
4403 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4404 ppc_extsw (code, ppc_r0, ins->sreg1);
4405 tmp = ppc_r0;
4406 } else {
4407 tmp = ins->sreg1;
4409 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4410 ppc_mffgpr (code, ins->dreg, tmp);
4411 } else {
4412 ppc_str (code, tmp, -8, ppc_r1);
4413 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4415 ppc_fcfid (code, ins->dreg, ins->dreg);
4416 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4417 ppc_frsp (code, ins->dreg, ins->dreg);
4418 break;
4420 case OP_LSHR:
4421 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4422 break;
4423 case OP_LSHR_UN:
4424 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4425 break;
4426 case OP_COND_EXC_C:
4427 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4429 ppc_mfspr (code, ppc_r0, ppc_xer);
4430 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4431 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4432 break;
4433 case OP_COND_EXC_OV:
4434 ppc_mfspr (code, ppc_r0, ppc_xer);
4435 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4436 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4437 break;
4438 case OP_LBEQ:
4439 case OP_LBNE_UN:
4440 case OP_LBLT:
4441 case OP_LBLT_UN:
4442 case OP_LBGT:
4443 case OP_LBGT_UN:
4444 case OP_LBGE:
4445 case OP_LBGE_UN:
4446 case OP_LBLE:
4447 case OP_LBLE_UN:
4448 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4449 break;
4450 case OP_FCONV_TO_I8:
4451 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4452 break;
4453 case OP_FCONV_TO_U8:
4454 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4455 break;
4456 case OP_STOREI4_MEMBASE_REG:
4457 if (ppc_is_imm16 (ins->inst_offset)) {
4458 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4459 } else {
4460 ppc_load (code, ppc_r0, ins->inst_offset);
4461 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4463 break;
4464 case OP_STOREI4_MEMINDEX:
4465 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4466 break;
4467 case OP_ISHR_IMM:
4468 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4469 break;
4470 case OP_ISHR_UN_IMM:
4471 if (ins->inst_imm & 0x1f)
4472 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4473 else
4474 ppc_mr (code, ins->dreg, ins->sreg1);
4475 break;
4476 #else
4477 case OP_ICONV_TO_R4:
4478 case OP_ICONV_TO_R8: {
4479 if (cpu_hw_caps & PPC_ISA_64) {
4480 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4481 ppc_stw (code, ppc_r0, -8, ppc_r1);
4482 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4483 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4484 ppc_fcfid (code, ins->dreg, ins->dreg);
4485 if (ins->opcode == OP_ICONV_TO_R4)
4486 ppc_frsp (code, ins->dreg, ins->dreg);
4488 break;
4490 #endif
4492 case OP_ATOMIC_ADD_I4:
4493 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4494 int location = ins->inst_basereg;
4495 int addend = ins->sreg2;
4496 guint8 *loop, *branch;
4497 g_assert (ins->inst_offset == 0);
4499 loop = code;
4500 ppc_sync (code);
4501 if (ins->opcode == OP_ATOMIC_ADD_I4)
4502 ppc_lwarx (code, ppc_r0, 0, location);
4503 #ifdef __mono_ppc64__
4504 else
4505 ppc_ldarx (code, ppc_r0, 0, location);
4506 #endif
4508 ppc_add (code, ppc_r0, ppc_r0, addend);
4510 if (ins->opcode == OP_ATOMIC_ADD_I4)
4511 ppc_stwcxd (code, ppc_r0, 0, location);
4512 #ifdef __mono_ppc64__
4513 else
4514 ppc_stdcxd (code, ppc_r0, 0, location);
4515 #endif
4517 branch = code;
4518 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4519 ppc_patch (branch, loop);
4521 ppc_sync (code);
4522 ppc_mr (code, ins->dreg, ppc_r0);
4523 break;
4525 case OP_ATOMIC_CAS_I4:
4526 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4527 int location = ins->sreg1;
4528 int value = ins->sreg2;
4529 int comparand = ins->sreg3;
4530 guint8 *start, *not_equal, *lost_reservation;
4532 start = code;
4533 ppc_sync (code);
4534 if (ins->opcode == OP_ATOMIC_CAS_I4)
4535 ppc_lwarx (code, ppc_r0, 0, location);
4536 #ifdef __mono_ppc64__
4537 else
4538 ppc_ldarx (code, ppc_r0, 0, location);
4539 #endif
4541 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4542 not_equal = code;
4543 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4545 if (ins->opcode == OP_ATOMIC_CAS_I4)
4546 ppc_stwcxd (code, value, 0, location);
4547 #ifdef __mono_ppc64__
4548 else
4549 ppc_stdcxd (code, value, 0, location);
4550 #endif
4552 lost_reservation = code;
4553 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4554 ppc_patch (lost_reservation, start);
4555 ppc_patch (not_equal, code);
4557 ppc_sync (code);
4558 ppc_mr (code, ins->dreg, ppc_r0);
4559 break;
4561 case OP_LIVERANGE_START: {
4562 if (cfg->verbose_level > 1)
4563 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4564 MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4565 break;
4567 case OP_LIVERANGE_END: {
4568 if (cfg->verbose_level > 1)
4569 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4570 MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4571 break;
4573 case OP_GC_SAFE_POINT:
4574 break;
4576 default:
4577 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4578 g_assert_not_reached ();
4581 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4582 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4583 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4584 g_assert_not_reached ();
4587 cpos += max_len;
4589 last_ins = ins;
4592 set_code_cursor (cfg, code);
4594 #endif /* !DISABLE_JIT */
4596 void
4597 mono_arch_register_lowlevel_calls (void)
4599 /* The signature doesn't matter */
4600 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4603 #ifdef __mono_ppc64__
4604 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4605 #define patch_load_sequence(ip,val) do {\
4606 guint16 *__load = (guint16*)(ip); \
4607 g_assert (sizeof (val) == sizeof (gsize)); \
4608 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4609 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4610 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4611 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4612 } while (0)
4613 #elif G_BYTE_ORDER == G_BIG_ENDIAN
4614 #define patch_load_sequence(ip,val) do {\
4615 guint16 *__load = (guint16*)(ip); \
4616 g_assert (sizeof (val) == sizeof (gsize)); \
4617 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4618 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4619 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4620 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4621 } while (0)
4622 #else
4623 #error huh? No endianess defined by compiler
4624 #endif
4625 #else
4626 #define patch_load_sequence(ip,val) do {\
4627 guint16 *__lis_ori = (guint16*)(ip); \
4628 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4629 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4630 } while (0)
4631 #endif
4633 #ifndef DISABLE_JIT
4634 void
4635 mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
4637 unsigned char *ip = ji->ip.i + code;
4638 gboolean is_fd = FALSE;
4640 switch (ji->type) {
4641 case MONO_PATCH_INFO_IP:
4642 patch_load_sequence (ip, ip);
4643 break;
4644 case MONO_PATCH_INFO_METHOD_REL:
4645 g_assert_not_reached ();
4646 *((gpointer *)(ip)) = code + ji->data.offset;
4647 break;
4648 case MONO_PATCH_INFO_SWITCH: {
4649 gpointer *table = (gpointer *)ji->data.table->table;
4650 int i;
4652 patch_load_sequence (ip, table);
4654 for (i = 0; i < ji->data.table->table_size; i++) {
4655 table [i] = (glong)ji->data.table->table [i] + code;
4657 /* we put into the table the absolute address, no need for ppc_patch in this case */
4658 break;
4660 case MONO_PATCH_INFO_METHODCONST:
4661 case MONO_PATCH_INFO_CLASS:
4662 case MONO_PATCH_INFO_IMAGE:
4663 case MONO_PATCH_INFO_FIELD:
4664 case MONO_PATCH_INFO_VTABLE:
4665 case MONO_PATCH_INFO_IID:
4666 case MONO_PATCH_INFO_SFLDA:
4667 case MONO_PATCH_INFO_LDSTR:
4668 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4669 case MONO_PATCH_INFO_LDTOKEN:
4670 /* from OP_AOTCONST : lis + ori */
4671 patch_load_sequence (ip, target);
4672 break;
4673 case MONO_PATCH_INFO_R4:
4674 case MONO_PATCH_INFO_R8:
4675 g_assert_not_reached ();
4676 *((gconstpointer *)(ip + 2)) = ji->data.target;
4677 break;
4678 case MONO_PATCH_INFO_EXC_NAME:
4679 g_assert_not_reached ();
4680 *((gconstpointer *)(ip + 1)) = ji->data.name;
4681 break;
4682 case MONO_PATCH_INFO_NONE:
4683 case MONO_PATCH_INFO_BB_OVF:
4684 case MONO_PATCH_INFO_EXC_OVF:
4685 /* everything is dealt with at epilog output time */
4686 break;
4687 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4688 case MONO_PATCH_INFO_JIT_ICALL:
4689 case MONO_PATCH_INFO_ABS:
4690 case MONO_PATCH_INFO_RGCTX_FETCH:
4691 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4692 is_fd = TRUE;
4693 /* fall through */
4694 #endif
4695 default:
4696 ppc_patch_full (cfg, domain, ip, target, is_fd);
4697 break;
4702 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4703 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4704 * the instruction offset immediate for all the registers.
4706 static guint8*
4707 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4709 int i;
4710 if (!save_lmf) {
4711 for (i = 13; i <= 31; i++) {
4712 if (used_int_regs & (1 << i)) {
4713 ppc_str (code, i, pos, base_reg);
4714 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4715 pos += sizeof (target_mgreg_t);
4718 } else {
4719 /* pos is the start of the MonoLMF structure */
4720 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4721 for (i = 13; i <= 31; i++) {
4722 ppc_str (code, i, offset, base_reg);
4723 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4724 offset += sizeof (target_mgreg_t);
4726 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4727 for (i = 14; i < 32; i++) {
4728 ppc_stfd (code, i, offset, base_reg);
4729 offset += sizeof (gdouble);
4732 return code;
4736 * Stack frame layout:
4738 * ------------------- sp
4739 * MonoLMF structure or saved registers
4740 * -------------------
4741 * spilled regs
4742 * -------------------
4743 * locals
4744 * -------------------
4745 * param area size is cfg->param_area
4746 * -------------------
4747 * linkage area size is PPC_STACK_PARAM_OFFSET
4748 * ------------------- sp
4749 * red zone
4751 guint8 *
4752 mono_arch_emit_prolog (MonoCompile *cfg)
4754 MonoMethod *method = cfg->method;
4755 MonoBasicBlock *bb;
4756 MonoMethodSignature *sig;
4757 MonoInst *inst;
4758 long alloc_size, pos, max_offset, cfa_offset;
4759 int i;
4760 guint8 *code;
4761 CallInfo *cinfo;
4762 int lmf_offset = 0;
4763 int tailcall_struct_index;
4765 sig = mono_method_signature_internal (method);
4766 cfg->code_size = 512 + sig->param_count * 32;
4767 code = cfg->native_code = g_malloc (cfg->code_size);
4769 cfa_offset = 0;
4771 /* We currently emit unwind info for aot, but don't use it */
4772 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4774 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4775 ppc_mflr (code, ppc_r0);
4776 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4777 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4780 alloc_size = cfg->stack_offset;
4781 pos = 0;
4783 if (!method->save_lmf) {
4784 for (i = 31; i >= 13; --i) {
4785 if (cfg->used_int_regs & (1 << i)) {
4786 pos += sizeof (target_mgreg_t);
4789 } else {
4790 pos += sizeof (MonoLMF);
4791 lmf_offset = pos;
4793 alloc_size += pos;
4794 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4795 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4796 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4797 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4800 cfg->stack_usage = alloc_size;
4801 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4802 if (alloc_size) {
4803 if (ppc_is_imm16 (-alloc_size)) {
4804 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4805 cfa_offset = alloc_size;
4806 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4807 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4808 } else {
4809 if (pos)
4810 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4811 ppc_load (code, ppc_r0, -alloc_size);
4812 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4813 cfa_offset = alloc_size;
4814 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4815 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4818 if (cfg->frame_reg != ppc_sp) {
4819 ppc_mr (code, cfg->frame_reg, ppc_sp);
4820 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4823 /* store runtime generic context */
4824 if (cfg->rgctx_var) {
4825 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4826 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4828 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4831 /* compute max_offset in order to use short forward jumps
4832 * we always do it on ppc because the immediate displacement
4833 * for jumps is too small
4835 max_offset = 0;
4836 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4837 MonoInst *ins;
4838 bb->max_offset = max_offset;
4840 MONO_BB_FOR_EACH_INS (bb, ins)
4841 max_offset += ins_get_size (ins->opcode);
4844 /* load arguments allocated to register from the stack */
4845 pos = 0;
4847 cinfo = get_call_info (sig);
4849 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4850 ArgInfo *ainfo = &cinfo->ret;
4852 inst = cfg->vret_addr;
4853 g_assert (inst);
4855 if (ppc_is_imm16 (inst->inst_offset)) {
4856 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4857 } else {
4858 ppc_load (code, ppc_r12, inst->inst_offset);
4859 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4863 tailcall_struct_index = 0;
4864 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4865 ArgInfo *ainfo = cinfo->args + i;
4866 inst = cfg->args [pos];
4868 if (cfg->verbose_level > 2)
4869 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4870 if (inst->opcode == OP_REGVAR) {
4871 if (ainfo->regtype == RegTypeGeneral)
4872 ppc_mr (code, inst->dreg, ainfo->reg);
4873 else if (ainfo->regtype == RegTypeFP)
4874 ppc_fmr (code, inst->dreg, ainfo->reg);
4875 else if (ainfo->regtype == RegTypeBase) {
4876 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4877 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4878 } else
4879 g_assert_not_reached ();
4881 if (cfg->verbose_level > 2)
4882 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4883 } else {
4884 /* the argument should be put on the stack: FIXME handle size != word */
4885 if (ainfo->regtype == RegTypeGeneral) {
4886 switch (ainfo->size) {
4887 case 1:
4888 if (ppc_is_imm16 (inst->inst_offset)) {
4889 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4890 } else {
4891 if (ppc_is_imm32 (inst->inst_offset)) {
4892 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4893 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4894 } else {
4895 ppc_load (code, ppc_r12, inst->inst_offset);
4896 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4899 break;
4900 case 2:
4901 if (ppc_is_imm16 (inst->inst_offset)) {
4902 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4903 } else {
4904 if (ppc_is_imm32 (inst->inst_offset)) {
4905 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4906 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4907 } else {
4908 ppc_load (code, ppc_r12, inst->inst_offset);
4909 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4912 break;
4913 #ifdef __mono_ppc64__
4914 case 4:
4915 if (ppc_is_imm16 (inst->inst_offset)) {
4916 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4917 } else {
4918 if (ppc_is_imm32 (inst->inst_offset)) {
4919 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4920 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
4921 } else {
4922 ppc_load (code, ppc_r12, inst->inst_offset);
4923 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4926 break;
4927 case 8:
4928 if (ppc_is_imm16 (inst->inst_offset)) {
4929 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4930 } else {
4931 ppc_load (code, ppc_r12, inst->inst_offset);
4932 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4934 break;
4935 #else
4936 case 8:
4937 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4938 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4939 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4940 } else {
4941 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4942 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4943 ppc_stw (code, ainfo->reg, 0, ppc_r12);
4944 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
4946 break;
4947 #endif
4948 default:
4949 if (ppc_is_imm16 (inst->inst_offset)) {
4950 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4951 } else {
4952 if (ppc_is_imm32 (inst->inst_offset)) {
4953 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4954 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
4955 } else {
4956 ppc_load (code, ppc_r12, inst->inst_offset);
4957 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4960 break;
4962 } else if (ainfo->regtype == RegTypeBase) {
4963 g_assert (ppc_is_imm16 (ainfo->offset));
4964 /* load the previous stack pointer in r12 */
4965 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4966 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
4967 switch (ainfo->size) {
4968 case 1:
4969 if (ppc_is_imm16 (inst->inst_offset)) {
4970 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4971 } else {
4972 if (ppc_is_imm32 (inst->inst_offset)) {
4973 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4974 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
4975 } else {
4976 ppc_load (code, ppc_r12, inst->inst_offset);
4977 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4980 break;
4981 case 2:
4982 if (ppc_is_imm16 (inst->inst_offset)) {
4983 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4984 } else {
4985 if (ppc_is_imm32 (inst->inst_offset)) {
4986 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4987 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
4988 } else {
4989 ppc_load (code, ppc_r12, inst->inst_offset);
4990 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4993 break;
4994 #ifdef __mono_ppc64__
4995 case 4:
4996 if (ppc_is_imm16 (inst->inst_offset)) {
4997 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4998 } else {
4999 if (ppc_is_imm32 (inst->inst_offset)) {
5000 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5001 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5002 } else {
5003 ppc_load (code, ppc_r12, inst->inst_offset);
5004 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5007 break;
5008 case 8:
5009 if (ppc_is_imm16 (inst->inst_offset)) {
5010 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5011 } else {
5012 ppc_load (code, ppc_r12, inst->inst_offset);
5013 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5015 break;
5016 #else
5017 case 8:
5018 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5019 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5020 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5021 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5022 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5023 } else {
5024 /* use r11 to load the 2nd half of the long before we clobber r12. */
5025 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5026 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5027 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5028 ppc_stw (code, ppc_r0, 0, ppc_r12);
5029 ppc_stw (code, ppc_r11, 4, ppc_r12);
5031 break;
5032 #endif
5033 default:
5034 if (ppc_is_imm16 (inst->inst_offset)) {
5035 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5036 } else {
5037 if (ppc_is_imm32 (inst->inst_offset)) {
5038 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5039 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5040 } else {
5041 ppc_load (code, ppc_r12, inst->inst_offset);
5042 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5045 break;
5047 } else if (ainfo->regtype == RegTypeFP) {
5048 g_assert (ppc_is_imm16 (inst->inst_offset));
5049 if (ainfo->size == 8)
5050 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5051 else if (ainfo->size == 4)
5052 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5053 else
5054 g_assert_not_reached ();
5055 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5056 int doffset = inst->inst_offset;
5057 int soffset = 0;
5058 int cur_reg;
5059 int size = 0;
5060 g_assert (ppc_is_imm16 (inst->inst_offset));
5061 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (target_mgreg_t)));
5062 /* FIXME: what if there is no class? */
5063 if (sig->pinvoke && mono_class_from_mono_type_internal (inst->inst_vtype))
5064 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), NULL);
5065 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5066 if (ainfo->size == 4) {
5067 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5068 } else {
5069 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5071 soffset += ainfo->size;
5072 doffset += ainfo->size;
5074 } else if (ainfo->regtype == RegTypeStructByVal) {
5075 int doffset = inst->inst_offset;
5076 int soffset = 0;
5077 int cur_reg;
5078 int size = 0;
5079 g_assert (ppc_is_imm16 (inst->inst_offset));
5080 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (target_mgreg_t)));
5081 /* FIXME: what if there is no class? */
5082 if (sig->pinvoke && mono_class_from_mono_type_internal (inst->inst_vtype))
5083 size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), NULL);
5084 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5085 #if __APPLE__
5087 * Darwin handles 1 and 2 byte
5088 * structs specially by
5089 * loading h/b into the arg
5090 * register. Only done for
5091 * pinvokes.
5093 if (size == 2)
5094 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5095 else if (size == 1)
5096 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5097 else
5098 #endif
5100 #ifdef __mono_ppc64__
5101 if (ainfo->bytes) {
5102 g_assert (cur_reg == 0);
5103 #if G_BYTE_ORDER == G_BIG_ENDIAN
5104 ppc_sldi (code, ppc_r0, ainfo->reg,
5105 (sizeof (target_mgreg_t) - ainfo->bytes) * 8);
5106 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5107 #else
5108 if (mono_class_native_size (inst->klass, NULL) == 1) {
5109 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5110 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5111 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5112 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5113 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5114 } else {
5115 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5117 #endif
5118 } else
5119 #endif
5121 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5122 inst->inst_basereg);
5125 soffset += sizeof (target_mgreg_t);
5126 doffset += sizeof (target_mgreg_t);
5128 if (ainfo->vtsize) {
5129 /* FIXME: we need to do the shifting here, too */
5130 if (ainfo->bytes)
5131 NOT_IMPLEMENTED;
5132 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5133 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5134 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5135 code = emit_memcpy (code, size - soffset,
5136 inst->inst_basereg, doffset,
5137 ppc_r12, ainfo->offset + soffset);
5138 } else {
5139 code = emit_memcpy (code, ainfo->vtsize * sizeof (target_mgreg_t),
5140 inst->inst_basereg, doffset,
5141 ppc_r12, ainfo->offset + soffset);
5144 } else if (ainfo->regtype == RegTypeStructByAddr) {
5145 /* if it was originally a RegTypeBase */
5146 if (ainfo->offset) {
5147 /* load the previous stack pointer in r12 */
5148 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5149 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5150 } else {
5151 ppc_mr (code, ppc_r12, ainfo->reg);
5154 g_assert (ppc_is_imm16 (inst->inst_offset));
5155 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5156 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5157 } else
5158 g_assert_not_reached ();
5160 pos++;
5163 if (method->save_lmf) {
5164 if (cfg->compile_aot) {
5165 /* Compute the got address which is needed by the PLT entry */
5166 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5168 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL,
5169 (gpointer)"mono_tls_get_lmf_addr");
5170 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5171 ppc_load_func (code, PPC_CALL_REG, 0);
5172 ppc_mtlr (code, PPC_CALL_REG);
5173 ppc_blrl (code);
5174 } else {
5175 ppc_bl (code, 0);
5177 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5178 /* lmf_offset is the offset from the previous stack pointer,
5179 * alloc_size is the total stack space allocated, so the offset
5180 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5181 * The pointer to the struct is put in ppc_r12 (new_lmf).
5182 * The callee-saved registers are already in the MonoLMF structure
5184 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5185 /* ppc_r3 is the result from mono_get_lmf_addr () */
5186 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5187 /* new_lmf->previous_lmf = *lmf_addr */
5188 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5189 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5190 /* *(lmf_addr) = r12 */
5191 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5192 /* save method info */
5193 if (cfg->compile_aot)
5194 // FIXME:
5195 ppc_load (code, ppc_r0, 0);
5196 else
5197 ppc_load_ptr (code, ppc_r0, method);
5198 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5199 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5200 /* save the current IP */
5201 if (cfg->compile_aot) {
5202 ppc_bl (code, 1);
5203 ppc_mflr (code, ppc_r0);
5204 } else {
5205 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5206 #ifdef __mono_ppc64__
5207 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5208 #else
5209 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5210 #endif
5212 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5215 set_code_cursor (cfg, code);
5216 g_free (cinfo);
5218 return code;
5221 void
5222 mono_arch_emit_epilog (MonoCompile *cfg)
5224 MonoMethod *method = cfg->method;
5225 int pos, i;
5226 int max_epilog_size = 16 + 20*4;
5227 guint8 *code;
5229 if (cfg->method->save_lmf)
5230 max_epilog_size += 128;
5232 code = realloc_code (cfg, max_epilog_size);
5234 pos = 0;
5236 if (method->save_lmf) {
5237 int lmf_offset;
5238 pos += sizeof (MonoLMF);
5239 lmf_offset = pos;
5240 /* save the frame reg in r8 */
5241 ppc_mr (code, ppc_r8, cfg->frame_reg);
5242 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5243 /* r5 = previous_lmf */
5244 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5245 /* r6 = lmf_addr */
5246 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5247 /* *(lmf_addr) = previous_lmf */
5248 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5249 /* FIXME: speedup: there is no actual need to restore the registers if
5250 * we didn't actually change them (idea from Zoltan).
5252 /* restore iregs */
5253 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5254 /* restore fregs */
5255 /*for (i = 14; i < 32; i++) {
5256 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5258 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5259 /* use the saved copy of the frame reg in r8 */
5260 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5261 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5262 ppc_mtlr (code, ppc_r0);
5264 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5265 } else {
5266 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5267 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5268 if (ppc_is_imm16 (return_offset)) {
5269 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5270 } else {
5271 ppc_load (code, ppc_r12, return_offset);
5272 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5274 ppc_mtlr (code, ppc_r0);
5276 if (ppc_is_imm16 (cfg->stack_usage)) {
5277 int offset = cfg->stack_usage;
5278 for (i = 13; i <= 31; i++) {
5279 if (cfg->used_int_regs & (1 << i))
5280 offset -= sizeof (target_mgreg_t);
5282 if (cfg->frame_reg != ppc_sp)
5283 ppc_mr (code, ppc_r12, cfg->frame_reg);
5284 /* note r31 (possibly the frame register) is restored last */
5285 for (i = 13; i <= 31; i++) {
5286 if (cfg->used_int_regs & (1 << i)) {
5287 ppc_ldr (code, i, offset, cfg->frame_reg);
5288 offset += sizeof (target_mgreg_t);
5291 if (cfg->frame_reg != ppc_sp)
5292 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5293 else
5294 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5295 } else {
5296 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5297 if (cfg->used_int_regs) {
5298 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5299 for (i = 31; i >= 13; --i) {
5300 if (cfg->used_int_regs & (1 << i)) {
5301 pos += sizeof (target_mgreg_t);
5302 ppc_ldr (code, i, -pos, ppc_r12);
5305 ppc_mr (code, ppc_sp, ppc_r12);
5306 } else {
5307 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5311 ppc_blr (code);
5313 set_code_cursor (cfg, code);
5316 #endif /* ifndef DISABLE_JIT */
5318 /* remove once throw_exception_by_name is eliminated */
5319 static int
5320 exception_id_by_name (const char *name)
5322 if (strcmp (name, "IndexOutOfRangeException") == 0)
5323 return MONO_EXC_INDEX_OUT_OF_RANGE;
5324 if (strcmp (name, "OverflowException") == 0)
5325 return MONO_EXC_OVERFLOW;
5326 if (strcmp (name, "ArithmeticException") == 0)
5327 return MONO_EXC_ARITHMETIC;
5328 if (strcmp (name, "DivideByZeroException") == 0)
5329 return MONO_EXC_DIVIDE_BY_ZERO;
5330 if (strcmp (name, "InvalidCastException") == 0)
5331 return MONO_EXC_INVALID_CAST;
5332 if (strcmp (name, "NullReferenceException") == 0)
5333 return MONO_EXC_NULL_REF;
5334 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5335 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5336 if (strcmp (name, "ArgumentException") == 0)
5337 return MONO_EXC_ARGUMENT;
5338 g_error ("Unknown intrinsic exception %s\n", name);
5339 return 0;
5342 #ifndef DISABLE_JIT
5343 void
5344 mono_arch_emit_exceptions (MonoCompile *cfg)
5346 MonoJumpInfo *patch_info;
5347 int i;
5348 guint8 *code;
5349 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5350 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5351 int max_epilog_size = 50;
5353 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5354 exc_throw_pos [i] = NULL;
5355 exc_throw_found [i] = 0;
5358 /* count the number of exception infos */
5361 * make sure we have enough space for exceptions
5363 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5364 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5365 i = exception_id_by_name (patch_info->data.target);
5366 if (!exc_throw_found [i]) {
5367 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5368 exc_throw_found [i] = TRUE;
5370 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5371 max_epilog_size += 12;
5372 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5373 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5374 i = exception_id_by_name (ovfj->data.exception);
5375 if (!exc_throw_found [i]) {
5376 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5377 exc_throw_found [i] = TRUE;
5379 max_epilog_size += 8;
5383 code = realloc_code (cfg, max_epilog_size);
5385 /* add code to raise exceptions */
5386 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5387 switch (patch_info->type) {
5388 case MONO_PATCH_INFO_BB_OVF: {
5389 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5390 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5391 /* patch the initial jump */
5392 ppc_patch (ip, code);
5393 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5394 ppc_b (code, 0);
5395 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5396 /* jump back to the true target */
5397 ppc_b (code, 0);
5398 ip = ovfj->data.bb->native_offset + cfg->native_code;
5399 ppc_patch (code - 4, ip);
5400 patch_info->type = MONO_PATCH_INFO_NONE;
5401 break;
5403 case MONO_PATCH_INFO_EXC_OVF: {
5404 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5405 MonoJumpInfo *newji;
5406 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5407 unsigned char *bcl = code;
5408 /* patch the initial jump: we arrived here with a call */
5409 ppc_patch (ip, code);
5410 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5411 ppc_b (code, 0);
5412 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5413 /* patch the conditional jump to the right handler */
5414 /* make it processed next */
5415 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5416 newji->type = MONO_PATCH_INFO_EXC;
5417 newji->ip.i = bcl - cfg->native_code;
5418 newji->data.target = ovfj->data.exception;
5419 newji->next = patch_info->next;
5420 patch_info->next = newji;
5421 patch_info->type = MONO_PATCH_INFO_NONE;
5422 break;
5424 case MONO_PATCH_INFO_EXC: {
5425 MonoClass *exc_class;
5427 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5428 i = exception_id_by_name (patch_info->data.target);
5429 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5430 ppc_patch (ip, exc_throw_pos [i]);
5431 patch_info->type = MONO_PATCH_INFO_NONE;
5432 break;
5433 } else {
5434 exc_throw_pos [i] = code;
5437 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5439 ppc_patch (ip, code);
5440 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5441 ppc_load (code, ppc_r3, m_class_get_type_token (exc_class));
5442 /* we got here from a conditional call, so the calling ip is set in lr */
5443 ppc_mflr (code, ppc_r4);
5444 patch_info->type = MONO_PATCH_INFO_JIT_ICALL;
5445 patch_info->data.name = "mono_arch_throw_corlib_exception";
5446 patch_info->ip.i = code - cfg->native_code;
5447 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5448 ppc_load_func (code, PPC_CALL_REG, 0);
5449 ppc_mtctr (code, PPC_CALL_REG);
5450 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5451 } else {
5452 ppc_bl (code, 0);
5454 break;
5456 default:
5457 /* do nothing */
5458 break;
5462 set_code_cursor (cfg, code);
5464 #endif
5466 #if DEAD_CODE
5467 static int
5468 try_offset_access (void *value, guint32 idx)
5470 register void* me __asm__ ("r2");
5471 void ***p = (void***)((char*)me + 284);
5472 int idx1 = idx / 32;
5473 int idx2 = idx % 32;
5474 if (!p [idx1])
5475 return 0;
5476 if (value != p[idx1][idx2])
5477 return 0;
5478 return 1;
5480 #endif
5482 void
5483 mono_arch_finish_init (void)
5487 void
5488 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5492 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5493 #define BR_SIZE 4
5494 #define LOADSTORE_SIZE 4
5495 #define JUMP_IMM_SIZE 12
5496 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5497 #define ENABLE_WRONG_METHOD_CHECK 0
5500 * LOCKING: called with the domain lock held
5502 gpointer
5503 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5504 gpointer fail_tramp)
5506 int i;
5507 int size = 0;
5508 guint8 *code, *start;
5510 for (i = 0; i < count; ++i) {
5511 MonoIMTCheckItem *item = imt_entries [i];
5512 if (item->is_equals) {
5513 if (item->check_target_idx) {
5514 if (!item->compare_done)
5515 item->chunk_size += CMP_SIZE;
5516 if (item->has_target_code)
5517 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5518 else
5519 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5520 } else {
5521 if (fail_tramp) {
5522 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5523 if (!item->has_target_code)
5524 item->chunk_size += LOADSTORE_SIZE;
5525 } else {
5526 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5527 #if ENABLE_WRONG_METHOD_CHECK
5528 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5529 #endif
5532 } else {
5533 item->chunk_size += CMP_SIZE + BR_SIZE;
5534 imt_entries [item->check_target_idx]->compare_done = TRUE;
5536 size += item->chunk_size;
5538 /* the initial load of the vtable address */
5539 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5540 if (fail_tramp) {
5541 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5542 } else {
5543 code = mono_domain_code_reserve (domain, size);
5545 start = code;
5548 * We need to save and restore r12 because it might be
5549 * used by the caller as the vtable register, so
5550 * clobbering it will trip up the magic trampoline.
5552 * FIXME: Get rid of this by making sure that r12 is
5553 * not used as the vtable register in interface calls.
5555 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5556 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5558 for (i = 0; i < count; ++i) {
5559 MonoIMTCheckItem *item = imt_entries [i];
5560 item->code_target = code;
5561 if (item->is_equals) {
5562 if (item->check_target_idx) {
5563 if (!item->compare_done) {
5564 ppc_load (code, ppc_r0, (gsize)item->key);
5565 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5567 item->jmp_code = code;
5568 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5569 if (item->has_target_code) {
5570 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5571 } else {
5572 ppc_ldptr (code, ppc_r0, (sizeof (target_mgreg_t) * item->value.vtable_slot), ppc_r12);
5573 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5575 ppc_mtctr (code, ppc_r0);
5576 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5577 } else {
5578 if (fail_tramp) {
5579 ppc_load (code, ppc_r0, (gulong)item->key);
5580 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5581 item->jmp_code = code;
5582 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5583 if (item->has_target_code) {
5584 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5585 } else {
5586 g_assert (vtable);
5587 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5588 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5590 ppc_mtctr (code, ppc_r0);
5591 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5592 ppc_patch (item->jmp_code, code);
5593 ppc_load_ptr (code, ppc_r0, fail_tramp);
5594 ppc_mtctr (code, ppc_r0);
5595 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5596 item->jmp_code = NULL;
5597 } else {
5598 /* enable the commented code to assert on wrong method */
5599 #if ENABLE_WRONG_METHOD_CHECK
5600 ppc_load (code, ppc_r0, (guint32)item->key);
5601 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5602 item->jmp_code = code;
5603 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5604 #endif
5605 ppc_ldptr (code, ppc_r0, (sizeof (target_mgreg_t) * item->value.vtable_slot), ppc_r12);
5606 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5607 ppc_mtctr (code, ppc_r0);
5608 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5609 #if ENABLE_WRONG_METHOD_CHECK
5610 ppc_patch (item->jmp_code, code);
5611 ppc_break (code);
5612 item->jmp_code = NULL;
5613 #endif
5616 } else {
5617 ppc_load (code, ppc_r0, (gulong)item->key);
5618 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5619 item->jmp_code = code;
5620 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5623 /* patch the branches to get to the target items */
5624 for (i = 0; i < count; ++i) {
5625 MonoIMTCheckItem *item = imt_entries [i];
5626 if (item->jmp_code) {
5627 if (item->check_target_idx) {
5628 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5633 if (!fail_tramp)
5634 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
5635 g_assert (code - start <= size);
5636 mono_arch_flush_icache (start, size);
5637 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
5639 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5641 return start;
5644 MonoMethod*
5645 mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
5647 host_mgreg_t *r = (host_mgreg_t*)regs;
5649 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5652 MonoVTable*
5653 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
5655 return (MonoVTable*)(gsize) regs [MONO_ARCH_RGCTX_REG];
5658 GSList*
5659 mono_arch_get_cie_program (void)
5661 GSList *l = NULL;
5663 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5665 return l;
5668 MonoInst*
5669 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5671 MonoInst *ins = NULL;
5672 int opcode = 0;
5674 if (cmethod->klass == mono_class_try_get_math_class ()) {
5675 if (strcmp (cmethod->name, "Sqrt") == 0) {
5676 opcode = OP_SQRT;
5677 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5678 opcode = OP_ABS;
5681 if (opcode && fsig->param_count == 1) {
5682 MONO_INST_NEW (cfg, ins, opcode);
5683 ins->type = STACK_R8;
5684 ins->dreg = mono_alloc_freg (cfg);
5685 ins->sreg1 = args [0]->dreg;
5686 MONO_ADD_INS (cfg->cbb, ins);
5689 /* Check for Min/Max for (u)int(32|64) */
5690 opcode = 0;
5691 if (cpu_hw_caps & PPC_ISA_2_03) {
5692 if (strcmp (cmethod->name, "Min") == 0) {
5693 if (fsig->params [0]->type == MONO_TYPE_I4)
5694 opcode = OP_IMIN;
5695 if (fsig->params [0]->type == MONO_TYPE_U4)
5696 opcode = OP_IMIN_UN;
5697 #ifdef __mono_ppc64__
5698 else if (fsig->params [0]->type == MONO_TYPE_I8)
5699 opcode = OP_LMIN;
5700 else if (fsig->params [0]->type == MONO_TYPE_U8)
5701 opcode = OP_LMIN_UN;
5702 #endif
5703 } else if (strcmp (cmethod->name, "Max") == 0) {
5704 if (fsig->params [0]->type == MONO_TYPE_I4)
5705 opcode = OP_IMAX;
5706 if (fsig->params [0]->type == MONO_TYPE_U4)
5707 opcode = OP_IMAX_UN;
5708 #ifdef __mono_ppc64__
5709 else if (fsig->params [0]->type == MONO_TYPE_I8)
5710 opcode = OP_LMAX;
5711 else if (fsig->params [0]->type == MONO_TYPE_U8)
5712 opcode = OP_LMAX_UN;
5713 #endif
5716 * TODO: Floating point version with fsel, but fsel has
5717 * some peculiarities (need a scratch reg unless
5718 * comparing with 0, NaN/Inf behaviour (then MathF too)
5722 if (opcode && fsig->param_count == 2) {
5723 MONO_INST_NEW (cfg, ins, opcode);
5724 ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5725 ins->dreg = mono_alloc_ireg (cfg);
5726 ins->sreg1 = args [0]->dreg;
5727 ins->sreg2 = args [1]->dreg;
5728 MONO_ADD_INS (cfg->cbb, ins);
5731 /* Rounding instructions */
5732 opcode = 0;
5733 if ((cpu_hw_caps & PPC_ISA_2X) && (fsig->param_count == 1) && (fsig->params [0]->type == MONO_TYPE_R8)) {
5735 * XXX: sysmath.c and frin imply round is a little bit
5736 * more complicated than expected? but amd64 does this?
5737 * (also, no float versions of these ops, but frsp
5738 * could be preprended?)
5740 if (!strcmp (cmethod->name, "Round"))
5741 opcode = OP_ROUND;
5742 else if (!strcmp (cmethod->name, "Floor"))
5743 opcode = OP_PPC_FLOOR;
5744 else if (!strcmp (cmethod->name, "Ceiling"))
5745 opcode = OP_PPC_CEIL;
5746 else if (!strcmp (cmethod->name, "Truncate"))
5747 opcode = OP_PPC_TRUNC;
5748 if (opcode != 0) {
5749 MONO_INST_NEW (cfg, ins, opcode);
5750 ins->type = STACK_R8;
5751 ins->dreg = mono_alloc_freg (cfg);
5752 ins->sreg1 = args [0]->dreg;
5753 MONO_ADD_INS (cfg->cbb, ins);
5757 if (cmethod->klass == mono_class_try_get_mathf_class ()) {
5758 if (strcmp (cmethod->name, "Sqrt") == 0) {
5759 opcode = OP_SQRTF;
5760 } /* XXX: POWER has no single-precision normal FPU abs? */
5762 if (opcode && fsig->param_count == 1) {
5763 MONO_INST_NEW (cfg, ins, opcode);
5764 ins->type = STACK_R4;
5765 ins->dreg = mono_alloc_freg (cfg);
5766 ins->sreg1 = args [0]->dreg;
5767 MONO_ADD_INS (cfg->cbb, ins);
5770 return ins;
5773 host_mgreg_t
5774 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5776 if (reg == ppc_r1)
5777 return (host_mgreg_t)(gsize)MONO_CONTEXT_GET_SP (ctx);
5779 return ctx->regs [reg];
5782 guint32
5783 mono_arch_get_patch_offset (guint8 *code)
5785 return 0;
5789 * mono_aot_emit_load_got_addr:
5791 * Emit code to load the got address.
5792 * On PPC, the result is placed into r30.
5794 guint8*
5795 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5797 ppc_bl (code, 1);
5798 ppc_mflr (code, ppc_r30);
5799 if (cfg)
5800 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5801 else
5802 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5803 /* arch_emit_got_address () patches this */
5804 #if defined(TARGET_POWERPC64)
5805 ppc_nop (code);
5806 ppc_nop (code);
5807 ppc_nop (code);
5808 ppc_nop (code);
5809 #else
5810 ppc_load32 (code, ppc_r0, 0);
5811 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5812 #endif
5814 set_code_cursor (cfg, code);
5815 return code;
5819 * mono_ppc_emit_load_aotconst:
5821 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5822 * TARGET from the mscorlib GOT in full-aot code.
5823 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5824 * r12.
5826 guint8*
5827 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
5829 /* Load the mscorlib got address */
5830 ppc_ldptr (code, ppc_r12, sizeof (target_mgreg_t), ppc_r30);
5831 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5832 /* arch_emit_got_access () patches this */
5833 ppc_load32 (code, ppc_r0, 0);
5834 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5836 return code;
5839 /* Soft Debug support */
5840 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5843 * BREAKPOINTS
5847 * mono_arch_set_breakpoint:
5849 * See mini-amd64.c for docs.
5851 void
5852 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5854 guint8 *code = ip;
5855 guint8 *orig_code = code;
5857 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
5858 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
5860 g_assert (code - orig_code == BREAKPOINT_SIZE);
5862 mono_arch_flush_icache (orig_code, code - orig_code);
5866 * mono_arch_clear_breakpoint:
5868 * See mini-amd64.c for docs.
5870 void
5871 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5873 guint8 *code = ip;
5874 int i;
5876 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5877 ppc_nop (code);
5879 mono_arch_flush_icache (ip, code - ip);
5883 * mono_arch_is_breakpoint_event:
5885 * See mini-amd64.c for docs.
5887 gboolean
5888 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5890 siginfo_t* sinfo = (siginfo_t*) info;
5891 /* Sometimes the address is off by 4 */
5892 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5893 return TRUE;
5894 else
5895 return FALSE;
5899 * mono_arch_skip_breakpoint:
5901 * See mini-amd64.c for docs.
5903 void
5904 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5906 /* skip the ldptr */
5907 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5911 * SINGLE STEPPING
5915 * mono_arch_start_single_stepping:
5917 * See mini-amd64.c for docs.
5919 void
5920 mono_arch_start_single_stepping (void)
5922 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5926 * mono_arch_stop_single_stepping:
5928 * See mini-amd64.c for docs.
5930 void
5931 mono_arch_stop_single_stepping (void)
5933 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5937 * mono_arch_is_single_step_event:
5939 * See mini-amd64.c for docs.
5941 gboolean
5942 mono_arch_is_single_step_event (void *info, void *sigctx)
5944 siginfo_t* sinfo = (siginfo_t*) info;
5945 /* Sometimes the address is off by 4 */
5946 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5947 return TRUE;
5948 else
5949 return FALSE;
5953 * mono_arch_skip_single_step:
5955 * See mini-amd64.c for docs.
5957 void
5958 mono_arch_skip_single_step (MonoContext *ctx)
5960 /* skip the ldptr */
5961 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5965 * mono_arch_create_seq_point_info:
5967 * See mini-amd64.c for docs.
5969 SeqPointInfo*
5970 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5972 NOT_IMPLEMENTED;
5973 return NULL;
5976 #endif
5978 gboolean
5979 mono_arch_opcode_supported (int opcode)
5981 switch (opcode) {
5982 case OP_ATOMIC_ADD_I4:
5983 case OP_ATOMIC_CAS_I4:
5984 #ifdef TARGET_POWERPC64
5985 case OP_ATOMIC_ADD_I8:
5986 case OP_ATOMIC_CAS_I8:
5987 #endif
5988 return TRUE;
5989 default:
5990 return FALSE;