[mono-api-info] Use XmlWriter instead of XmlDocument to make this faster.
[mono-project.git] / mono / mini / mini-ppc.c
blob6060e0a0782244354d369301801ad110fd8883d8
1 /*
2 * mini-ppc.c: PowerPC backend for the Mono code generator
4 * Authors:
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
12 #include "mini.h"
13 #include <string.h>
15 #include <mono/metadata/abi-details.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/utils/mono-proclib.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/mono-hwcap-ppc.h>
22 #include "mini-ppc.h"
23 #ifdef TARGET_POWERPC64
24 #include "cpu-ppc64.h"
25 #else
26 #include "cpu-ppc.h"
27 #endif
28 #include "trace.h"
29 #include "ir-emit.h"
30 #ifdef __APPLE__
31 #include <sys/sysctl.h>
32 #endif
33 #ifdef __linux__
34 #include <unistd.h>
35 #endif
37 #define FORCE_INDIR_CALL 1
39 enum {
40 TLS_MODE_DETECT,
41 TLS_MODE_FAILED,
42 TLS_MODE_LTHREADS,
43 TLS_MODE_NPTL,
44 TLS_MODE_DARWIN_G4,
45 TLS_MODE_DARWIN_G5
48 /* cpu_hw_caps contains the flags defined below */
49 static int cpu_hw_caps = 0;
50 static int cachelinesize = 0;
51 static int cachelineinc = 0;
52 enum {
53 PPC_ICACHE_SNOOP = 1 << 0,
54 PPC_MULTIPLE_LS_UNITS = 1 << 1,
55 PPC_SMP_CAPABLE = 1 << 2,
56 PPC_ISA_2X = 1 << 3,
57 PPC_ISA_64 = 1 << 4,
58 PPC_MOVE_FPR_GPR = 1 << 5,
59 PPC_HW_CAP_END
62 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
64 /* This mutex protects architecture specific caches */
65 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
66 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
67 static mono_mutex_t mini_arch_mutex;
69 int mono_exc_esp_offset = 0;
70 static int tls_mode = TLS_MODE_DETECT;
71 static int lmf_pthread_key = -1;
74 * The code generated for sequence points reads from this location, which is
75 * made read-only when single stepping is enabled.
77 static gpointer ss_trigger_page;
79 /* Enabled breakpoints read from this trigger page */
80 static gpointer bp_trigger_page;
82 static int
83 offsets_from_pthread_key (guint32 key, int *offset2)
85 int idx1 = key / 32;
86 int idx2 = key % 32;
87 *offset2 = idx2 * sizeof (gpointer);
88 return 284 + idx1 * sizeof (gpointer);
91 #define emit_linuxthreads_tls(code,dreg,key) do {\
92 int off1, off2; \
93 off1 = offsets_from_pthread_key ((key), &off2); \
94 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
95 ppc_ldptr ((code), (dreg), off2, (dreg)); \
96 } while (0);
98 #define emit_darwing5_tls(code,dreg,key) do {\
99 int off1 = 0x48 + key * sizeof (gpointer); \
100 ppc_mfspr ((code), (dreg), 104); \
101 ppc_ldptr ((code), (dreg), off1, (dreg)); \
102 } while (0);
104 /* FIXME: ensure the sc call preserves all but r3 */
105 #define emit_darwing4_tls(code,dreg,key) do {\
106 int off1 = 0x48 + key * sizeof (gpointer); \
107 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r12, ppc_r3); \
108 ppc_li ((code), ppc_r0, 0x7FF2); \
109 ppc_sc ((code)); \
110 ppc_lwz ((code), (dreg), off1, ppc_r3); \
111 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r12); \
112 } while (0);
114 #ifdef PPC_THREAD_PTR_REG
115 #define emit_nptl_tls(code,dreg,key) do { \
116 int off1 = key; \
117 int off2 = key >> 15; \
118 if ((off2 == 0) || (off2 == -1)) { \
119 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
120 } else { \
121 int off3 = (off2 + 1) > 1; \
122 ppc_addis ((code), ppc_r12, PPC_THREAD_PTR_REG, off3); \
123 ppc_ldptr ((code), (dreg), off1, ppc_r12); \
125 } while (0);
126 #else
127 #define emit_nptl_tls(code,dreg,key) do { \
128 g_assert_not_reached (); \
129 } while (0)
130 #endif
132 #define emit_tls_access(code,dreg,key) do { \
133 switch (tls_mode) { \
134 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
135 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
137 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
138 default: g_assert_not_reached (); \
140 } while (0)
142 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
143 MonoInst *inst; \
144 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
145 inst->type = STACK_R8; \
146 inst->dreg = (dr); \
147 inst->inst_p0 = (void*)(addr); \
148 mono_bblock_add_inst (cfg->cbb, inst); \
149 } while (0)
151 const char*
152 mono_arch_regname (int reg) {
153 static const char rnames[][4] = {
154 "r0", "sp", "r2", "r3", "r4",
155 "r5", "r6", "r7", "r8", "r9",
156 "r10", "r11", "r12", "r13", "r14",
157 "r15", "r16", "r17", "r18", "r19",
158 "r20", "r21", "r22", "r23", "r24",
159 "r25", "r26", "r27", "r28", "r29",
160 "r30", "r31"
162 if (reg >= 0 && reg < 32)
163 return rnames [reg];
164 return "unknown";
167 const char*
168 mono_arch_fregname (int reg) {
169 static const char rnames[][4] = {
170 "f0", "f1", "f2", "f3", "f4",
171 "f5", "f6", "f7", "f8", "f9",
172 "f10", "f11", "f12", "f13", "f14",
173 "f15", "f16", "f17", "f18", "f19",
174 "f20", "f21", "f22", "f23", "f24",
175 "f25", "f26", "f27", "f28", "f29",
176 "f30", "f31"
178 if (reg >= 0 && reg < 32)
179 return rnames [reg];
180 return "unknown";
183 /* this function overwrites r0, r11, r12 */
184 static guint8*
185 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
187 /* unrolled, use the counter in big */
188 if (size > sizeof (gpointer) * 5) {
189 long shifted = size / SIZEOF_VOID_P;
190 guint8 *copy_loop_start, *copy_loop_jump;
192 ppc_load (code, ppc_r0, shifted);
193 ppc_mtctr (code, ppc_r0);
194 //g_assert (sreg == ppc_r12);
195 ppc_addi (code, ppc_r11, dreg, (doffset - sizeof (gpointer)));
196 ppc_addi (code, ppc_r12, sreg, (soffset - sizeof (gpointer)));
197 copy_loop_start = code;
198 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
200 copy_loop_jump = code;
201 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
202 ppc_patch (copy_loop_jump, copy_loop_start);
203 size -= shifted * sizeof (gpointer);
204 doffset = soffset = 0;
205 dreg = ppc_r11;
207 #ifdef __mono_ppc64__
208 /* the hardware has multiple load/store units and the move is long
209 enough to use more then one register, then use load/load/store/store
210 to execute 2 instructions per cycle. */
211 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
212 while (size >= 16) {
213 ppc_ldptr (code, ppc_r0, soffset, sreg);
214 ppc_ldptr (code, ppc_r11, soffset+8, sreg);
215 ppc_stptr (code, ppc_r0, doffset, dreg);
216 ppc_stptr (code, ppc_r11, doffset+8, dreg);
217 size -= 16;
218 soffset += 16;
219 doffset += 16;
222 while (size >= 8) {
223 ppc_ldr (code, ppc_r0, soffset, sreg);
224 ppc_str (code, ppc_r0, doffset, dreg);
225 size -= 8;
226 soffset += 8;
227 doffset += 8;
229 #else
230 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
231 while (size >= 8) {
232 ppc_lwz (code, ppc_r0, soffset, sreg);
233 ppc_lwz (code, ppc_r11, soffset+4, sreg);
234 ppc_stw (code, ppc_r0, doffset, dreg);
235 ppc_stw (code, ppc_r11, doffset+4, dreg);
236 size -= 8;
237 soffset += 8;
238 doffset += 8;
241 #endif
242 while (size >= 4) {
243 ppc_lwz (code, ppc_r0, soffset, sreg);
244 ppc_stw (code, ppc_r0, doffset, dreg);
245 size -= 4;
246 soffset += 4;
247 doffset += 4;
249 while (size >= 2) {
250 ppc_lhz (code, ppc_r0, soffset, sreg);
251 ppc_sth (code, ppc_r0, doffset, dreg);
252 size -= 2;
253 soffset += 2;
254 doffset += 2;
256 while (size >= 1) {
257 ppc_lbz (code, ppc_r0, soffset, sreg);
258 ppc_stb (code, ppc_r0, doffset, dreg);
259 size -= 1;
260 soffset += 1;
261 doffset += 1;
263 return code;
267 * mono_arch_get_argument_info:
268 * @csig: a method signature
269 * @param_count: the number of parameters to consider
270 * @arg_info: an array to store the result infos
272 * Gathers information on parameters such as size, alignment and
273 * padding. arg_info should be large enought to hold param_count + 1 entries.
275 * Returns the size of the activation frame.
278 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
280 #ifdef __mono_ppc64__
281 NOT_IMPLEMENTED;
282 return -1;
283 #else
284 int k, frame_size = 0;
285 int size, align, pad;
286 int offset = 8;
288 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
289 frame_size += sizeof (gpointer);
290 offset += 4;
293 arg_info [0].offset = offset;
295 if (csig->hasthis) {
296 frame_size += sizeof (gpointer);
297 offset += 4;
300 arg_info [0].size = frame_size;
302 for (k = 0; k < param_count; k++) {
304 if (csig->pinvoke)
305 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
306 else
307 size = mini_type_stack_size (csig->params [k], &align);
309 /* ignore alignment for now */
310 align = 1;
312 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
313 arg_info [k].pad = pad;
314 frame_size += size;
315 arg_info [k + 1].pad = 0;
316 arg_info [k + 1].size = size;
317 offset += pad;
318 arg_info [k + 1].offset = offset;
319 offset += size;
322 align = MONO_ARCH_FRAME_ALIGNMENT;
323 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
324 arg_info [k].pad = pad;
326 return frame_size;
327 #endif
330 #ifdef __mono_ppc64__
331 static gboolean
332 is_load_sequence (guint32 *seq)
334 return ppc_opcode (seq [0]) == 15 && /* lis */
335 ppc_opcode (seq [1]) == 24 && /* ori */
336 ppc_opcode (seq [2]) == 30 && /* sldi */
337 ppc_opcode (seq [3]) == 25 && /* oris */
338 ppc_opcode (seq [4]) == 24; /* ori */
341 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
342 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
343 #endif
345 /* ld || lwz */
346 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
348 /* code must point to the blrl */
349 gboolean
350 mono_ppc_is_direct_call_sequence (guint32 *code)
352 #ifdef __mono_ppc64__
353 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
355 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
356 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
357 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
358 if (!is_load_sequence (&code [-8]))
359 return FALSE;
360 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
361 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
362 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
364 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
365 return is_load_sequence (&code [-8]);
366 else
367 return is_load_sequence (&code [-6]);
369 return FALSE;
370 #else
371 g_assert(*code == 0x4e800021);
373 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
374 return ppc_opcode (code [-1]) == 31 &&
375 ppc_opcode (code [-2]) == 24 &&
376 ppc_opcode (code [-3]) == 15;
377 #endif
380 #define MAX_ARCH_DELEGATE_PARAMS 7
382 static gpointer
383 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
385 guint8 *code, *start;
387 if (has_target) {
388 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
390 start = code = mono_global_codeman_reserve (size);
391 if (!aot)
392 code = mono_ppc_create_pre_code_ftnptr (code);
394 /* Replace the this argument with the target */
395 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
396 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
397 /* it's a function descriptor */
398 /* Can't use ldptr as it doesn't work with r0 */
399 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
400 #endif
401 ppc_mtctr (code, ppc_r0);
402 ppc_ldptr (code, ppc_r3, MONO_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
403 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
405 g_assert ((code - start) <= size);
407 mono_arch_flush_icache (start, size);
408 } else {
409 int size, i;
411 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
412 start = code = mono_global_codeman_reserve (size);
413 if (!aot)
414 code = mono_ppc_create_pre_code_ftnptr (code);
416 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
417 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
418 /* it's a function descriptor */
419 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
420 #endif
421 ppc_mtctr (code, ppc_r0);
422 /* slide down the arguments */
423 for (i = 0; i < param_count; ++i) {
424 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
426 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
428 g_assert ((code - start) <= size);
430 mono_arch_flush_icache (start, size);
433 if (has_target) {
434 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
435 } else {
436 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
437 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
438 g_free (name);
441 return start;
444 GSList*
445 mono_arch_get_delegate_invoke_impls (void)
447 GSList *res = NULL;
448 MonoTrampInfo *info;
449 int i;
451 get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
452 res = g_slist_prepend (res, info);
454 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
455 get_delegate_invoke_impl (&info, FALSE, i, TRUE);
456 res = g_slist_prepend (res, info);
459 return res;
462 gpointer
463 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
465 guint8 *code, *start;
467 /* FIXME: Support more cases */
468 if (MONO_TYPE_ISSTRUCT (sig->ret))
469 return NULL;
471 if (has_target) {
472 static guint8* cached = NULL;
474 if (cached)
475 return cached;
477 if (mono_aot_only) {
478 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
479 } else {
480 MonoTrampInfo *info;
481 start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
482 mono_tramp_info_register (info, NULL);
484 mono_memory_barrier ();
486 cached = start;
487 } else {
488 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
489 int i;
491 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
492 return NULL;
493 for (i = 0; i < sig->param_count; ++i)
494 if (!mono_is_regsize_var (sig->params [i]))
495 return NULL;
498 code = cache [sig->param_count];
499 if (code)
500 return code;
502 if (mono_aot_only) {
503 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
504 start = mono_aot_get_trampoline (name);
505 g_free (name);
506 } else {
507 MonoTrampInfo *info;
508 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
509 mono_tramp_info_register (info, NULL);
512 mono_memory_barrier ();
514 cache [sig->param_count] = start;
516 return start;
519 gpointer
520 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
522 return NULL;
525 gpointer
526 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
528 mgreg_t *r = (mgreg_t*)regs;
530 return (gpointer)(gsize)r [ppc_r3];
533 typedef struct {
534 long int type;
535 long int value;
536 } AuxVec;
538 #define MAX_AUX_ENTRIES 128
540 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
541 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
543 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
545 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
546 #define ISA_64 0x40000000
548 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
549 #define ISA_MOVE_FPR_GPR 0x00000200
551 * Initialize the cpu to execute managed code.
553 void
554 mono_arch_cpu_init (void)
559 * Initialize architecture specific code.
561 void
562 mono_arch_init (void)
564 #if defined(MONO_CROSS_COMPILE)
565 #elif defined(__APPLE__)
566 int mib [3];
567 size_t len = sizeof (cachelinesize);
569 mib [0] = CTL_HW;
570 mib [1] = HW_CACHELINE;
572 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
573 perror ("sysctl");
574 cachelinesize = 128;
575 } else {
576 cachelineinc = cachelinesize;
578 #elif defined(__linux__)
579 AuxVec vec [MAX_AUX_ENTRIES];
580 int i, vec_entries = 0;
581 /* sadly this will work only with 2.6 kernels... */
582 FILE* f = fopen ("/proc/self/auxv", "rb");
584 if (f) {
585 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
586 fclose (f);
589 for (i = 0; i < vec_entries; i++) {
590 int type = vec [i].type;
592 if (type == 19) { /* AT_DCACHEBSIZE */
593 cachelinesize = vec [i].value;
594 continue;
597 #elif defined(G_COMPILER_CODEWARRIOR)
598 cachelinesize = 32;
599 cachelineinc = 32;
600 #else
601 //#error Need a way to get cache line size
602 #endif
604 if (mono_hwcap_ppc_has_icache_snoop)
605 cpu_hw_caps |= PPC_ICACHE_SNOOP;
607 if (mono_hwcap_ppc_is_isa_2x)
608 cpu_hw_caps |= PPC_ISA_2X;
610 if (mono_hwcap_ppc_is_isa_64)
611 cpu_hw_caps |= PPC_ISA_64;
613 if (mono_hwcap_ppc_has_move_fpr_gpr)
614 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
616 if (mono_hwcap_ppc_has_multiple_ls_units)
617 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
619 if (!cachelinesize)
620 cachelinesize = 32;
622 if (!cachelineinc)
623 cachelineinc = cachelinesize;
625 if (mono_cpu_count () > 1)
626 cpu_hw_caps |= PPC_SMP_CAPABLE;
628 mono_os_mutex_init_recursive (&mini_arch_mutex);
630 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
631 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
632 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
634 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
636 // FIXME: Fix partial sharing for power and remove this
637 mono_set_partial_sharing_supported (FALSE);
641 * Cleanup architecture specific code.
643 void
644 mono_arch_cleanup (void)
646 mono_os_mutex_destroy (&mini_arch_mutex);
650 * This function returns the optimizations supported on this cpu.
652 guint32
653 mono_arch_cpu_optimizations (guint32 *exclude_mask)
655 guint32 opts = 0;
657 /* no ppc-specific optimizations yet */
658 *exclude_mask = 0;
659 return opts;
663 * This function test for all SIMD functions supported.
665 * Returns a bitmask corresponding to all supported versions.
668 guint32
669 mono_arch_cpu_enumerate_simd_versions (void)
671 /* SIMD is currently unimplemented */
672 return 0;
675 #ifdef __mono_ppc64__
676 #define CASE_PPC32(c)
677 #define CASE_PPC64(c) case c:
678 #else
679 #define CASE_PPC32(c) case c:
680 #define CASE_PPC64(c)
681 #endif
683 static gboolean
684 is_regsize_var (MonoType *t) {
685 if (t->byref)
686 return TRUE;
687 t = mini_get_underlying_type (t);
688 switch (t->type) {
689 case MONO_TYPE_I4:
690 case MONO_TYPE_U4:
691 CASE_PPC64 (MONO_TYPE_I8)
692 CASE_PPC64 (MONO_TYPE_U8)
693 case MONO_TYPE_I:
694 case MONO_TYPE_U:
695 case MONO_TYPE_PTR:
696 case MONO_TYPE_FNPTR:
697 return TRUE;
698 case MONO_TYPE_OBJECT:
699 case MONO_TYPE_STRING:
700 case MONO_TYPE_CLASS:
701 case MONO_TYPE_SZARRAY:
702 case MONO_TYPE_ARRAY:
703 return TRUE;
704 case MONO_TYPE_GENERICINST:
705 if (!mono_type_generic_inst_is_valuetype (t))
706 return TRUE;
707 return FALSE;
708 case MONO_TYPE_VALUETYPE:
709 return FALSE;
711 return FALSE;
714 #ifndef DISABLE_JIT
715 GList *
716 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
718 GList *vars = NULL;
719 int i;
721 for (i = 0; i < cfg->num_varinfo; i++) {
722 MonoInst *ins = cfg->varinfo [i];
723 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
725 /* unused vars */
726 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
727 continue;
729 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
730 continue;
732 /* we can only allocate 32 bit values */
733 if (is_regsize_var (ins->inst_vtype)) {
734 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
735 g_assert (i == vmv->idx);
736 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
740 return vars;
742 #endif /* ifndef DISABLE_JIT */
744 GList *
745 mono_arch_get_global_int_regs (MonoCompile *cfg)
747 GList *regs = NULL;
748 int i, top = 32;
749 if (cfg->frame_reg != ppc_sp)
750 top = 31;
751 /* ppc_r13 is used by the system on PPC EABI */
752 for (i = 14; i < top; ++i) {
754 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
755 * since the trampolines can clobber r12.
757 if (!(cfg->compile_aot && i == 29))
758 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
761 return regs;
765 * mono_arch_regalloc_cost:
767 * Return the cost, in number of memory references, of the action of
768 * allocating the variable VMV into a register during global register
769 * allocation.
771 guint32
772 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
774 /* FIXME: */
775 return 2;
778 void
779 mono_arch_flush_icache (guint8 *code, gint size)
781 #ifdef MONO_CROSS_COMPILE
782 #else
783 register guint8 *p;
784 guint8 *endp, *start;
786 p = start = code;
787 endp = p + size;
788 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
789 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
790 #if defined(G_COMPILER_CODEWARRIOR)
791 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
792 for (p = start; p < endp; p += cachelineinc) {
793 asm { dcbf 0, p };
795 } else {
796 for (p = start; p < endp; p += cachelineinc) {
797 asm { dcbst 0, p };
800 asm { sync };
801 p = code;
802 for (p = start; p < endp; p += cachelineinc) {
803 asm {
804 icbi 0, p
805 sync
808 asm {
809 sync
810 isync
812 #else
813 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
814 * The sync is required to insure that the store queue is completely empty.
815 * While the icbi performs no cache operations, icbi/isync is required to
816 * kill local prefetch.
818 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
819 asm ("sync");
820 asm ("icbi 0,%0;" : : "r"(code) : "memory");
821 asm ("isync");
822 return;
824 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
825 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
826 for (p = start; p < endp; p += cachelineinc) {
827 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
829 } else {
830 for (p = start; p < endp; p += cachelineinc) {
831 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
834 asm ("sync");
835 p = code;
836 for (p = start; p < endp; p += cachelineinc) {
837 /* for ISA2.0+ implementations we should not need any extra sync between the
838 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
839 * So I am not sure which chip had this problem but its not an issue on
840 * of the ISA V2 chips.
842 if (cpu_hw_caps & PPC_ISA_2X)
843 asm ("icbi 0,%0;" : : "r"(p) : "memory");
844 else
845 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
847 if (!(cpu_hw_caps & PPC_ISA_2X))
848 asm ("sync");
849 asm ("isync");
850 #endif
851 #endif
854 void
855 mono_arch_flush_register_windows (void)
859 #ifdef __APPLE__
860 #define ALWAYS_ON_STACK(s) s
861 #define FP_ALSO_IN_REG(s) s
862 #else
863 #ifdef __mono_ppc64__
864 #define ALWAYS_ON_STACK(s) s
865 #define FP_ALSO_IN_REG(s) s
866 #else
867 #define ALWAYS_ON_STACK(s)
868 #define FP_ALSO_IN_REG(s)
869 #endif
870 #define ALIGN_DOUBLES
871 #endif
873 enum {
874 RegTypeGeneral,
875 RegTypeBase,
876 RegTypeFP,
877 RegTypeStructByVal,
878 RegTypeStructByAddr,
879 RegTypeFPStructByVal, // For the v2 ABI, floats should be passed in FRs instead of GRs. Only valid for ABI v2!
882 typedef struct {
883 gint32 offset;
884 guint32 vtsize; /* in param area */
885 guint8 reg;
886 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal/RegTypeFPStructByVal */
887 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
888 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal/RegTypeFPStructByVal */
889 guint8 bytes : 4; /* size in bytes - only valid for
890 RegTypeStructByVal/RegTypeFPStructByVal if the struct fits
891 in one word, otherwise it's 0*/
892 } ArgInfo;
894 typedef struct {
895 int nargs;
896 guint32 stack_usage;
897 guint32 struct_ret;
898 ArgInfo ret;
899 ArgInfo sig_cookie;
900 gboolean vtype_retaddr;
901 int vret_arg_index;
902 ArgInfo args [1];
903 } CallInfo;
905 #define DEBUG(a)
908 #if PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS
910 // Test if a structure is completely composed of either float XOR double fields and has fewer than
911 // PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTER members.
912 // If this is true the structure can be returned directly via float registers instead of by a hidden parameter
913 // pointing to where the return value should be stored.
914 // This is as per the ELF ABI v2.
916 static gboolean
917 is_float_struct_returnable_via_regs (MonoType *type, int* member_cnt, int* member_size)
919 int local_member_cnt, local_member_size;
920 if (!member_cnt) {
921 member_cnt = &local_member_cnt;
923 if (!member_size) {
924 member_size = &local_member_size;
927 gboolean is_all_floats = mini_type_is_hfa(type, member_cnt, member_size);
928 return is_all_floats && (*member_cnt <= PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTERS);
930 #else
932 #define is_float_struct_returnable_via_regs(a,b,c) (FALSE)
934 #endif
936 #if PPC_RETURN_SMALL_STRUCTS_IN_REGS
938 // Test if a structure is smaller in size than 2 doublewords (PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS) and is
939 // completely composed of fields all of basic types.
940 // If this is true the structure can be returned directly via registers r3/r4 instead of by a hidden parameter
941 // pointing to where the return value should be stored.
942 // This is as per the ELF ABI v2.
944 static gboolean
945 is_struct_returnable_via_regs (MonoClass *klass, gboolean is_pinvoke)
947 gboolean has_a_field = FALSE;
948 int size = 0;
949 if (klass) {
950 gpointer iter = NULL;
951 MonoClassField *f;
952 if (is_pinvoke)
953 size = mono_type_native_stack_size (&klass->byval_arg, 0);
954 else
955 size = mini_type_stack_size (&klass->byval_arg, 0);
956 if (size == 0)
957 return TRUE;
958 if (size > PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS)
959 return FALSE;
960 while ((f = mono_class_get_fields (klass, &iter))) {
961 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
962 // TBD: Is there a better way to check for the basic types?
963 if (f->type->byref) {
964 return FALSE;
965 } else if ((f->type->type >= MONO_TYPE_BOOLEAN) && (f->type->type <= MONO_TYPE_R8)) {
966 has_a_field = TRUE;
967 } else if (MONO_TYPE_ISSTRUCT (f->type)) {
968 MonoClass *klass = mono_class_from_mono_type (f->type);
969 if (is_struct_returnable_via_regs(klass, is_pinvoke)) {
970 has_a_field = TRUE;
971 } else {
972 return FALSE;
974 } else {
975 return FALSE;
980 return has_a_field;
982 #else
984 #define is_struct_returnable_via_regs(a,b) (FALSE)
986 #endif
988 static void inline
989 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
991 #ifdef __mono_ppc64__
992 g_assert (simple);
993 #endif
995 if (simple) {
996 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
997 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
998 ainfo->reg = ppc_sp; /* in the caller */
999 ainfo->regtype = RegTypeBase;
1000 *stack_size += sizeof (gpointer);
1001 } else {
1002 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
1003 ainfo->reg = *gr;
1005 } else {
1006 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
1007 #ifdef ALIGN_DOUBLES
1008 //*stack_size += (*stack_size % 8);
1009 #endif
1010 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
1011 ainfo->reg = ppc_sp; /* in the caller */
1012 ainfo->regtype = RegTypeBase;
1013 *stack_size += 8;
1014 } else {
1015 #ifdef ALIGN_DOUBLES
1016 if (!((*gr) & 1))
1017 (*gr) ++;
1018 #endif
1019 ALWAYS_ON_STACK (*stack_size += 8);
1020 ainfo->reg = *gr;
1022 (*gr) ++;
1024 (*gr) ++;
1027 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1028 static gboolean
1029 has_only_a_r48_field (MonoClass *klass)
1031 gpointer iter;
1032 MonoClassField *f;
1033 gboolean have_field = FALSE;
1034 iter = NULL;
1035 while ((f = mono_class_get_fields (klass, &iter))) {
1036 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1037 if (have_field)
1038 return FALSE;
1039 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
1040 have_field = TRUE;
1041 else
1042 return FALSE;
1045 return have_field;
1047 #endif
1049 static CallInfo*
1050 get_call_info (MonoMethodSignature *sig)
1052 guint i, fr, gr, pstart;
1053 int n = sig->hasthis + sig->param_count;
1054 MonoType *simpletype;
1055 guint32 stack_size = 0;
1056 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1057 gboolean is_pinvoke = sig->pinvoke;
1059 fr = PPC_FIRST_FPARG_REG;
1060 gr = PPC_FIRST_ARG_REG;
1062 /* FIXME: handle returning a struct */
1063 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1064 cinfo->vtype_retaddr = TRUE;
1067 pstart = 0;
1068 n = 0;
1070 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1071 * the first argument, allowing 'this' to be always passed in the first arg reg.
1072 * Also do this if the first argument is a reference type, since virtual calls
1073 * are sometimes made using calli without sig->hasthis set, like in the delegate
1074 * invoke wrappers.
1076 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1077 if (sig->hasthis) {
1078 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1079 n ++;
1080 } else {
1081 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1082 pstart = 1;
1083 n ++;
1085 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1086 cinfo->struct_ret = cinfo->ret.reg;
1087 cinfo->vret_arg_index = 1;
1088 } else {
1089 /* this */
1090 if (sig->hasthis) {
1091 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1092 n ++;
1095 if (cinfo->vtype_retaddr) {
1096 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1097 cinfo->struct_ret = cinfo->ret.reg;
1101 DEBUG(printf("params: %d\n", sig->param_count));
1102 for (i = pstart; i < sig->param_count; ++i) {
1103 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1104 /* Prevent implicit arguments and sig_cookie from
1105 being passed in registers */
1106 gr = PPC_LAST_ARG_REG + 1;
1107 /* FIXME: don't we have to set fr, too? */
1108 /* Emit the signature cookie just before the implicit arguments */
1109 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1111 DEBUG(printf("param %d: ", i));
1112 if (sig->params [i]->byref) {
1113 DEBUG(printf("byref\n"));
1114 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1115 n++;
1116 continue;
1118 simpletype = mini_get_underlying_type (sig->params [i]);
1119 switch (simpletype->type) {
1120 case MONO_TYPE_BOOLEAN:
1121 case MONO_TYPE_I1:
1122 case MONO_TYPE_U1:
1123 cinfo->args [n].size = 1;
1124 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1125 n++;
1126 break;
1127 case MONO_TYPE_CHAR:
1128 case MONO_TYPE_I2:
1129 case MONO_TYPE_U2:
1130 cinfo->args [n].size = 2;
1131 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1132 n++;
1133 break;
1134 case MONO_TYPE_I4:
1135 case MONO_TYPE_U4:
1136 cinfo->args [n].size = 4;
1137 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1138 n++;
1139 break;
1140 case MONO_TYPE_I:
1141 case MONO_TYPE_U:
1142 case MONO_TYPE_PTR:
1143 case MONO_TYPE_FNPTR:
1144 case MONO_TYPE_CLASS:
1145 case MONO_TYPE_OBJECT:
1146 case MONO_TYPE_STRING:
1147 case MONO_TYPE_SZARRAY:
1148 case MONO_TYPE_ARRAY:
1149 cinfo->args [n].size = sizeof (gpointer);
1150 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1151 n++;
1152 break;
1153 case MONO_TYPE_GENERICINST:
1154 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1155 cinfo->args [n].size = sizeof (gpointer);
1156 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1157 n++;
1158 break;
1160 /* Fall through */
1161 case MONO_TYPE_VALUETYPE:
1162 case MONO_TYPE_TYPEDBYREF: {
1163 gint size;
1164 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1165 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1166 size = sizeof (MonoTypedRef);
1167 else if (is_pinvoke)
1168 size = mono_class_native_size (klass, NULL);
1169 else
1170 size = mono_class_value_size (klass, NULL);
1172 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1173 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1174 cinfo->args [n].size = size;
1176 /* It was 7, now it is 8 in LinuxPPC */
1177 if (fr <= PPC_LAST_FPARG_REG) {
1178 cinfo->args [n].regtype = RegTypeFP;
1179 cinfo->args [n].reg = fr;
1180 fr ++;
1181 FP_ALSO_IN_REG (gr ++);
1182 #if !defined(__mono_ppc64__)
1183 if (size == 8)
1184 FP_ALSO_IN_REG (gr ++);
1185 #endif
1186 ALWAYS_ON_STACK (stack_size += size);
1187 } else {
1188 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1189 cinfo->args [n].regtype = RegTypeBase;
1190 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1191 stack_size += 8;
1193 n++;
1194 break;
1196 #endif
1197 DEBUG(printf ("load %d bytes struct\n",
1198 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1200 #if PPC_PASS_STRUCTS_BY_VALUE
1202 int align_size = size;
1203 int nregs = 0;
1204 int rest = PPC_LAST_ARG_REG - gr + 1;
1205 int n_in_regs = 0;
1207 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1208 int mbr_cnt = 0;
1209 int mbr_size = 0;
1210 gboolean is_all_floats = is_float_struct_returnable_via_regs (sig->params [i], &mbr_cnt, &mbr_size);
1212 if (is_all_floats) {
1213 rest = PPC_LAST_FPARG_REG - fr + 1;
1215 // Pass small (<= 8 member) structures entirely made up of either float or double members
1216 // in FR registers. There have to be at least mbr_cnt registers left.
1217 if (is_all_floats &&
1218 (rest >= mbr_cnt)) {
1219 nregs = mbr_cnt;
1220 n_in_regs = MIN (rest, nregs);
1221 cinfo->args [n].regtype = RegTypeFPStructByVal;
1222 cinfo->args [n].vtregs = n_in_regs;
1223 cinfo->args [n].size = mbr_size;
1224 cinfo->args [n].vtsize = nregs - n_in_regs;
1225 cinfo->args [n].reg = fr;
1226 fr += n_in_regs;
1227 if (mbr_size == 4) {
1228 // floats
1229 FP_ALSO_IN_REG (gr += (n_in_regs+1)/2);
1230 } else {
1231 // doubles
1232 FP_ALSO_IN_REG (gr += (n_in_regs));
1234 } else
1235 #endif
1237 align_size += (sizeof (gpointer) - 1);
1238 align_size &= ~(sizeof (gpointer) - 1);
1239 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1240 n_in_regs = MIN (rest, nregs);
1241 if (n_in_regs < 0)
1242 n_in_regs = 0;
1243 #ifdef __APPLE__
1244 /* FIXME: check this */
1245 if (size >= 3 && size % 4 != 0)
1246 n_in_regs = 0;
1247 #endif
1248 cinfo->args [n].regtype = RegTypeStructByVal;
1249 cinfo->args [n].vtregs = n_in_regs;
1250 cinfo->args [n].size = n_in_regs;
1251 cinfo->args [n].vtsize = nregs - n_in_regs;
1252 cinfo->args [n].reg = gr;
1253 gr += n_in_regs;
1256 #ifdef __mono_ppc64__
1257 if (nregs == 1 && is_pinvoke)
1258 cinfo->args [n].bytes = size;
1259 else
1260 #endif
1261 cinfo->args [n].bytes = 0;
1262 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1263 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1264 stack_size += nregs * sizeof (gpointer);
1266 #else
1267 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1268 cinfo->args [n].regtype = RegTypeStructByAddr;
1269 cinfo->args [n].vtsize = size;
1270 #endif
1271 n++;
1272 break;
1274 case MONO_TYPE_U8:
1275 case MONO_TYPE_I8:
1276 cinfo->args [n].size = 8;
1277 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1278 n++;
1279 break;
1280 case MONO_TYPE_R4:
1281 cinfo->args [n].size = 4;
1283 /* It was 7, now it is 8 in LinuxPPC */
1284 if (fr <= PPC_LAST_FPARG_REG
1285 // For non-native vararg calls the parms must go in storage
1286 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1288 cinfo->args [n].regtype = RegTypeFP;
1289 cinfo->args [n].reg = fr;
1290 fr ++;
1291 FP_ALSO_IN_REG (gr ++);
1292 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1293 } else {
1294 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1295 cinfo->args [n].regtype = RegTypeBase;
1296 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1297 stack_size += SIZEOF_REGISTER;
1299 n++;
1300 break;
1301 case MONO_TYPE_R8:
1302 cinfo->args [n].size = 8;
1303 /* It was 7, now it is 8 in LinuxPPC */
1304 if (fr <= PPC_LAST_FPARG_REG
1305 // For non-native vararg calls the parms must go in storage
1306 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1308 cinfo->args [n].regtype = RegTypeFP;
1309 cinfo->args [n].reg = fr;
1310 fr ++;
1311 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1312 ALWAYS_ON_STACK (stack_size += 8);
1313 } else {
1314 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1315 cinfo->args [n].regtype = RegTypeBase;
1316 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1317 stack_size += 8;
1319 n++;
1320 break;
1321 default:
1322 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1325 cinfo->nargs = n;
1327 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1328 /* Prevent implicit arguments and sig_cookie from
1329 being passed in registers */
1330 gr = PPC_LAST_ARG_REG + 1;
1331 /* Emit the signature cookie just before the implicit arguments */
1332 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1336 simpletype = mini_get_underlying_type (sig->ret);
1337 switch (simpletype->type) {
1338 case MONO_TYPE_BOOLEAN:
1339 case MONO_TYPE_I1:
1340 case MONO_TYPE_U1:
1341 case MONO_TYPE_I2:
1342 case MONO_TYPE_U2:
1343 case MONO_TYPE_CHAR:
1344 case MONO_TYPE_I4:
1345 case MONO_TYPE_U4:
1346 case MONO_TYPE_I:
1347 case MONO_TYPE_U:
1348 case MONO_TYPE_PTR:
1349 case MONO_TYPE_FNPTR:
1350 case MONO_TYPE_CLASS:
1351 case MONO_TYPE_OBJECT:
1352 case MONO_TYPE_SZARRAY:
1353 case MONO_TYPE_ARRAY:
1354 case MONO_TYPE_STRING:
1355 cinfo->ret.reg = ppc_r3;
1356 break;
1357 case MONO_TYPE_U8:
1358 case MONO_TYPE_I8:
1359 cinfo->ret.reg = ppc_r3;
1360 break;
1361 case MONO_TYPE_R4:
1362 case MONO_TYPE_R8:
1363 cinfo->ret.reg = ppc_f1;
1364 cinfo->ret.regtype = RegTypeFP;
1365 break;
1366 case MONO_TYPE_GENERICINST:
1367 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1368 cinfo->ret.reg = ppc_r3;
1369 break;
1371 break;
1372 case MONO_TYPE_VALUETYPE:
1373 break;
1374 case MONO_TYPE_TYPEDBYREF:
1375 case MONO_TYPE_VOID:
1376 break;
1377 default:
1378 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1382 /* align stack size to 16 */
1383 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1384 stack_size = (stack_size + 15) & ~15;
1386 cinfo->stack_usage = stack_size;
1387 return cinfo;
1390 gboolean
1391 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1393 CallInfo *c1, *c2;
1394 gboolean res;
1395 int i;
1397 c1 = get_call_info (caller_sig);
1398 c2 = get_call_info (callee_sig);
1399 res = c1->stack_usage >= c2->stack_usage;
1400 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1401 /* An address on the callee's stack is passed as the first argument */
1402 res = FALSE;
1403 for (i = 0; i < c2->nargs; ++i) {
1404 if (c2->args [i].regtype == RegTypeStructByAddr)
1405 /* An address on the callee's stack is passed as the argument */
1406 res = FALSE;
1410 if (!mono_debug_count ())
1411 res = FALSE;
1414 g_free (c1);
1415 g_free (c2);
1417 return res;
1421 * Set var information according to the calling convention. ppc version.
1422 * The locals var stuff should most likely be split in another method.
1424 void
1425 mono_arch_allocate_vars (MonoCompile *m)
1427 MonoMethodSignature *sig;
1428 MonoMethodHeader *header;
1429 MonoInst *inst;
1430 int i, offset, size, align, curinst;
1431 int frame_reg = ppc_sp;
1432 gint32 *offsets;
1433 guint32 locals_stack_size, locals_stack_align;
1435 m->flags |= MONO_CFG_HAS_SPILLUP;
1437 /* allow room for the vararg method args: void* and long/double */
1438 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1439 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1440 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1441 * call convs needs to be handled this way.
1443 if (m->flags & MONO_CFG_HAS_VARARGS)
1444 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1445 /* gtk-sharp and other broken code will dllimport vararg functions even with
1446 * non-varargs signatures. Since there is little hope people will get this right
1447 * we assume they won't.
1449 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1450 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1452 header = m->header;
1455 * We use the frame register also for any method that has
1456 * exception clauses. This way, when the handlers are called,
1457 * the code will reference local variables using the frame reg instead of
1458 * the stack pointer: if we had to restore the stack pointer, we'd
1459 * corrupt the method frames that are already on the stack (since
1460 * filters get called before stack unwinding happens) when the filter
1461 * code would call any method (this also applies to finally etc.).
1463 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1464 frame_reg = ppc_r31;
1465 m->frame_reg = frame_reg;
1466 if (frame_reg != ppc_sp) {
1467 m->used_int_regs |= 1 << frame_reg;
1470 sig = mono_method_signature (m->method);
1472 offset = 0;
1473 curinst = 0;
1474 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1475 m->ret->opcode = OP_REGVAR;
1476 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1477 } else {
1478 /* FIXME: handle long values? */
1479 switch (mini_get_underlying_type (sig->ret)->type) {
1480 case MONO_TYPE_VOID:
1481 break;
1482 case MONO_TYPE_R4:
1483 case MONO_TYPE_R8:
1484 m->ret->opcode = OP_REGVAR;
1485 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1486 break;
1487 default:
1488 m->ret->opcode = OP_REGVAR;
1489 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1490 break;
1493 /* local vars are at a positive offset from the stack pointer */
1495 * also note that if the function uses alloca, we use ppc_r31
1496 * to point at the local variables.
1498 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1499 /* align the offset to 16 bytes: not sure this is needed here */
1500 //offset += 16 - 1;
1501 //offset &= ~(16 - 1);
1503 /* add parameter area size for called functions */
1504 offset += m->param_area;
1505 offset += 16 - 1;
1506 offset &= ~(16 - 1);
1508 /* allow room to save the return value */
1509 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1510 offset += 8;
1512 /* the MonoLMF structure is stored just below the stack pointer */
1514 #if 0
1515 /* this stuff should not be needed on ppc and the new jit,
1516 * because a call on ppc to the handlers doesn't change the
1517 * stack pointer and the jist doesn't manipulate the stack pointer
1518 * for operations involving valuetypes.
1520 /* reserve space to store the esp */
1521 offset += sizeof (gpointer);
1523 /* this is a global constant */
1524 mono_exc_esp_offset = offset;
1525 #endif
1527 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1528 offset += sizeof(gpointer) - 1;
1529 offset &= ~(sizeof(gpointer) - 1);
1531 m->vret_addr->opcode = OP_REGOFFSET;
1532 m->vret_addr->inst_basereg = frame_reg;
1533 m->vret_addr->inst_offset = offset;
1535 if (G_UNLIKELY (m->verbose_level > 1)) {
1536 printf ("vret_addr =");
1537 mono_print_ins (m->vret_addr);
1540 offset += sizeof(gpointer);
1543 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1544 if (locals_stack_align) {
1545 offset += (locals_stack_align - 1);
1546 offset &= ~(locals_stack_align - 1);
1548 for (i = m->locals_start; i < m->num_varinfo; i++) {
1549 if (offsets [i] != -1) {
1550 MonoInst *inst = m->varinfo [i];
1551 inst->opcode = OP_REGOFFSET;
1552 inst->inst_basereg = frame_reg;
1553 inst->inst_offset = offset + offsets [i];
1555 g_print ("allocating local %d (%s) to %d\n",
1556 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1560 offset += locals_stack_size;
1562 curinst = 0;
1563 if (sig->hasthis) {
1564 inst = m->args [curinst];
1565 if (inst->opcode != OP_REGVAR) {
1566 inst->opcode = OP_REGOFFSET;
1567 inst->inst_basereg = frame_reg;
1568 offset += sizeof (gpointer) - 1;
1569 offset &= ~(sizeof (gpointer) - 1);
1570 inst->inst_offset = offset;
1571 offset += sizeof (gpointer);
1573 curinst++;
1576 for (i = 0; i < sig->param_count; ++i) {
1577 inst = m->args [curinst];
1578 if (inst->opcode != OP_REGVAR) {
1579 inst->opcode = OP_REGOFFSET;
1580 inst->inst_basereg = frame_reg;
1581 if (sig->pinvoke) {
1582 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1583 inst->backend.is_pinvoke = 1;
1584 } else {
1585 size = mono_type_size (sig->params [i], &align);
1587 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1588 size = align = sizeof (gpointer);
1590 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1591 * they are saved using std in the prolog.
1593 align = sizeof (gpointer);
1594 offset += align - 1;
1595 offset &= ~(align - 1);
1596 inst->inst_offset = offset;
1597 offset += size;
1599 curinst++;
1602 /* some storage for fp conversions */
1603 offset += 8 - 1;
1604 offset &= ~(8 - 1);
1605 m->arch.fp_conv_var_offset = offset;
1606 offset += 8;
1608 /* align the offset to 16 bytes */
1609 offset += 16 - 1;
1610 offset &= ~(16 - 1);
1612 /* change sign? */
1613 m->stack_offset = offset;
1615 if (sig->call_convention == MONO_CALL_VARARG) {
1616 CallInfo *cinfo = get_call_info (m->method->signature);
1618 m->sig_cookie = cinfo->sig_cookie.offset;
1620 g_free(cinfo);
1624 void
1625 mono_arch_create_vars (MonoCompile *cfg)
1627 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1629 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1630 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1634 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1635 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1638 static void
1639 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1641 int sig_reg = mono_alloc_ireg (cfg);
1643 /* FIXME: Add support for signature tokens to AOT */
1644 cfg->disable_aot = TRUE;
1646 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1647 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1648 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1651 void
1652 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1654 MonoInst *in, *ins;
1655 MonoMethodSignature *sig;
1656 int i, n;
1657 CallInfo *cinfo;
1659 sig = call->signature;
1660 n = sig->param_count + sig->hasthis;
1662 cinfo = get_call_info (sig);
1664 for (i = 0; i < n; ++i) {
1665 ArgInfo *ainfo = cinfo->args + i;
1666 MonoType *t;
1668 if (i >= sig->hasthis)
1669 t = sig->params [i - sig->hasthis];
1670 else
1671 t = &mono_defaults.int_class->byval_arg;
1672 t = mini_get_underlying_type (t);
1674 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1675 emit_sig_cookie (cfg, call, cinfo);
1677 in = call->args [i];
1679 if (ainfo->regtype == RegTypeGeneral) {
1680 #ifndef __mono_ppc64__
1681 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1682 MONO_INST_NEW (cfg, ins, OP_MOVE);
1683 ins->dreg = mono_alloc_ireg (cfg);
1684 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1685 MONO_ADD_INS (cfg->cbb, ins);
1686 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1688 MONO_INST_NEW (cfg, ins, OP_MOVE);
1689 ins->dreg = mono_alloc_ireg (cfg);
1690 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1691 MONO_ADD_INS (cfg->cbb, ins);
1692 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1693 } else
1694 #endif
1696 MONO_INST_NEW (cfg, ins, OP_MOVE);
1697 ins->dreg = mono_alloc_ireg (cfg);
1698 ins->sreg1 = in->dreg;
1699 MONO_ADD_INS (cfg->cbb, ins);
1701 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1703 } else if (ainfo->regtype == RegTypeStructByAddr) {
1704 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1705 ins->opcode = OP_OUTARG_VT;
1706 ins->sreg1 = in->dreg;
1707 ins->klass = in->klass;
1708 ins->inst_p0 = call;
1709 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1710 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1711 MONO_ADD_INS (cfg->cbb, ins);
1712 } else if (ainfo->regtype == RegTypeStructByVal) {
1713 /* this is further handled in mono_arch_emit_outarg_vt () */
1714 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1715 ins->opcode = OP_OUTARG_VT;
1716 ins->sreg1 = in->dreg;
1717 ins->klass = in->klass;
1718 ins->inst_p0 = call;
1719 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1720 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1721 MONO_ADD_INS (cfg->cbb, ins);
1722 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1723 /* this is further handled in mono_arch_emit_outarg_vt () */
1724 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1725 ins->opcode = OP_OUTARG_VT;
1726 ins->sreg1 = in->dreg;
1727 ins->klass = in->klass;
1728 ins->inst_p0 = call;
1729 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1730 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1731 MONO_ADD_INS (cfg->cbb, ins);
1732 cfg->flags |= MONO_CFG_HAS_FPOUT;
1733 } else if (ainfo->regtype == RegTypeBase) {
1734 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1735 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1736 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1737 if (t->type == MONO_TYPE_R8)
1738 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1739 else
1740 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1741 } else {
1742 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1744 } else if (ainfo->regtype == RegTypeFP) {
1745 if (t->type == MONO_TYPE_VALUETYPE) {
1746 /* this is further handled in mono_arch_emit_outarg_vt () */
1747 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1748 ins->opcode = OP_OUTARG_VT;
1749 ins->sreg1 = in->dreg;
1750 ins->klass = in->klass;
1751 ins->inst_p0 = call;
1752 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1753 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1754 MONO_ADD_INS (cfg->cbb, ins);
1756 cfg->flags |= MONO_CFG_HAS_FPOUT;
1757 } else {
1758 int dreg = mono_alloc_freg (cfg);
1760 if (ainfo->size == 4) {
1761 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1762 } else {
1763 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1764 ins->dreg = dreg;
1765 ins->sreg1 = in->dreg;
1766 MONO_ADD_INS (cfg->cbb, ins);
1769 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1770 cfg->flags |= MONO_CFG_HAS_FPOUT;
1772 } else {
1773 g_assert_not_reached ();
1777 /* Emit the signature cookie in the case that there is no
1778 additional argument */
1779 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1780 emit_sig_cookie (cfg, call, cinfo);
1782 if (cinfo->struct_ret) {
1783 MonoInst *vtarg;
1785 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1786 vtarg->sreg1 = call->vret_var->dreg;
1787 vtarg->dreg = mono_alloc_preg (cfg);
1788 MONO_ADD_INS (cfg->cbb, vtarg);
1790 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1793 call->stack_usage = cinfo->stack_usage;
1794 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1795 cfg->flags |= MONO_CFG_HAS_CALLS;
1797 g_free (cinfo);
1800 #ifndef DISABLE_JIT
1802 void
1803 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1805 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1806 ArgInfo *ainfo = ins->inst_p1;
1807 int ovf_size = ainfo->vtsize;
1808 int doffset = ainfo->offset;
1809 int i, soffset, dreg;
1811 if (ainfo->regtype == RegTypeStructByVal) {
1812 #ifdef __APPLE__
1813 guint32 size = 0;
1814 #endif
1815 soffset = 0;
1816 #ifdef __APPLE__
1818 * Darwin pinvokes needs some special handling for 1
1819 * and 2 byte arguments
1821 g_assert (ins->klass);
1822 if (call->signature->pinvoke)
1823 size = mono_class_native_size (ins->klass, NULL);
1824 if (size == 2 || size == 1) {
1825 int tmpr = mono_alloc_ireg (cfg);
1826 if (size == 1)
1827 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1828 else
1829 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1830 dreg = mono_alloc_ireg (cfg);
1831 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1832 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1833 } else
1834 #endif
1835 for (i = 0; i < ainfo->vtregs; ++i) {
1836 dreg = mono_alloc_ireg (cfg);
1837 #if G_BYTE_ORDER == G_BIG_ENDIAN
1838 int antipadding = 0;
1839 if (ainfo->bytes) {
1840 g_assert (i == 0);
1841 antipadding = sizeof (gpointer) - ainfo->bytes;
1843 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1844 if (antipadding)
1845 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1846 #else
1847 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1848 #endif
1849 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1850 soffset += sizeof (gpointer);
1852 if (ovf_size != 0)
1853 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1854 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1855 soffset = 0;
1856 for (i = 0; i < ainfo->vtregs; ++i) {
1857 int tmpr = mono_alloc_freg (cfg);
1858 if (ainfo->size == 4)
1859 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, soffset);
1860 else // ==8
1861 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, soffset);
1862 dreg = mono_alloc_freg (cfg);
1863 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1864 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg+i, TRUE);
1865 soffset += ainfo->size;
1867 if (ovf_size != 0)
1868 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1869 } else if (ainfo->regtype == RegTypeFP) {
1870 int tmpr = mono_alloc_freg (cfg);
1871 if (ainfo->size == 4)
1872 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1873 else
1874 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1875 dreg = mono_alloc_freg (cfg);
1876 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1877 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1878 } else {
1879 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1880 MonoInst *load;
1881 guint32 size;
1883 /* FIXME: alignment? */
1884 if (call->signature->pinvoke) {
1885 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1886 vtcopy->backend.is_pinvoke = 1;
1887 } else {
1888 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1890 if (size > 0)
1891 g_assert (ovf_size > 0);
1893 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1894 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1896 if (ainfo->offset)
1897 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1898 else
1899 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1903 void
1904 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1906 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1907 if (!ret->byref) {
1908 #ifndef __mono_ppc64__
1909 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1910 MonoInst *ins;
1912 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1913 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1914 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1915 MONO_ADD_INS (cfg->cbb, ins);
1916 return;
1918 #endif
1919 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1920 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1921 return;
1924 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1927 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1928 gboolean
1929 mono_arch_is_inst_imm (gint64 imm)
1931 return TRUE;
1934 #endif /* DISABLE_JIT */
1937 * Allow tracing to work with this interface (with an optional argument)
1940 void*
1941 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1943 guchar *code = p;
1945 ppc_load_ptr (code, ppc_r3, cfg->method);
1946 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1947 ppc_load_func (code, PPC_CALL_REG, func);
1948 ppc_mtlr (code, PPC_CALL_REG);
1949 ppc_blrl (code);
1950 return code;
1953 enum {
1954 SAVE_NONE,
1955 SAVE_STRUCT,
1956 SAVE_ONE,
1957 SAVE_TWO,
1958 SAVE_FP
1961 void*
1962 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1964 guchar *code = p;
1965 int save_mode = SAVE_NONE;
1966 int offset;
1967 MonoMethod *method = cfg->method;
1968 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
1969 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1970 save_offset += 15;
1971 save_offset &= ~15;
1973 offset = code - cfg->native_code;
1974 /* we need about 16 instructions */
1975 if (offset > (cfg->code_size - 16 * 4)) {
1976 cfg->code_size *= 2;
1977 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1978 code = cfg->native_code + offset;
1981 switch (rtype) {
1982 case MONO_TYPE_VOID:
1983 /* special case string .ctor icall */
1984 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1985 save_mode = SAVE_ONE;
1986 else
1987 save_mode = SAVE_NONE;
1988 break;
1989 #ifndef __mono_ppc64__
1990 case MONO_TYPE_I8:
1991 case MONO_TYPE_U8:
1992 save_mode = SAVE_TWO;
1993 break;
1994 #endif
1995 case MONO_TYPE_R4:
1996 case MONO_TYPE_R8:
1997 save_mode = SAVE_FP;
1998 break;
1999 case MONO_TYPE_VALUETYPE:
2000 save_mode = SAVE_STRUCT;
2001 break;
2002 default:
2003 save_mode = SAVE_ONE;
2004 break;
2007 switch (save_mode) {
2008 case SAVE_TWO:
2009 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
2010 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
2011 if (enable_arguments) {
2012 ppc_mr (code, ppc_r5, ppc_r4);
2013 ppc_mr (code, ppc_r4, ppc_r3);
2015 break;
2016 case SAVE_ONE:
2017 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
2018 if (enable_arguments) {
2019 ppc_mr (code, ppc_r4, ppc_r3);
2021 break;
2022 case SAVE_FP:
2023 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
2024 if (enable_arguments) {
2025 /* FIXME: what reg? */
2026 ppc_fmr (code, ppc_f3, ppc_f1);
2027 /* FIXME: use 8 byte load on PPC64 */
2028 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
2029 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
2031 break;
2032 case SAVE_STRUCT:
2033 if (enable_arguments) {
2034 /* FIXME: get the actual address */
2035 ppc_mr (code, ppc_r4, ppc_r3);
2036 // FIXME: Support the new v2 ABI!
2038 break;
2039 case SAVE_NONE:
2040 default:
2041 break;
2044 ppc_load_ptr (code, ppc_r3, cfg->method);
2045 ppc_load_func (code, PPC_CALL_REG, func);
2046 ppc_mtlr (code, PPC_CALL_REG);
2047 ppc_blrl (code);
2049 switch (save_mode) {
2050 case SAVE_TWO:
2051 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
2052 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
2053 break;
2054 case SAVE_ONE:
2055 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
2056 break;
2057 case SAVE_FP:
2058 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
2059 break;
2060 case SAVE_NONE:
2061 default:
2062 break;
2065 return code;
2068 * Conditional branches have a small offset, so if it is likely overflowed,
2069 * we do a branch to the end of the method (uncond branches have much larger
2070 * offsets) where we perform the conditional and jump back unconditionally.
2071 * It's slightly slower, since we add two uncond branches, but it's very simple
2072 * with the current patch implementation and such large methods are likely not
2073 * going to be perf critical anyway.
2075 typedef struct {
2076 union {
2077 MonoBasicBlock *bb;
2078 const char *exception;
2079 } data;
2080 guint32 ip_offset;
2081 guint16 b0_cond;
2082 guint16 b1_cond;
2083 } MonoOvfJump;
2085 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
2086 if (0 && ins->inst_true_bb->native_offset) { \
2087 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
2088 } else { \
2089 int br_disp = ins->inst_true_bb->max_offset - offset; \
2090 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2091 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2092 ovfj->data.bb = ins->inst_true_bb; \
2093 ovfj->ip_offset = 0; \
2094 ovfj->b0_cond = (b0); \
2095 ovfj->b1_cond = (b1); \
2096 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
2097 ppc_b (code, 0); \
2098 } else { \
2099 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
2100 ppc_bc (code, (b0), (b1), 0); \
2104 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
2106 /* emit an exception if condition is fail
2108 * We assign the extra code used to throw the implicit exceptions
2109 * to cfg->bb_exit as far as the big branch handling is concerned
2111 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
2112 do { \
2113 int br_disp = cfg->bb_exit->max_offset - offset; \
2114 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2115 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2116 ovfj->data.exception = (exc_name); \
2117 ovfj->ip_offset = code - cfg->native_code; \
2118 ovfj->b0_cond = (b0); \
2119 ovfj->b1_cond = (b1); \
2120 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
2121 ppc_bl (code, 0); \
2122 cfg->bb_exit->max_offset += 24; \
2123 } else { \
2124 mono_add_patch_info (cfg, code - cfg->native_code, \
2125 MONO_PATCH_INFO_EXC, exc_name); \
2126 ppc_bcl (code, (b0), (b1), 0); \
2128 } while (0);
2130 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2132 void
2133 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2137 static int
2138 normalize_opcode (int opcode)
2140 switch (opcode) {
2141 #ifndef __mono_ilp32__
2142 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2143 return OP_LOAD_MEMBASE;
2144 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2145 return OP_LOAD_MEMINDEX;
2146 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2147 return OP_STORE_MEMBASE_REG;
2148 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2149 return OP_STORE_MEMBASE_IMM;
2150 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2151 return OP_STORE_MEMINDEX;
2152 #endif
2153 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2154 return OP_SHR_IMM;
2155 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2156 return OP_SHR_UN_IMM;
2157 default:
2158 return opcode;
2162 void
2163 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2165 MonoInst *ins, *n, *last_ins = NULL;
2167 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2168 switch (normalize_opcode (ins->opcode)) {
2169 case OP_MUL_IMM:
2170 /* remove unnecessary multiplication with 1 */
2171 if (ins->inst_imm == 1) {
2172 if (ins->dreg != ins->sreg1) {
2173 ins->opcode = OP_MOVE;
2174 } else {
2175 MONO_DELETE_INS (bb, ins);
2176 continue;
2178 } else {
2179 int power2 = mono_is_power_of_two (ins->inst_imm);
2180 if (power2 > 0) {
2181 ins->opcode = OP_SHL_IMM;
2182 ins->inst_imm = power2;
2185 break;
2186 case OP_LOAD_MEMBASE:
2188 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2189 * OP_LOAD_MEMBASE offset(basereg), reg
2191 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2192 ins->inst_basereg == last_ins->inst_destbasereg &&
2193 ins->inst_offset == last_ins->inst_offset) {
2194 if (ins->dreg == last_ins->sreg1) {
2195 MONO_DELETE_INS (bb, ins);
2196 continue;
2197 } else {
2198 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2199 ins->opcode = OP_MOVE;
2200 ins->sreg1 = last_ins->sreg1;
2204 * Note: reg1 must be different from the basereg in the second load
2205 * OP_LOAD_MEMBASE offset(basereg), reg1
2206 * OP_LOAD_MEMBASE offset(basereg), reg2
2207 * -->
2208 * OP_LOAD_MEMBASE offset(basereg), reg1
2209 * OP_MOVE reg1, reg2
2211 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2212 ins->inst_basereg != last_ins->dreg &&
2213 ins->inst_basereg == last_ins->inst_basereg &&
2214 ins->inst_offset == last_ins->inst_offset) {
2216 if (ins->dreg == last_ins->dreg) {
2217 MONO_DELETE_INS (bb, ins);
2218 continue;
2219 } else {
2220 ins->opcode = OP_MOVE;
2221 ins->sreg1 = last_ins->dreg;
2224 //g_assert_not_reached ();
2226 #if 0
2228 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2229 * OP_LOAD_MEMBASE offset(basereg), reg
2230 * -->
2231 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2232 * OP_ICONST reg, imm
2234 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2235 ins->inst_basereg == last_ins->inst_destbasereg &&
2236 ins->inst_offset == last_ins->inst_offset) {
2237 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2238 ins->opcode = OP_ICONST;
2239 ins->inst_c0 = last_ins->inst_imm;
2240 g_assert_not_reached (); // check this rule
2241 #endif
2243 break;
2244 case OP_LOADU1_MEMBASE:
2245 case OP_LOADI1_MEMBASE:
2246 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2247 ins->inst_basereg == last_ins->inst_destbasereg &&
2248 ins->inst_offset == last_ins->inst_offset) {
2249 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2250 ins->sreg1 = last_ins->sreg1;
2252 break;
2253 case OP_LOADU2_MEMBASE:
2254 case OP_LOADI2_MEMBASE:
2255 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2256 ins->inst_basereg == last_ins->inst_destbasereg &&
2257 ins->inst_offset == last_ins->inst_offset) {
2258 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2259 ins->sreg1 = last_ins->sreg1;
2261 break;
2262 #ifdef __mono_ppc64__
2263 case OP_LOADU4_MEMBASE:
2264 case OP_LOADI4_MEMBASE:
2265 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2266 ins->inst_basereg == last_ins->inst_destbasereg &&
2267 ins->inst_offset == last_ins->inst_offset) {
2268 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2269 ins->sreg1 = last_ins->sreg1;
2271 break;
2272 #endif
2273 case OP_MOVE:
2274 ins->opcode = OP_MOVE;
2276 * OP_MOVE reg, reg
2278 if (ins->dreg == ins->sreg1) {
2279 MONO_DELETE_INS (bb, ins);
2280 continue;
2283 * OP_MOVE sreg, dreg
2284 * OP_MOVE dreg, sreg
2286 if (last_ins && last_ins->opcode == OP_MOVE &&
2287 ins->sreg1 == last_ins->dreg &&
2288 ins->dreg == last_ins->sreg1) {
2289 MONO_DELETE_INS (bb, ins);
2290 continue;
2292 break;
2294 last_ins = ins;
2295 ins = ins->next;
2297 bb->last_ins = last_ins;
2300 void
2301 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2303 switch (ins->opcode) {
2304 case OP_ICONV_TO_R_UN: {
2305 // This value is OK as-is for both big and little endian because of how it is stored
2306 static const guint64 adjust_val = 0x4330000000000000ULL;
2307 int msw_reg = mono_alloc_ireg (cfg);
2308 int adj_reg = mono_alloc_freg (cfg);
2309 int tmp_reg = mono_alloc_freg (cfg);
2310 int basereg = ppc_sp;
2311 int offset = -8;
2312 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2313 if (!ppc_is_imm16 (offset + 4)) {
2314 basereg = mono_alloc_ireg (cfg);
2315 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2317 #if G_BYTE_ORDER == G_BIG_ENDIAN
2318 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2319 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2320 #else
2321 // For little endian the words are reversed
2322 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2323 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2324 #endif
2325 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2326 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2327 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2328 ins->opcode = OP_NOP;
2329 break;
2331 #ifndef __mono_ppc64__
2332 case OP_ICONV_TO_R4:
2333 case OP_ICONV_TO_R8: {
2334 /* If we have a PPC_FEATURE_64 machine we can avoid
2335 this and use the fcfid instruction. Otherwise
2336 on an old 32-bit chip and we have to do this the
2337 hard way. */
2338 if (!(cpu_hw_caps & PPC_ISA_64)) {
2339 /* FIXME: change precision for CEE_CONV_R4 */
2340 static const guint64 adjust_val = 0x4330000080000000ULL;
2341 int msw_reg = mono_alloc_ireg (cfg);
2342 int xored = mono_alloc_ireg (cfg);
2343 int adj_reg = mono_alloc_freg (cfg);
2344 int tmp_reg = mono_alloc_freg (cfg);
2345 int basereg = ppc_sp;
2346 int offset = -8;
2347 if (!ppc_is_imm16 (offset + 4)) {
2348 basereg = mono_alloc_ireg (cfg);
2349 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2351 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2352 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2353 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2354 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2355 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2356 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2357 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2358 if (ins->opcode == OP_ICONV_TO_R4)
2359 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2360 ins->opcode = OP_NOP;
2362 break;
2364 #endif
2365 case OP_CKFINITE: {
2366 int msw_reg = mono_alloc_ireg (cfg);
2367 int basereg = ppc_sp;
2368 int offset = -8;
2369 if (!ppc_is_imm16 (offset + 4)) {
2370 basereg = mono_alloc_ireg (cfg);
2371 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2373 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2374 #if G_BYTE_ORDER == G_BIG_ENDIAN
2375 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2376 #else
2377 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2378 #endif
2379 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2380 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2381 ins->opcode = OP_NOP;
2382 break;
2384 #ifdef __mono_ppc64__
2385 case OP_IADD_OVF:
2386 case OP_IADD_OVF_UN:
2387 case OP_ISUB_OVF: {
2388 int shifted1_reg = mono_alloc_ireg (cfg);
2389 int shifted2_reg = mono_alloc_ireg (cfg);
2390 int result_shifted_reg = mono_alloc_ireg (cfg);
2392 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2393 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2394 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2395 if (ins->opcode == OP_IADD_OVF_UN)
2396 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2397 else
2398 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2399 ins->opcode = OP_NOP;
2400 break;
2402 #endif
2403 default:
2404 break;
2408 void
2409 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2411 switch (ins->opcode) {
2412 case OP_LADD_OVF:
2413 /* ADC sets the condition code */
2414 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2415 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2416 NULLIFY_INS (ins);
2417 break;
2418 case OP_LADD_OVF_UN:
2419 /* ADC sets the condition code */
2420 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2421 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));
2422 NULLIFY_INS (ins);
2423 break;
2424 case OP_LSUB_OVF:
2425 /* SBB sets the condition code */
2426 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2427 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2428 NULLIFY_INS (ins);
2429 break;
2430 case OP_LSUB_OVF_UN:
2431 /* SBB sets the condition code */
2432 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2433 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));
2434 NULLIFY_INS (ins);
2435 break;
2436 case OP_LNEG:
2437 /* From gcc generated code */
2438 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), 0);
2439 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1));
2440 NULLIFY_INS (ins);
2441 break;
2442 default:
2443 break;
2448 * the branch_b0_table should maintain the order of these
2449 * opcodes.
2450 case CEE_BEQ:
2451 case CEE_BGE:
2452 case CEE_BGT:
2453 case CEE_BLE:
2454 case CEE_BLT:
2455 case CEE_BNE_UN:
2456 case CEE_BGE_UN:
2457 case CEE_BGT_UN:
2458 case CEE_BLE_UN:
2459 case CEE_BLT_UN:
2461 static const guchar
2462 branch_b0_table [] = {
2463 PPC_BR_TRUE,
2464 PPC_BR_FALSE,
2465 PPC_BR_TRUE,
2466 PPC_BR_FALSE,
2467 PPC_BR_TRUE,
2469 PPC_BR_FALSE,
2470 PPC_BR_FALSE,
2471 PPC_BR_TRUE,
2472 PPC_BR_FALSE,
2473 PPC_BR_TRUE
2476 static const guchar
2477 branch_b1_table [] = {
2478 PPC_BR_EQ,
2479 PPC_BR_LT,
2480 PPC_BR_GT,
2481 PPC_BR_GT,
2482 PPC_BR_LT,
2484 PPC_BR_EQ,
2485 PPC_BR_LT,
2486 PPC_BR_GT,
2487 PPC_BR_GT,
2488 PPC_BR_LT
2491 #define NEW_INS(cfg,dest,op) do { \
2492 MONO_INST_NEW((cfg), (dest), (op)); \
2493 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2494 } while (0)
2496 static int
2497 map_to_reg_reg_op (int op)
2499 switch (op) {
2500 case OP_ADD_IMM:
2501 return OP_IADD;
2502 case OP_SUB_IMM:
2503 return OP_ISUB;
2504 case OP_AND_IMM:
2505 return OP_IAND;
2506 case OP_COMPARE_IMM:
2507 return OP_COMPARE;
2508 case OP_ICOMPARE_IMM:
2509 return OP_ICOMPARE;
2510 case OP_LCOMPARE_IMM:
2511 return OP_LCOMPARE;
2512 case OP_ADDCC_IMM:
2513 return OP_IADDCC;
2514 case OP_ADC_IMM:
2515 return OP_IADC;
2516 case OP_SUBCC_IMM:
2517 return OP_ISUBCC;
2518 case OP_SBB_IMM:
2519 return OP_ISBB;
2520 case OP_OR_IMM:
2521 return OP_IOR;
2522 case OP_XOR_IMM:
2523 return OP_IXOR;
2524 case OP_MUL_IMM:
2525 return OP_IMUL;
2526 case OP_LOAD_MEMBASE:
2527 return OP_LOAD_MEMINDEX;
2528 case OP_LOADI4_MEMBASE:
2529 return OP_LOADI4_MEMINDEX;
2530 case OP_LOADU4_MEMBASE:
2531 return OP_LOADU4_MEMINDEX;
2532 case OP_LOADI8_MEMBASE:
2533 return OP_LOADI8_MEMINDEX;
2534 case OP_LOADU1_MEMBASE:
2535 return OP_LOADU1_MEMINDEX;
2536 case OP_LOADI2_MEMBASE:
2537 return OP_LOADI2_MEMINDEX;
2538 case OP_LOADU2_MEMBASE:
2539 return OP_LOADU2_MEMINDEX;
2540 case OP_LOADI1_MEMBASE:
2541 return OP_LOADI1_MEMINDEX;
2542 case OP_LOADR4_MEMBASE:
2543 return OP_LOADR4_MEMINDEX;
2544 case OP_LOADR8_MEMBASE:
2545 return OP_LOADR8_MEMINDEX;
2546 case OP_STOREI1_MEMBASE_REG:
2547 return OP_STOREI1_MEMINDEX;
2548 case OP_STOREI2_MEMBASE_REG:
2549 return OP_STOREI2_MEMINDEX;
2550 case OP_STOREI4_MEMBASE_REG:
2551 return OP_STOREI4_MEMINDEX;
2552 case OP_STOREI8_MEMBASE_REG:
2553 return OP_STOREI8_MEMINDEX;
2554 case OP_STORE_MEMBASE_REG:
2555 return OP_STORE_MEMINDEX;
2556 case OP_STORER4_MEMBASE_REG:
2557 return OP_STORER4_MEMINDEX;
2558 case OP_STORER8_MEMBASE_REG:
2559 return OP_STORER8_MEMINDEX;
2560 case OP_STORE_MEMBASE_IMM:
2561 return OP_STORE_MEMBASE_REG;
2562 case OP_STOREI1_MEMBASE_IMM:
2563 return OP_STOREI1_MEMBASE_REG;
2564 case OP_STOREI2_MEMBASE_IMM:
2565 return OP_STOREI2_MEMBASE_REG;
2566 case OP_STOREI4_MEMBASE_IMM:
2567 return OP_STOREI4_MEMBASE_REG;
2568 case OP_STOREI8_MEMBASE_IMM:
2569 return OP_STOREI8_MEMBASE_REG;
2571 if (mono_op_imm_to_op (op) == -1)
2572 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2573 return mono_op_imm_to_op (op);
2576 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2578 #define compare_opcode_is_unsigned(opcode) \
2579 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2580 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2581 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2582 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2583 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2584 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2585 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2586 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2589 * Remove from the instruction list the instructions that can't be
2590 * represented with very simple instructions with no register
2591 * requirements.
2593 void
2594 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2596 MonoInst *ins, *next, *temp, *last_ins = NULL;
2597 int imm;
2599 MONO_BB_FOR_EACH_INS (bb, ins) {
2600 loop_start:
2601 switch (ins->opcode) {
2602 case OP_IDIV_UN_IMM:
2603 case OP_IDIV_IMM:
2604 case OP_IREM_IMM:
2605 case OP_IREM_UN_IMM:
2606 CASE_PPC64 (OP_LREM_IMM) {
2607 NEW_INS (cfg, temp, OP_ICONST);
2608 temp->inst_c0 = ins->inst_imm;
2609 temp->dreg = mono_alloc_ireg (cfg);
2610 ins->sreg2 = temp->dreg;
2611 if (ins->opcode == OP_IDIV_IMM)
2612 ins->opcode = OP_IDIV;
2613 else if (ins->opcode == OP_IREM_IMM)
2614 ins->opcode = OP_IREM;
2615 else if (ins->opcode == OP_IDIV_UN_IMM)
2616 ins->opcode = OP_IDIV_UN;
2617 else if (ins->opcode == OP_IREM_UN_IMM)
2618 ins->opcode = OP_IREM_UN;
2619 else if (ins->opcode == OP_LREM_IMM)
2620 ins->opcode = OP_LREM;
2621 last_ins = temp;
2622 /* handle rem separately */
2623 goto loop_start;
2625 case OP_IREM:
2626 case OP_IREM_UN:
2627 CASE_PPC64 (OP_LREM)
2628 CASE_PPC64 (OP_LREM_UN) {
2629 MonoInst *mul;
2630 /* we change a rem dest, src1, src2 to
2631 * div temp1, src1, src2
2632 * mul temp2, temp1, src2
2633 * sub dest, src1, temp2
2635 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2636 NEW_INS (cfg, mul, OP_IMUL);
2637 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2638 ins->opcode = OP_ISUB;
2639 } else {
2640 NEW_INS (cfg, mul, OP_LMUL);
2641 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2642 ins->opcode = OP_LSUB;
2644 temp->sreg1 = ins->sreg1;
2645 temp->sreg2 = ins->sreg2;
2646 temp->dreg = mono_alloc_ireg (cfg);
2647 mul->sreg1 = temp->dreg;
2648 mul->sreg2 = ins->sreg2;
2649 mul->dreg = mono_alloc_ireg (cfg);
2650 ins->sreg2 = mul->dreg;
2651 break;
2653 case OP_IADD_IMM:
2654 CASE_PPC64 (OP_LADD_IMM)
2655 case OP_ADD_IMM:
2656 case OP_ADDCC_IMM:
2657 if (!ppc_is_imm16 (ins->inst_imm)) {
2658 NEW_INS (cfg, temp, OP_ICONST);
2659 temp->inst_c0 = ins->inst_imm;
2660 temp->dreg = mono_alloc_ireg (cfg);
2661 ins->sreg2 = temp->dreg;
2662 ins->opcode = map_to_reg_reg_op (ins->opcode);
2664 break;
2665 case OP_ISUB_IMM:
2666 CASE_PPC64 (OP_LSUB_IMM)
2667 case OP_SUB_IMM:
2668 if (!ppc_is_imm16 (-ins->inst_imm)) {
2669 NEW_INS (cfg, temp, OP_ICONST);
2670 temp->inst_c0 = ins->inst_imm;
2671 temp->dreg = mono_alloc_ireg (cfg);
2672 ins->sreg2 = temp->dreg;
2673 ins->opcode = map_to_reg_reg_op (ins->opcode);
2675 break;
2676 case OP_IAND_IMM:
2677 case OP_IOR_IMM:
2678 case OP_IXOR_IMM:
2679 case OP_LAND_IMM:
2680 case OP_LOR_IMM:
2681 case OP_LXOR_IMM:
2682 case OP_AND_IMM:
2683 case OP_OR_IMM:
2684 case OP_XOR_IMM: {
2685 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2686 #ifdef __mono_ppc64__
2687 if (ins->inst_imm & 0xffffffff00000000ULL)
2688 is_imm = TRUE;
2689 #endif
2690 if (is_imm) {
2691 NEW_INS (cfg, temp, OP_ICONST);
2692 temp->inst_c0 = ins->inst_imm;
2693 temp->dreg = mono_alloc_ireg (cfg);
2694 ins->sreg2 = temp->dreg;
2695 ins->opcode = map_to_reg_reg_op (ins->opcode);
2697 break;
2699 case OP_ISBB_IMM:
2700 case OP_IADC_IMM:
2701 case OP_SBB_IMM:
2702 case OP_SUBCC_IMM:
2703 case OP_ADC_IMM:
2704 NEW_INS (cfg, temp, OP_ICONST);
2705 temp->inst_c0 = ins->inst_imm;
2706 temp->dreg = mono_alloc_ireg (cfg);
2707 ins->sreg2 = temp->dreg;
2708 ins->opcode = map_to_reg_reg_op (ins->opcode);
2709 break;
2710 case OP_COMPARE_IMM:
2711 case OP_ICOMPARE_IMM:
2712 CASE_PPC64 (OP_LCOMPARE_IMM)
2713 next = ins->next;
2714 /* Branch opts can eliminate the branch */
2715 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2716 ins->opcode = OP_NOP;
2717 break;
2719 g_assert(next);
2720 if (compare_opcode_is_unsigned (next->opcode)) {
2721 if (!ppc_is_uimm16 (ins->inst_imm)) {
2722 NEW_INS (cfg, temp, OP_ICONST);
2723 temp->inst_c0 = ins->inst_imm;
2724 temp->dreg = mono_alloc_ireg (cfg);
2725 ins->sreg2 = temp->dreg;
2726 ins->opcode = map_to_reg_reg_op (ins->opcode);
2728 } else {
2729 if (!ppc_is_imm16 (ins->inst_imm)) {
2730 NEW_INS (cfg, temp, OP_ICONST);
2731 temp->inst_c0 = ins->inst_imm;
2732 temp->dreg = mono_alloc_ireg (cfg);
2733 ins->sreg2 = temp->dreg;
2734 ins->opcode = map_to_reg_reg_op (ins->opcode);
2737 break;
2738 case OP_IMUL_IMM:
2739 case OP_MUL_IMM:
2740 if (ins->inst_imm == 1) {
2741 ins->opcode = OP_MOVE;
2742 break;
2744 if (ins->inst_imm == 0) {
2745 ins->opcode = OP_ICONST;
2746 ins->inst_c0 = 0;
2747 break;
2749 imm = mono_is_power_of_two (ins->inst_imm);
2750 if (imm > 0) {
2751 ins->opcode = OP_SHL_IMM;
2752 ins->inst_imm = imm;
2753 break;
2755 if (!ppc_is_imm16 (ins->inst_imm)) {
2756 NEW_INS (cfg, temp, OP_ICONST);
2757 temp->inst_c0 = ins->inst_imm;
2758 temp->dreg = mono_alloc_ireg (cfg);
2759 ins->sreg2 = temp->dreg;
2760 ins->opcode = map_to_reg_reg_op (ins->opcode);
2762 break;
2763 case OP_LOCALLOC_IMM:
2764 NEW_INS (cfg, temp, OP_ICONST);
2765 temp->inst_c0 = ins->inst_imm;
2766 temp->dreg = mono_alloc_ireg (cfg);
2767 ins->sreg1 = temp->dreg;
2768 ins->opcode = OP_LOCALLOC;
2769 break;
2770 case OP_LOAD_MEMBASE:
2771 case OP_LOADI4_MEMBASE:
2772 CASE_PPC64 (OP_LOADI8_MEMBASE)
2773 case OP_LOADU4_MEMBASE:
2774 case OP_LOADI2_MEMBASE:
2775 case OP_LOADU2_MEMBASE:
2776 case OP_LOADI1_MEMBASE:
2777 case OP_LOADU1_MEMBASE:
2778 case OP_LOADR4_MEMBASE:
2779 case OP_LOADR8_MEMBASE:
2780 case OP_STORE_MEMBASE_REG:
2781 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2782 case OP_STOREI4_MEMBASE_REG:
2783 case OP_STOREI2_MEMBASE_REG:
2784 case OP_STOREI1_MEMBASE_REG:
2785 case OP_STORER4_MEMBASE_REG:
2786 case OP_STORER8_MEMBASE_REG:
2787 /* we can do two things: load the immed in a register
2788 * and use an indexed load, or see if the immed can be
2789 * represented as an ad_imm + a load with a smaller offset
2790 * that fits. We just do the first for now, optimize later.
2792 if (ppc_is_imm16 (ins->inst_offset))
2793 break;
2794 NEW_INS (cfg, temp, OP_ICONST);
2795 temp->inst_c0 = ins->inst_offset;
2796 temp->dreg = mono_alloc_ireg (cfg);
2797 ins->sreg2 = temp->dreg;
2798 ins->opcode = map_to_reg_reg_op (ins->opcode);
2799 break;
2800 case OP_STORE_MEMBASE_IMM:
2801 case OP_STOREI1_MEMBASE_IMM:
2802 case OP_STOREI2_MEMBASE_IMM:
2803 case OP_STOREI4_MEMBASE_IMM:
2804 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2805 NEW_INS (cfg, temp, OP_ICONST);
2806 temp->inst_c0 = ins->inst_imm;
2807 temp->dreg = mono_alloc_ireg (cfg);
2808 ins->sreg1 = temp->dreg;
2809 ins->opcode = map_to_reg_reg_op (ins->opcode);
2810 last_ins = temp;
2811 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2812 case OP_R8CONST:
2813 case OP_R4CONST:
2814 if (cfg->compile_aot) {
2815 /* Keep these in the aot case */
2816 break;
2818 NEW_INS (cfg, temp, OP_ICONST);
2819 temp->inst_c0 = (gulong)ins->inst_p0;
2820 temp->dreg = mono_alloc_ireg (cfg);
2821 ins->inst_basereg = temp->dreg;
2822 ins->inst_offset = 0;
2823 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2824 last_ins = temp;
2825 /* make it handle the possibly big ins->inst_offset
2826 * later optimize to use lis + load_membase
2828 goto loop_start;
2830 last_ins = ins;
2832 bb->last_ins = last_ins;
2833 bb->max_vreg = cfg->next_vreg;
2836 static guchar*
2837 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2839 long offset = cfg->arch.fp_conv_var_offset;
2840 long sub_offset;
2841 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2842 #ifdef __mono_ppc64__
2843 if (size == 8) {
2844 ppc_fctidz (code, ppc_f0, sreg);
2845 sub_offset = 0;
2846 } else
2847 #endif
2849 ppc_fctiwz (code, ppc_f0, sreg);
2850 sub_offset = 4;
2852 if (ppc_is_imm16 (offset + sub_offset)) {
2853 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2854 if (size == 8)
2855 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2856 else
2857 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2858 } else {
2859 ppc_load (code, dreg, offset);
2860 ppc_add (code, dreg, dreg, cfg->frame_reg);
2861 ppc_stfd (code, ppc_f0, 0, dreg);
2862 if (size == 8)
2863 ppc_ldr (code, dreg, sub_offset, dreg);
2864 else
2865 ppc_lwz (code, dreg, sub_offset, dreg);
2867 if (!is_signed) {
2868 if (size == 1)
2869 ppc_andid (code, dreg, dreg, 0xff);
2870 else if (size == 2)
2871 ppc_andid (code, dreg, dreg, 0xffff);
2872 #ifdef __mono_ppc64__
2873 else if (size == 4)
2874 ppc_clrldi (code, dreg, dreg, 32);
2875 #endif
2876 } else {
2877 if (size == 1)
2878 ppc_extsb (code, dreg, dreg);
2879 else if (size == 2)
2880 ppc_extsh (code, dreg, dreg);
2881 #ifdef __mono_ppc64__
2882 else if (size == 4)
2883 ppc_extsw (code, dreg, dreg);
2884 #endif
2886 return code;
2889 typedef struct {
2890 guchar *code;
2891 const guchar *target;
2892 int absolute;
2893 int found;
2894 } PatchData;
2896 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2898 static int
2899 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2900 #ifdef __mono_ppc64__
2901 g_assert_not_reached ();
2902 #else
2903 PatchData *pdata = (PatchData*)user_data;
2904 guchar *code = data;
2905 guint32 *thunks = data;
2906 guint32 *endthunks = (guint32*)(code + bsize);
2907 guint32 load [2];
2908 guchar *templ;
2909 int count = 0;
2910 int difflow, diffhigh;
2912 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2913 difflow = (char*)pdata->code - (char*)thunks;
2914 diffhigh = (char*)pdata->code - (char*)endthunks;
2915 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2916 return 0;
2918 templ = (guchar*)load;
2919 ppc_load_sequence (templ, ppc_r0, pdata->target);
2921 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2922 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2923 while (thunks < endthunks) {
2924 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2925 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2926 ppc_patch (pdata->code, (guchar*)thunks);
2927 pdata->found = 1;
2929 static int num_thunks = 0;
2930 num_thunks++;
2931 if ((num_thunks % 20) == 0)
2932 g_print ("num_thunks lookup: %d\n", num_thunks);
2934 return 1;
2935 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2936 /* found a free slot instead: emit thunk */
2937 code = (guchar*)thunks;
2938 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2939 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2940 ppc_mtctr (code, ppc_r0);
2941 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2942 mono_arch_flush_icache ((guchar*)thunks, 16);
2944 ppc_patch (pdata->code, (guchar*)thunks);
2945 pdata->found = 1;
2947 static int num_thunks = 0;
2948 num_thunks++;
2949 if ((num_thunks % 20) == 0)
2950 g_print ("num_thunks: %d\n", num_thunks);
2952 return 1;
2954 /* skip 16 bytes, the size of the thunk */
2955 thunks += 4;
2956 count++;
2958 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2960 #endif
2961 return 0;
2964 static void
2965 handle_thunk (int absolute, guchar *code, const guchar *target) {
2966 MonoDomain *domain = mono_domain_get ();
2967 PatchData pdata;
2969 pdata.code = code;
2970 pdata.target = target;
2971 pdata.absolute = absolute;
2972 pdata.found = 0;
2974 mono_domain_lock (domain);
2975 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2977 if (!pdata.found) {
2978 /* this uses the first available slot */
2979 pdata.found = 2;
2980 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2982 mono_domain_unlock (domain);
2984 if (pdata.found != 1)
2985 g_print ("thunk failed for %p from %p\n", target, code);
2986 g_assert (pdata.found == 1);
2989 static void
2990 patch_ins (guint8 *code, guint32 ins)
2992 *(guint32*)code = ins;
2993 mono_arch_flush_icache (code, 4);
2996 void
2997 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2999 guint32 ins = *(guint32*)code;
3000 guint32 prim = ins >> 26;
3001 guint32 ovf;
3003 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
3004 if (prim == 18) {
3005 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
3006 gint diff = target - code;
3007 g_assert (!is_fd);
3008 if (diff >= 0){
3009 if (diff <= 33554431){
3010 ins = (18 << 26) | (diff) | (ins & 1);
3011 patch_ins (code, ins);
3012 return;
3014 } else {
3015 /* diff between 0 and -33554432 */
3016 if (diff >= -33554432){
3017 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
3018 patch_ins (code, ins);
3019 return;
3023 if ((glong)target >= 0){
3024 if ((glong)target <= 33554431){
3025 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
3026 patch_ins (code, ins);
3027 return;
3029 } else {
3030 if ((glong)target >= -33554432){
3031 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
3032 patch_ins (code, ins);
3033 return;
3037 handle_thunk (TRUE, code, target);
3038 return;
3040 g_assert_not_reached ();
3044 if (prim == 16) {
3045 g_assert (!is_fd);
3046 // absolute address
3047 if (ins & 2) {
3048 guint32 li = (gulong)target;
3049 ins = (ins & 0xffff0000) | (ins & 3);
3050 ovf = li & 0xffff0000;
3051 if (ovf != 0 && ovf != 0xffff0000)
3052 g_assert_not_reached ();
3053 li &= 0xffff;
3054 ins |= li;
3055 // FIXME: assert the top bits of li are 0
3056 } else {
3057 gint diff = target - code;
3058 ins = (ins & 0xffff0000) | (ins & 3);
3059 ovf = diff & 0xffff0000;
3060 if (ovf != 0 && ovf != 0xffff0000)
3061 g_assert_not_reached ();
3062 diff &= 0xffff;
3063 ins |= diff;
3065 patch_ins (code, ins);
3066 return;
3069 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3070 #ifdef __mono_ppc64__
3071 guint32 *seq = (guint32*)code;
3072 guint32 *branch_ins;
3074 /* the trampoline code will try to patch the blrl, blr, bcctr */
3075 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3076 branch_ins = seq;
3077 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
3078 code -= 32;
3079 else
3080 code -= 24;
3081 } else {
3082 if (ppc_is_load_op (seq [5])
3083 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3084 /* With function descs we need to do more careful
3085 matches. */
3086 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
3087 #endif
3089 branch_ins = seq + 8;
3090 else
3091 branch_ins = seq + 6;
3094 seq = (guint32*)code;
3095 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
3096 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
3098 if (ppc_is_load_op (seq [5])) {
3099 g_assert (ppc_is_load_op (seq [6]));
3101 if (!is_fd) {
3102 guint8 *buf = (guint8*)&seq [5];
3103 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
3104 ppc_nop (buf);
3106 } else {
3107 if (is_fd)
3108 target = mono_get_addr_from_ftnptr ((gpointer)target);
3111 /* FIXME: make this thread safe */
3112 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3113 /* FIXME: we're assuming we're using r12 here */
3114 ppc_load_ptr_sequence (code, ppc_r12, target);
3115 #else
3116 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
3117 #endif
3118 mono_arch_flush_icache ((guint8*)seq, 28);
3119 #else
3120 guint32 *seq;
3121 /* the trampoline code will try to patch the blrl, blr, bcctr */
3122 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3123 code -= 12;
3125 /* this is the lis/ori/mtlr/blrl sequence */
3126 seq = (guint32*)code;
3127 g_assert ((seq [0] >> 26) == 15);
3128 g_assert ((seq [1] >> 26) == 24);
3129 g_assert ((seq [2] >> 26) == 31);
3130 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
3131 /* FIXME: make this thread safe */
3132 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
3133 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
3134 mono_arch_flush_icache (code - 8, 8);
3135 #endif
3136 } else {
3137 g_assert_not_reached ();
3139 // g_print ("patched with 0x%08x\n", ins);
3142 void
3143 ppc_patch (guchar *code, const guchar *target)
3145 ppc_patch_full (code, target, FALSE);
3148 void
3149 mono_ppc_patch (guchar *code, const guchar *target)
3151 ppc_patch (code, target);
3154 static guint8*
3155 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3157 switch (ins->opcode) {
3158 case OP_FCALL:
3159 case OP_FCALL_REG:
3160 case OP_FCALL_MEMBASE:
3161 if (ins->dreg != ppc_f1)
3162 ppc_fmr (code, ins->dreg, ppc_f1);
3163 break;
3166 return code;
3169 static int
3170 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3172 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3175 static guint8*
3176 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3178 long size = cfg->param_area;
3180 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3181 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3183 if (!size)
3184 return code;
3186 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3187 if (ppc_is_imm16 (-size)) {
3188 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3189 } else {
3190 ppc_load (code, ppc_r12, -size);
3191 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3194 return code;
3197 static guint8*
3198 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3200 long size = cfg->param_area;
3202 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3203 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3205 if (!size)
3206 return code;
3208 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3209 if (ppc_is_imm16 (size)) {
3210 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3211 } else {
3212 ppc_load (code, ppc_r12, size);
3213 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3216 return code;
3219 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3221 #ifndef DISABLE_JIT
3222 void
3223 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3225 MonoInst *ins, *next;
3226 MonoCallInst *call;
3227 guint offset;
3228 guint8 *code = cfg->native_code + cfg->code_len;
3229 MonoInst *last_ins = NULL;
3230 guint last_offset = 0;
3231 int max_len, cpos;
3232 int L;
3234 /* we don't align basic blocks of loops on ppc */
3236 if (cfg->verbose_level > 2)
3237 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3239 cpos = bb->max_offset;
3241 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3242 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3243 //g_assert (!mono_compile_aot);
3244 //cpos += 6;
3245 //if (bb->cil_code)
3246 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3247 /* this is not thread save, but good enough */
3248 /* fixme: howto handle overflows? */
3249 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3252 MONO_BB_FOR_EACH_INS (bb, ins) {
3253 offset = code - cfg->native_code;
3255 max_len = ins_native_length (cfg, ins);
3257 if (offset > (cfg->code_size - max_len - 16)) {
3258 cfg->code_size *= 2;
3259 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3260 code = cfg->native_code + offset;
3262 // if (ins->cil_code)
3263 // g_print ("cil code\n");
3264 mono_debug_record_line_number (cfg, ins, offset);
3266 switch (normalize_opcode (ins->opcode)) {
3267 case OP_RELAXED_NOP:
3268 case OP_NOP:
3269 case OP_DUMMY_USE:
3270 case OP_DUMMY_STORE:
3271 case OP_NOT_REACHED:
3272 case OP_NOT_NULL:
3273 break;
3274 case OP_IL_SEQ_POINT:
3275 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3276 break;
3277 case OP_SEQ_POINT: {
3278 int i;
3280 if (cfg->compile_aot)
3281 NOT_IMPLEMENTED;
3284 * Read from the single stepping trigger page. This will cause a
3285 * SIGSEGV when single stepping is enabled.
3286 * We do this _before_ the breakpoint, so single stepping after
3287 * a breakpoint is hit will step to the next IL offset.
3289 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3290 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3291 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3294 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3297 * A placeholder for a possible breakpoint inserted by
3298 * mono_arch_set_breakpoint ().
3300 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3301 ppc_nop (code);
3302 break;
3304 case OP_TLS_GET:
3305 emit_tls_access (code, ins->dreg, ins->inst_offset);
3306 break;
3307 case OP_BIGMUL:
3308 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3309 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3310 ppc_mr (code, ppc_r4, ppc_r0);
3311 break;
3312 case OP_BIGMUL_UN:
3313 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3314 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3315 ppc_mr (code, ppc_r4, ppc_r0);
3316 break;
3317 case OP_MEMORY_BARRIER:
3318 ppc_sync (code);
3319 break;
3320 case OP_STOREI1_MEMBASE_REG:
3321 if (ppc_is_imm16 (ins->inst_offset)) {
3322 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3323 } else {
3324 if (ppc_is_imm32 (ins->inst_offset)) {
3325 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3326 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3327 } else {
3328 ppc_load (code, ppc_r0, ins->inst_offset);
3329 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3332 break;
3333 case OP_STOREI2_MEMBASE_REG:
3334 if (ppc_is_imm16 (ins->inst_offset)) {
3335 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3336 } else {
3337 if (ppc_is_imm32 (ins->inst_offset)) {
3338 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3339 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3340 } else {
3341 ppc_load (code, ppc_r0, ins->inst_offset);
3342 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3345 break;
3346 case OP_STORE_MEMBASE_REG:
3347 if (ppc_is_imm16 (ins->inst_offset)) {
3348 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3349 } else {
3350 if (ppc_is_imm32 (ins->inst_offset)) {
3351 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3352 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3353 } else {
3354 ppc_load (code, ppc_r0, ins->inst_offset);
3355 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3358 break;
3359 #ifdef __mono_ilp32__
3360 case OP_STOREI8_MEMBASE_REG:
3361 if (ppc_is_imm16 (ins->inst_offset)) {
3362 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3363 } else {
3364 ppc_load (code, ppc_r0, ins->inst_offset);
3365 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3367 break;
3368 #endif
3369 case OP_STOREI1_MEMINDEX:
3370 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3371 break;
3372 case OP_STOREI2_MEMINDEX:
3373 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3374 break;
3375 case OP_STORE_MEMINDEX:
3376 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3377 break;
3378 case OP_LOADU4_MEM:
3379 g_assert_not_reached ();
3380 break;
3381 case OP_LOAD_MEMBASE:
3382 if (ppc_is_imm16 (ins->inst_offset)) {
3383 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3384 } else {
3385 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3386 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3387 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3388 } else {
3389 ppc_load (code, ppc_r0, ins->inst_offset);
3390 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3393 break;
3394 case OP_LOADI4_MEMBASE:
3395 #ifdef __mono_ppc64__
3396 if (ppc_is_imm16 (ins->inst_offset)) {
3397 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3398 } else {
3399 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3400 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3401 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3402 } else {
3403 ppc_load (code, ppc_r0, ins->inst_offset);
3404 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3407 break;
3408 #endif
3409 case OP_LOADU4_MEMBASE:
3410 if (ppc_is_imm16 (ins->inst_offset)) {
3411 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3412 } else {
3413 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3414 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3415 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3416 } else {
3417 ppc_load (code, ppc_r0, ins->inst_offset);
3418 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3421 break;
3422 case OP_LOADI1_MEMBASE:
3423 case OP_LOADU1_MEMBASE:
3424 if (ppc_is_imm16 (ins->inst_offset)) {
3425 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3426 } else {
3427 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3428 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3429 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3430 } else {
3431 ppc_load (code, ppc_r0, ins->inst_offset);
3432 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3435 if (ins->opcode == OP_LOADI1_MEMBASE)
3436 ppc_extsb (code, ins->dreg, ins->dreg);
3437 break;
3438 case OP_LOADU2_MEMBASE:
3439 if (ppc_is_imm16 (ins->inst_offset)) {
3440 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3441 } else {
3442 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3443 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3444 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3445 } else {
3446 ppc_load (code, ppc_r0, ins->inst_offset);
3447 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3450 break;
3451 case OP_LOADI2_MEMBASE:
3452 if (ppc_is_imm16 (ins->inst_offset)) {
3453 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3454 } else {
3455 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3456 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3457 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3458 } else {
3459 ppc_load (code, ppc_r0, ins->inst_offset);
3460 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3463 break;
3464 #ifdef __mono_ilp32__
3465 case OP_LOADI8_MEMBASE:
3466 if (ppc_is_imm16 (ins->inst_offset)) {
3467 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3468 } else {
3469 ppc_load (code, ppc_r0, ins->inst_offset);
3470 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3472 break;
3473 #endif
3474 case OP_LOAD_MEMINDEX:
3475 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3476 break;
3477 case OP_LOADI4_MEMINDEX:
3478 #ifdef __mono_ppc64__
3479 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3480 break;
3481 #endif
3482 case OP_LOADU4_MEMINDEX:
3483 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3484 break;
3485 case OP_LOADU2_MEMINDEX:
3486 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3487 break;
3488 case OP_LOADI2_MEMINDEX:
3489 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3490 break;
3491 case OP_LOADU1_MEMINDEX:
3492 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3493 break;
3494 case OP_LOADI1_MEMINDEX:
3495 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3496 ppc_extsb (code, ins->dreg, ins->dreg);
3497 break;
3498 case OP_ICONV_TO_I1:
3499 CASE_PPC64 (OP_LCONV_TO_I1)
3500 ppc_extsb (code, ins->dreg, ins->sreg1);
3501 break;
3502 case OP_ICONV_TO_I2:
3503 CASE_PPC64 (OP_LCONV_TO_I2)
3504 ppc_extsh (code, ins->dreg, ins->sreg1);
3505 break;
3506 case OP_ICONV_TO_U1:
3507 CASE_PPC64 (OP_LCONV_TO_U1)
3508 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3509 break;
3510 case OP_ICONV_TO_U2:
3511 CASE_PPC64 (OP_LCONV_TO_U2)
3512 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3513 break;
3514 case OP_COMPARE:
3515 case OP_ICOMPARE:
3516 CASE_PPC64 (OP_LCOMPARE)
3517 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3518 next = ins->next;
3519 if (next && compare_opcode_is_unsigned (next->opcode))
3520 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3521 else
3522 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3523 break;
3524 case OP_COMPARE_IMM:
3525 case OP_ICOMPARE_IMM:
3526 CASE_PPC64 (OP_LCOMPARE_IMM)
3527 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3528 next = ins->next;
3529 if (next && compare_opcode_is_unsigned (next->opcode)) {
3530 if (ppc_is_uimm16 (ins->inst_imm)) {
3531 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3532 } else {
3533 g_assert_not_reached ();
3535 } else {
3536 if (ppc_is_imm16 (ins->inst_imm)) {
3537 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3538 } else {
3539 g_assert_not_reached ();
3542 break;
3543 case OP_BREAK:
3545 * gdb does not like encountering a trap in the debugged code. So
3546 * instead of emitting a trap, we emit a call a C function and place a
3547 * breakpoint there.
3549 //ppc_break (code);
3550 ppc_mr (code, ppc_r3, ins->sreg1);
3551 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3552 (gpointer)"mono_break");
3553 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3554 ppc_load_func (code, PPC_CALL_REG, 0);
3555 ppc_mtlr (code, PPC_CALL_REG);
3556 ppc_blrl (code);
3557 } else {
3558 ppc_bl (code, 0);
3560 break;
3561 case OP_ADDCC:
3562 case OP_IADDCC:
3563 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3564 break;
3565 case OP_IADD:
3566 CASE_PPC64 (OP_LADD)
3567 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3568 break;
3569 case OP_ADC:
3570 case OP_IADC:
3571 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3572 break;
3573 case OP_ADDCC_IMM:
3574 if (ppc_is_imm16 (ins->inst_imm)) {
3575 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3576 } else {
3577 g_assert_not_reached ();
3579 break;
3580 case OP_ADD_IMM:
3581 case OP_IADD_IMM:
3582 CASE_PPC64 (OP_LADD_IMM)
3583 if (ppc_is_imm16 (ins->inst_imm)) {
3584 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3585 } else {
3586 g_assert_not_reached ();
3588 break;
3589 case OP_IADD_OVF:
3590 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3592 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3593 ppc_mfspr (code, ppc_r0, ppc_xer);
3594 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3595 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3596 break;
3597 case OP_IADD_OVF_UN:
3598 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3600 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3601 ppc_mfspr (code, ppc_r0, ppc_xer);
3602 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3603 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3604 break;
3605 case OP_ISUB_OVF:
3606 CASE_PPC64 (OP_LSUB_OVF)
3607 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3609 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3610 ppc_mfspr (code, ppc_r0, ppc_xer);
3611 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3612 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3613 break;
3614 case OP_ISUB_OVF_UN:
3615 CASE_PPC64 (OP_LSUB_OVF_UN)
3616 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3618 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3619 ppc_mfspr (code, ppc_r0, ppc_xer);
3620 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3621 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3622 break;
3623 case OP_ADD_OVF_CARRY:
3624 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3626 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3627 ppc_mfspr (code, ppc_r0, ppc_xer);
3628 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3629 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3630 break;
3631 case OP_ADD_OVF_UN_CARRY:
3632 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3634 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3635 ppc_mfspr (code, ppc_r0, ppc_xer);
3636 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3637 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3638 break;
3639 case OP_SUB_OVF_CARRY:
3640 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3642 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3643 ppc_mfspr (code, ppc_r0, ppc_xer);
3644 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3645 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3646 break;
3647 case OP_SUB_OVF_UN_CARRY:
3648 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3650 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3651 ppc_mfspr (code, ppc_r0, ppc_xer);
3652 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3653 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3654 break;
3655 case OP_SUBCC:
3656 case OP_ISUBCC:
3657 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3658 break;
3659 case OP_ISUB:
3660 CASE_PPC64 (OP_LSUB)
3661 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3662 break;
3663 case OP_SBB:
3664 case OP_ISBB:
3665 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3666 break;
3667 case OP_SUB_IMM:
3668 case OP_ISUB_IMM:
3669 CASE_PPC64 (OP_LSUB_IMM)
3670 // we add the negated value
3671 if (ppc_is_imm16 (-ins->inst_imm))
3672 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3673 else {
3674 g_assert_not_reached ();
3676 break;
3677 case OP_PPC_SUBFIC:
3678 g_assert (ppc_is_imm16 (ins->inst_imm));
3679 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3680 break;
3681 case OP_PPC_SUBFZE:
3682 ppc_subfze (code, ins->dreg, ins->sreg1);
3683 break;
3684 case OP_IAND:
3685 CASE_PPC64 (OP_LAND)
3686 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3687 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3688 break;
3689 case OP_AND_IMM:
3690 case OP_IAND_IMM:
3691 CASE_PPC64 (OP_LAND_IMM)
3692 if (!(ins->inst_imm & 0xffff0000)) {
3693 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3694 } else if (!(ins->inst_imm & 0xffff)) {
3695 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3696 } else {
3697 g_assert_not_reached ();
3699 break;
3700 case OP_IDIV:
3701 CASE_PPC64 (OP_LDIV) {
3702 guint8 *divisor_is_m1;
3703 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3705 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3706 divisor_is_m1 = code;
3707 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3708 ppc_lis (code, ppc_r0, 0x8000);
3709 #ifdef __mono_ppc64__
3710 if (ins->opcode == OP_LDIV)
3711 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3712 #endif
3713 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3714 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3715 ppc_patch (divisor_is_m1, code);
3716 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3718 if (ins->opcode == OP_IDIV)
3719 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3720 #ifdef __mono_ppc64__
3721 else
3722 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3723 #endif
3724 ppc_mfspr (code, ppc_r0, ppc_xer);
3725 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3726 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3727 break;
3729 case OP_IDIV_UN:
3730 CASE_PPC64 (OP_LDIV_UN)
3731 if (ins->opcode == OP_IDIV_UN)
3732 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3733 #ifdef __mono_ppc64__
3734 else
3735 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3736 #endif
3737 ppc_mfspr (code, ppc_r0, ppc_xer);
3738 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3739 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3740 break;
3741 case OP_DIV_IMM:
3742 case OP_IREM:
3743 case OP_IREM_UN:
3744 case OP_REM_IMM:
3745 g_assert_not_reached ();
3746 case OP_IOR:
3747 CASE_PPC64 (OP_LOR)
3748 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3749 break;
3750 case OP_OR_IMM:
3751 case OP_IOR_IMM:
3752 CASE_PPC64 (OP_LOR_IMM)
3753 if (!(ins->inst_imm & 0xffff0000)) {
3754 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3755 } else if (!(ins->inst_imm & 0xffff)) {
3756 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3757 } else {
3758 g_assert_not_reached ();
3760 break;
3761 case OP_IXOR:
3762 CASE_PPC64 (OP_LXOR)
3763 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3764 break;
3765 case OP_IXOR_IMM:
3766 case OP_XOR_IMM:
3767 CASE_PPC64 (OP_LXOR_IMM)
3768 if (!(ins->inst_imm & 0xffff0000)) {
3769 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3770 } else if (!(ins->inst_imm & 0xffff)) {
3771 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3772 } else {
3773 g_assert_not_reached ();
3775 break;
3776 case OP_ISHL:
3777 CASE_PPC64 (OP_LSHL)
3778 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3779 break;
3780 case OP_SHL_IMM:
3781 case OP_ISHL_IMM:
3782 CASE_PPC64 (OP_LSHL_IMM)
3783 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3784 break;
3785 case OP_ISHR:
3786 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3787 break;
3788 case OP_SHR_IMM:
3789 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3790 break;
3791 case OP_SHR_UN_IMM:
3792 if (MASK_SHIFT_IMM (ins->inst_imm))
3793 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3794 else
3795 ppc_mr (code, ins->dreg, ins->sreg1);
3796 break;
3797 case OP_ISHR_UN:
3798 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3799 break;
3800 case OP_INOT:
3801 CASE_PPC64 (OP_LNOT)
3802 ppc_not (code, ins->dreg, ins->sreg1);
3803 break;
3804 case OP_INEG:
3805 CASE_PPC64 (OP_LNEG)
3806 ppc_neg (code, ins->dreg, ins->sreg1);
3807 break;
3808 case OP_IMUL:
3809 CASE_PPC64 (OP_LMUL)
3810 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3811 break;
3812 case OP_IMUL_IMM:
3813 case OP_MUL_IMM:
3814 CASE_PPC64 (OP_LMUL_IMM)
3815 if (ppc_is_imm16 (ins->inst_imm)) {
3816 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3817 } else {
3818 g_assert_not_reached ();
3820 break;
3821 case OP_IMUL_OVF:
3822 CASE_PPC64 (OP_LMUL_OVF)
3823 /* we annot use mcrxr, since it's not implemented on some processors
3824 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3826 if (ins->opcode == OP_IMUL_OVF)
3827 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3828 #ifdef __mono_ppc64__
3829 else
3830 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3831 #endif
3832 ppc_mfspr (code, ppc_r0, ppc_xer);
3833 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3834 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3835 break;
3836 case OP_IMUL_OVF_UN:
3837 CASE_PPC64 (OP_LMUL_OVF_UN)
3838 /* we first multiply to get the high word and compare to 0
3839 * to set the flags, then the result is discarded and then
3840 * we multiply to get the lower * bits result
3842 if (ins->opcode == OP_IMUL_OVF_UN)
3843 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3844 #ifdef __mono_ppc64__
3845 else
3846 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3847 #endif
3848 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3849 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3850 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3851 break;
3852 case OP_ICONST:
3853 ppc_load (code, ins->dreg, ins->inst_c0);
3854 break;
3855 case OP_I8CONST: {
3856 ppc_load (code, ins->dreg, ins->inst_l);
3857 break;
3859 case OP_LOAD_GOTADDR:
3860 /* The PLT implementation depends on this */
3861 g_assert (ins->dreg == ppc_r30);
3863 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3864 break;
3865 case OP_GOT_ENTRY:
3866 // FIXME: Fix max instruction length
3867 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3868 /* arch_emit_got_access () patches this */
3869 ppc_load32 (code, ppc_r0, 0);
3870 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3871 break;
3872 case OP_AOTCONST:
3873 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3874 ppc_load_sequence (code, ins->dreg, 0);
3875 break;
3876 CASE_PPC32 (OP_ICONV_TO_I4)
3877 CASE_PPC32 (OP_ICONV_TO_U4)
3878 case OP_MOVE:
3879 if (ins->dreg != ins->sreg1)
3880 ppc_mr (code, ins->dreg, ins->sreg1);
3881 break;
3882 case OP_SETLRET: {
3883 int saved = ins->sreg1;
3884 if (ins->sreg1 == ppc_r3) {
3885 ppc_mr (code, ppc_r0, ins->sreg1);
3886 saved = ppc_r0;
3888 if (ins->sreg2 != ppc_r3)
3889 ppc_mr (code, ppc_r3, ins->sreg2);
3890 if (saved != ppc_r4)
3891 ppc_mr (code, ppc_r4, saved);
3892 break;
3894 case OP_FMOVE:
3895 if (ins->dreg != ins->sreg1)
3896 ppc_fmr (code, ins->dreg, ins->sreg1);
3897 break;
3898 case OP_MOVE_F_TO_I4:
3899 ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3900 ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3901 break;
3902 case OP_MOVE_I4_TO_F:
3903 ppc_stw (code, ins->sreg1, -4, ppc_r1);
3904 ppc_lfs (code, ins->dreg, -4, ppc_r1);
3905 break;
3906 case OP_FCONV_TO_R4:
3907 ppc_frsp (code, ins->dreg, ins->sreg1);
3908 break;
3909 case OP_TAILCALL: {
3910 int i, pos;
3911 MonoCallInst *call = (MonoCallInst*)ins;
3914 * Keep in sync with mono_arch_emit_epilog
3916 g_assert (!cfg->method->save_lmf);
3918 * Note: we can use ppc_r12 here because it is dead anyway:
3919 * we're leaving the method.
3921 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3922 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3923 if (ppc_is_imm16 (ret_offset)) {
3924 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3925 } else {
3926 ppc_load (code, ppc_r12, ret_offset);
3927 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3929 ppc_mtlr (code, ppc_r0);
3932 if (ppc_is_imm16 (cfg->stack_usage)) {
3933 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3934 } else {
3935 /* cfg->stack_usage is an int, so we can use
3936 * an addis/addi sequence here even in 64-bit. */
3937 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3938 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3940 if (!cfg->method->save_lmf) {
3941 pos = 0;
3942 for (i = 31; i >= 13; --i) {
3943 if (cfg->used_int_regs & (1 << i)) {
3944 pos += sizeof (gpointer);
3945 ppc_ldptr (code, i, -pos, ppc_r12);
3948 } else {
3949 /* FIXME restore from MonoLMF: though this can't happen yet */
3952 /* Copy arguments on the stack to our argument area */
3953 if (call->stack_usage) {
3954 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3955 /* r12 was clobbered */
3956 g_assert (cfg->frame_reg == ppc_sp);
3957 if (ppc_is_imm16 (cfg->stack_usage)) {
3958 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3959 } else {
3960 /* cfg->stack_usage is an int, so we can use
3961 * an addis/addi sequence here even in 64-bit. */
3962 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3963 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3967 ppc_mr (code, ppc_sp, ppc_r12);
3968 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3969 if (cfg->compile_aot) {
3970 /* arch_emit_got_access () patches this */
3971 ppc_load32 (code, ppc_r0, 0);
3972 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3973 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3974 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3975 #else
3976 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3977 #endif
3978 ppc_mtctr (code, ppc_r0);
3979 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3980 } else {
3981 ppc_b (code, 0);
3983 break;
3985 case OP_CHECK_THIS:
3986 /* ensure ins->sreg1 is not NULL */
3987 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3988 break;
3989 case OP_ARGLIST: {
3990 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3991 if (ppc_is_imm16 (cookie_offset)) {
3992 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3993 } else {
3994 ppc_load (code, ppc_r0, cookie_offset);
3995 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3997 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3998 break;
4000 case OP_FCALL:
4001 case OP_LCALL:
4002 case OP_VCALL:
4003 case OP_VCALL2:
4004 case OP_VOIDCALL:
4005 case OP_CALL:
4006 call = (MonoCallInst*)ins;
4007 if (ins->flags & MONO_INST_HAS_METHOD)
4008 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4009 else
4010 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4011 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4012 ppc_load_func (code, PPC_CALL_REG, 0);
4013 ppc_mtlr (code, PPC_CALL_REG);
4014 ppc_blrl (code);
4015 } else {
4016 ppc_bl (code, 0);
4018 /* FIXME: this should be handled somewhere else in the new jit */
4019 code = emit_move_return_value (cfg, ins, code);
4020 break;
4021 case OP_FCALL_REG:
4022 case OP_LCALL_REG:
4023 case OP_VCALL_REG:
4024 case OP_VCALL2_REG:
4025 case OP_VOIDCALL_REG:
4026 case OP_CALL_REG:
4027 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4028 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4029 /* FIXME: if we know that this is a method, we
4030 can omit this load */
4031 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4032 ppc_mtlr (code, ppc_r0);
4033 #else
4034 #if (_CALL_ELF == 2)
4035 if (ins->flags & MONO_INST_HAS_METHOD) {
4036 // Not a global entry point
4037 } else {
4038 // Need to set up r12 with function entry address for global entry point
4039 if (ppc_r12 != ins->sreg1) {
4040 ppc_mr(code,ppc_r12,ins->sreg1);
4043 #endif
4044 ppc_mtlr (code, ins->sreg1);
4045 #endif
4046 ppc_blrl (code);
4047 /* FIXME: this should be handled somewhere else in the new jit */
4048 code = emit_move_return_value (cfg, ins, code);
4049 break;
4050 case OP_FCALL_MEMBASE:
4051 case OP_LCALL_MEMBASE:
4052 case OP_VCALL_MEMBASE:
4053 case OP_VCALL2_MEMBASE:
4054 case OP_VOIDCALL_MEMBASE:
4055 case OP_CALL_MEMBASE:
4056 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
4057 /* The trampolines clobber this */
4058 ppc_mr (code, ppc_r29, ins->sreg1);
4059 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4060 } else {
4061 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4063 ppc_mtlr (code, ppc_r0);
4064 ppc_blrl (code);
4065 /* FIXME: this should be handled somewhere else in the new jit */
4066 code = emit_move_return_value (cfg, ins, code);
4067 break;
4068 case OP_LOCALLOC: {
4069 guint8 * zero_loop_jump, * zero_loop_start;
4070 /* keep alignment */
4071 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4072 int area_offset = alloca_waste;
4073 area_offset &= ~31;
4074 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
4075 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4076 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
4077 /* use ctr to store the number of words to 0 if needed */
4078 if (ins->flags & MONO_INST_INIT) {
4079 /* we zero 4 bytes at a time:
4080 * we add 7 instead of 3 so that we set the counter to
4081 * at least 1, otherwise the bdnz instruction will make
4082 * it negative and iterate billions of times.
4084 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4085 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4086 ppc_mtctr (code, ppc_r0);
4088 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4089 ppc_neg (code, ppc_r12, ppc_r12);
4090 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4092 /* FIXME: make this loop work in 8 byte
4093 increments on PPC64 */
4094 if (ins->flags & MONO_INST_INIT) {
4095 /* adjust the dest reg by -4 so we can use stwu */
4096 /* we actually adjust -8 because we let the loop
4097 * run at least once
4099 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4100 ppc_li (code, ppc_r12, 0);
4101 zero_loop_start = code;
4102 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4103 zero_loop_jump = code;
4104 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4105 ppc_patch (zero_loop_jump, zero_loop_start);
4107 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4108 break;
4110 case OP_THROW: {
4111 //ppc_break (code);
4112 ppc_mr (code, ppc_r3, ins->sreg1);
4113 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4114 (gpointer)"mono_arch_throw_exception");
4115 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4116 ppc_load_func (code, PPC_CALL_REG, 0);
4117 ppc_mtlr (code, PPC_CALL_REG);
4118 ppc_blrl (code);
4119 } else {
4120 ppc_bl (code, 0);
4122 break;
4124 case OP_RETHROW: {
4125 //ppc_break (code);
4126 ppc_mr (code, ppc_r3, ins->sreg1);
4127 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4128 (gpointer)"mono_arch_rethrow_exception");
4129 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4130 ppc_load_func (code, PPC_CALL_REG, 0);
4131 ppc_mtlr (code, PPC_CALL_REG);
4132 ppc_blrl (code);
4133 } else {
4134 ppc_bl (code, 0);
4136 break;
4138 case OP_START_HANDLER: {
4139 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4140 g_assert (spvar->inst_basereg != ppc_sp);
4141 code = emit_reserve_param_area (cfg, code);
4142 ppc_mflr (code, ppc_r0);
4143 if (ppc_is_imm16 (spvar->inst_offset)) {
4144 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4145 } else {
4146 ppc_load (code, ppc_r12, spvar->inst_offset);
4147 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4149 break;
4151 case OP_ENDFILTER: {
4152 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4153 g_assert (spvar->inst_basereg != ppc_sp);
4154 code = emit_unreserve_param_area (cfg, code);
4155 if (ins->sreg1 != ppc_r3)
4156 ppc_mr (code, ppc_r3, ins->sreg1);
4157 if (ppc_is_imm16 (spvar->inst_offset)) {
4158 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4159 } else {
4160 ppc_load (code, ppc_r12, spvar->inst_offset);
4161 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4163 ppc_mtlr (code, ppc_r0);
4164 ppc_blr (code);
4165 break;
4167 case OP_ENDFINALLY: {
4168 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4169 g_assert (spvar->inst_basereg != ppc_sp);
4170 code = emit_unreserve_param_area (cfg, code);
4171 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4172 ppc_mtlr (code, ppc_r0);
4173 ppc_blr (code);
4174 break;
4176 case OP_CALL_HANDLER:
4177 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4178 ppc_bl (code, 0);
4179 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4180 break;
4181 case OP_LABEL:
4182 ins->inst_c0 = code - cfg->native_code;
4183 break;
4184 case OP_BR:
4185 /*if (ins->inst_target_bb->native_offset) {
4186 ppc_b (code, 0);
4187 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4188 } else*/ {
4189 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4190 ppc_b (code, 0);
4192 break;
4193 case OP_BR_REG:
4194 ppc_mtctr (code, ins->sreg1);
4195 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4196 break;
4197 case OP_CEQ:
4198 case OP_ICEQ:
4199 CASE_PPC64 (OP_LCEQ)
4200 ppc_li (code, ins->dreg, 0);
4201 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4202 ppc_li (code, ins->dreg, 1);
4203 break;
4204 case OP_CLT:
4205 case OP_CLT_UN:
4206 case OP_ICLT:
4207 case OP_ICLT_UN:
4208 CASE_PPC64 (OP_LCLT)
4209 CASE_PPC64 (OP_LCLT_UN)
4210 ppc_li (code, ins->dreg, 1);
4211 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4212 ppc_li (code, ins->dreg, 0);
4213 break;
4214 case OP_CGT:
4215 case OP_CGT_UN:
4216 case OP_ICGT:
4217 case OP_ICGT_UN:
4218 CASE_PPC64 (OP_LCGT)
4219 CASE_PPC64 (OP_LCGT_UN)
4220 ppc_li (code, ins->dreg, 1);
4221 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4222 ppc_li (code, ins->dreg, 0);
4223 break;
4224 case OP_COND_EXC_EQ:
4225 case OP_COND_EXC_NE_UN:
4226 case OP_COND_EXC_LT:
4227 case OP_COND_EXC_LT_UN:
4228 case OP_COND_EXC_GT:
4229 case OP_COND_EXC_GT_UN:
4230 case OP_COND_EXC_GE:
4231 case OP_COND_EXC_GE_UN:
4232 case OP_COND_EXC_LE:
4233 case OP_COND_EXC_LE_UN:
4234 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4235 break;
4236 case OP_COND_EXC_IEQ:
4237 case OP_COND_EXC_INE_UN:
4238 case OP_COND_EXC_ILT:
4239 case OP_COND_EXC_ILT_UN:
4240 case OP_COND_EXC_IGT:
4241 case OP_COND_EXC_IGT_UN:
4242 case OP_COND_EXC_IGE:
4243 case OP_COND_EXC_IGE_UN:
4244 case OP_COND_EXC_ILE:
4245 case OP_COND_EXC_ILE_UN:
4246 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4247 break;
4248 case OP_IBEQ:
4249 case OP_IBNE_UN:
4250 case OP_IBLT:
4251 case OP_IBLT_UN:
4252 case OP_IBGT:
4253 case OP_IBGT_UN:
4254 case OP_IBGE:
4255 case OP_IBGE_UN:
4256 case OP_IBLE:
4257 case OP_IBLE_UN:
4258 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4259 break;
4261 /* floating point opcodes */
4262 case OP_R8CONST:
4263 g_assert (cfg->compile_aot);
4265 /* FIXME: Optimize this */
4266 ppc_bl (code, 1);
4267 ppc_mflr (code, ppc_r12);
4268 ppc_b (code, 3);
4269 *(double*)code = *(double*)ins->inst_p0;
4270 code += 8;
4271 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4272 break;
4273 case OP_R4CONST:
4274 g_assert_not_reached ();
4275 break;
4276 case OP_STORER8_MEMBASE_REG:
4277 if (ppc_is_imm16 (ins->inst_offset)) {
4278 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4279 } else {
4280 if (ppc_is_imm32 (ins->inst_offset)) {
4281 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4282 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4283 } else {
4284 ppc_load (code, ppc_r0, ins->inst_offset);
4285 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4288 break;
4289 case OP_LOADR8_MEMBASE:
4290 if (ppc_is_imm16 (ins->inst_offset)) {
4291 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4292 } else {
4293 if (ppc_is_imm32 (ins->inst_offset)) {
4294 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4295 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4296 } else {
4297 ppc_load (code, ppc_r0, ins->inst_offset);
4298 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4301 break;
4302 case OP_STORER4_MEMBASE_REG:
4303 ppc_frsp (code, ins->sreg1, ins->sreg1);
4304 if (ppc_is_imm16 (ins->inst_offset)) {
4305 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4306 } else {
4307 if (ppc_is_imm32 (ins->inst_offset)) {
4308 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4309 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4310 } else {
4311 ppc_load (code, ppc_r0, ins->inst_offset);
4312 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4315 break;
4316 case OP_LOADR4_MEMBASE:
4317 if (ppc_is_imm16 (ins->inst_offset)) {
4318 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4319 } else {
4320 if (ppc_is_imm32 (ins->inst_offset)) {
4321 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4322 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4323 } else {
4324 ppc_load (code, ppc_r0, ins->inst_offset);
4325 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4328 break;
4329 case OP_LOADR4_MEMINDEX:
4330 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4331 break;
4332 case OP_LOADR8_MEMINDEX:
4333 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4334 break;
4335 case OP_STORER4_MEMINDEX:
4336 ppc_frsp (code, ins->sreg1, ins->sreg1);
4337 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4338 break;
4339 case OP_STORER8_MEMINDEX:
4340 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4341 break;
4342 case CEE_CONV_R_UN:
4343 case CEE_CONV_R4: /* FIXME: change precision */
4344 case CEE_CONV_R8:
4345 g_assert_not_reached ();
4346 case OP_FCONV_TO_I1:
4347 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4348 break;
4349 case OP_FCONV_TO_U1:
4350 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4351 break;
4352 case OP_FCONV_TO_I2:
4353 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4354 break;
4355 case OP_FCONV_TO_U2:
4356 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4357 break;
4358 case OP_FCONV_TO_I4:
4359 case OP_FCONV_TO_I:
4360 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4361 break;
4362 case OP_FCONV_TO_U4:
4363 case OP_FCONV_TO_U:
4364 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4365 break;
4366 case OP_LCONV_TO_R_UN:
4367 g_assert_not_reached ();
4368 /* Implemented as helper calls */
4369 break;
4370 case OP_LCONV_TO_OVF_I4_2:
4371 case OP_LCONV_TO_OVF_I: {
4372 #ifdef __mono_ppc64__
4373 NOT_IMPLEMENTED;
4374 #else
4375 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4376 // Check if its negative
4377 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4378 negative_branch = code;
4379 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4380 // Its positive msword == 0
4381 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4382 msword_positive_branch = code;
4383 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4385 ovf_ex_target = code;
4386 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4387 // Negative
4388 ppc_patch (negative_branch, code);
4389 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4390 msword_negative_branch = code;
4391 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4392 ppc_patch (msword_negative_branch, ovf_ex_target);
4394 ppc_patch (msword_positive_branch, code);
4395 if (ins->dreg != ins->sreg1)
4396 ppc_mr (code, ins->dreg, ins->sreg1);
4397 break;
4398 #endif
4400 case OP_SQRT:
4401 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4402 break;
4403 case OP_FADD:
4404 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4405 break;
4406 case OP_FSUB:
4407 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4408 break;
4409 case OP_FMUL:
4410 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4411 break;
4412 case OP_FDIV:
4413 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4414 break;
4415 case OP_FNEG:
4416 ppc_fneg (code, ins->dreg, ins->sreg1);
4417 break;
4418 case OP_FREM:
4419 /* emulated */
4420 g_assert_not_reached ();
4421 break;
4422 case OP_FCOMPARE:
4423 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4424 break;
4425 case OP_FCEQ:
4426 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4427 ppc_li (code, ins->dreg, 0);
4428 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4429 ppc_li (code, ins->dreg, 1);
4430 break;
4431 case OP_FCLT:
4432 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4433 ppc_li (code, ins->dreg, 1);
4434 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4435 ppc_li (code, ins->dreg, 0);
4436 break;
4437 case OP_FCLT_UN:
4438 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4439 ppc_li (code, ins->dreg, 1);
4440 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4441 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4442 ppc_li (code, ins->dreg, 0);
4443 break;
4444 case OP_FCGT:
4445 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4446 ppc_li (code, ins->dreg, 1);
4447 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4448 ppc_li (code, ins->dreg, 0);
4449 break;
4450 case OP_FCGT_UN:
4451 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4452 ppc_li (code, ins->dreg, 1);
4453 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4454 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4455 ppc_li (code, ins->dreg, 0);
4456 break;
4457 case OP_FBEQ:
4458 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4459 break;
4460 case OP_FBNE_UN:
4461 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4462 break;
4463 case OP_FBLT:
4464 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4465 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4466 break;
4467 case OP_FBLT_UN:
4468 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4469 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4470 break;
4471 case OP_FBGT:
4472 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4473 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4474 break;
4475 case OP_FBGT_UN:
4476 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4477 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4478 break;
4479 case OP_FBGE:
4480 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4481 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4482 break;
4483 case OP_FBGE_UN:
4484 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4485 break;
4486 case OP_FBLE:
4487 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4488 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4489 break;
4490 case OP_FBLE_UN:
4491 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4492 break;
4493 case OP_CKFINITE:
4494 g_assert_not_reached ();
4495 case OP_CHECK_FINITE: {
4496 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4497 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4498 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4499 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4500 break;
4501 case OP_JUMP_TABLE:
4502 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4503 #ifdef __mono_ppc64__
4504 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4505 #else
4506 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4507 #endif
4508 break;
4511 #ifdef __mono_ppc64__
4512 case OP_ICONV_TO_I4:
4513 case OP_SEXT_I4:
4514 ppc_extsw (code, ins->dreg, ins->sreg1);
4515 break;
4516 case OP_ICONV_TO_U4:
4517 case OP_ZEXT_I4:
4518 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4519 break;
4520 case OP_ICONV_TO_R4:
4521 case OP_ICONV_TO_R8:
4522 case OP_LCONV_TO_R4:
4523 case OP_LCONV_TO_R8: {
4524 int tmp;
4525 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4526 ppc_extsw (code, ppc_r0, ins->sreg1);
4527 tmp = ppc_r0;
4528 } else {
4529 tmp = ins->sreg1;
4531 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4532 ppc_mffgpr (code, ins->dreg, tmp);
4533 } else {
4534 ppc_str (code, tmp, -8, ppc_r1);
4535 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4537 ppc_fcfid (code, ins->dreg, ins->dreg);
4538 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4539 ppc_frsp (code, ins->dreg, ins->dreg);
4540 break;
4542 case OP_LSHR:
4543 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4544 break;
4545 case OP_LSHR_UN:
4546 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4547 break;
4548 case OP_COND_EXC_C:
4549 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4551 ppc_mfspr (code, ppc_r0, ppc_xer);
4552 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4553 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4554 break;
4555 case OP_COND_EXC_OV:
4556 ppc_mfspr (code, ppc_r0, ppc_xer);
4557 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4558 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4559 break;
4560 case OP_LBEQ:
4561 case OP_LBNE_UN:
4562 case OP_LBLT:
4563 case OP_LBLT_UN:
4564 case OP_LBGT:
4565 case OP_LBGT_UN:
4566 case OP_LBGE:
4567 case OP_LBGE_UN:
4568 case OP_LBLE:
4569 case OP_LBLE_UN:
4570 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4571 break;
4572 case OP_FCONV_TO_I8:
4573 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4574 break;
4575 case OP_FCONV_TO_U8:
4576 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4577 break;
4578 case OP_STOREI4_MEMBASE_REG:
4579 if (ppc_is_imm16 (ins->inst_offset)) {
4580 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4581 } else {
4582 ppc_load (code, ppc_r0, ins->inst_offset);
4583 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4585 break;
4586 case OP_STOREI4_MEMINDEX:
4587 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4588 break;
4589 case OP_ISHR_IMM:
4590 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4591 break;
4592 case OP_ISHR_UN_IMM:
4593 if (ins->inst_imm & 0x1f)
4594 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4595 else
4596 ppc_mr (code, ins->dreg, ins->sreg1);
4597 break;
4598 #else
4599 case OP_ICONV_TO_R4:
4600 case OP_ICONV_TO_R8: {
4601 if (cpu_hw_caps & PPC_ISA_64) {
4602 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4603 ppc_stw (code, ppc_r0, -8, ppc_r1);
4604 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4605 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4606 ppc_fcfid (code, ins->dreg, ins->dreg);
4607 if (ins->opcode == OP_ICONV_TO_R4)
4608 ppc_frsp (code, ins->dreg, ins->dreg);
4610 break;
4612 #endif
4614 case OP_ATOMIC_ADD_I4:
4615 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4616 int location = ins->inst_basereg;
4617 int addend = ins->sreg2;
4618 guint8 *loop, *branch;
4619 g_assert (ins->inst_offset == 0);
4621 loop = code;
4622 ppc_sync (code);
4623 if (ins->opcode == OP_ATOMIC_ADD_I4)
4624 ppc_lwarx (code, ppc_r0, 0, location);
4625 #ifdef __mono_ppc64__
4626 else
4627 ppc_ldarx (code, ppc_r0, 0, location);
4628 #endif
4630 ppc_add (code, ppc_r0, ppc_r0, addend);
4632 if (ins->opcode == OP_ATOMIC_ADD_I4)
4633 ppc_stwcxd (code, ppc_r0, 0, location);
4634 #ifdef __mono_ppc64__
4635 else
4636 ppc_stdcxd (code, ppc_r0, 0, location);
4637 #endif
4639 branch = code;
4640 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4641 ppc_patch (branch, loop);
4643 ppc_sync (code);
4644 ppc_mr (code, ins->dreg, ppc_r0);
4645 break;
4647 case OP_ATOMIC_CAS_I4:
4648 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4649 int location = ins->sreg1;
4650 int value = ins->sreg2;
4651 int comparand = ins->sreg3;
4652 guint8 *start, *not_equal, *lost_reservation;
4654 start = code;
4655 ppc_sync (code);
4656 if (ins->opcode == OP_ATOMIC_CAS_I4)
4657 ppc_lwarx (code, ppc_r0, 0, location);
4658 #ifdef __mono_ppc64__
4659 else
4660 ppc_ldarx (code, ppc_r0, 0, location);
4661 #endif
4663 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4664 not_equal = code;
4665 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4667 if (ins->opcode == OP_ATOMIC_CAS_I4)
4668 ppc_stwcxd (code, value, 0, location);
4669 #ifdef __mono_ppc64__
4670 else
4671 ppc_stdcxd (code, value, 0, location);
4672 #endif
4674 lost_reservation = code;
4675 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4676 ppc_patch (lost_reservation, start);
4677 ppc_patch (not_equal, code);
4679 ppc_sync (code);
4680 ppc_mr (code, ins->dreg, ppc_r0);
4681 break;
4683 case OP_GC_SAFE_POINT:
4684 break;
4686 default:
4687 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4688 g_assert_not_reached ();
4691 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4692 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4693 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4694 g_assert_not_reached ();
4697 cpos += max_len;
4699 last_ins = ins;
4700 last_offset = offset;
4703 cfg->code_len = code - cfg->native_code;
4705 #endif /* !DISABLE_JIT */
4707 void
4708 mono_arch_register_lowlevel_calls (void)
4710 /* The signature doesn't matter */
4711 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4714 #ifdef __mono_ppc64__
4715 #ifdef _LITTLE_ENDIAN
4716 #define patch_load_sequence(ip,val) do {\
4717 guint16 *__load = (guint16*)(ip); \
4718 g_assert (sizeof (val) == sizeof (gsize)); \
4719 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4720 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4721 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4722 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4723 } while (0)
4724 #elif defined _BIG_ENDIAN
4725 #define patch_load_sequence(ip,val) do {\
4726 guint16 *__load = (guint16*)(ip); \
4727 g_assert (sizeof (val) == sizeof (gsize)); \
4728 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4729 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4730 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4731 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4732 } while (0)
4733 #else
4734 #error huh? No endianess defined by compiler
4735 #endif
4736 #else
4737 #define patch_load_sequence(ip,val) do {\
4738 guint16 *__lis_ori = (guint16*)(ip); \
4739 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4740 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4741 } while (0)
4742 #endif
4744 #ifndef DISABLE_JIT
4745 void
4746 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4748 MonoJumpInfo *patch_info;
4749 gboolean compile_aot = !run_cctors;
4751 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4752 unsigned char *ip = patch_info->ip.i + code;
4753 unsigned char *target;
4754 gboolean is_fd = FALSE;
4756 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4758 if (compile_aot) {
4759 switch (patch_info->type) {
4760 case MONO_PATCH_INFO_BB:
4761 case MONO_PATCH_INFO_LABEL:
4762 break;
4763 default:
4764 /* No need to patch these */
4765 continue;
4769 switch (patch_info->type) {
4770 case MONO_PATCH_INFO_IP:
4771 patch_load_sequence (ip, ip);
4772 continue;
4773 case MONO_PATCH_INFO_METHOD_REL:
4774 g_assert_not_reached ();
4775 *((gpointer *)(ip)) = code + patch_info->data.offset;
4776 continue;
4777 case MONO_PATCH_INFO_SWITCH: {
4778 gpointer *table = (gpointer *)patch_info->data.table->table;
4779 int i;
4781 patch_load_sequence (ip, table);
4783 for (i = 0; i < patch_info->data.table->table_size; i++) {
4784 table [i] = (glong)patch_info->data.table->table [i] + code;
4786 /* we put into the table the absolute address, no need for ppc_patch in this case */
4787 continue;
4789 case MONO_PATCH_INFO_METHODCONST:
4790 case MONO_PATCH_INFO_CLASS:
4791 case MONO_PATCH_INFO_IMAGE:
4792 case MONO_PATCH_INFO_FIELD:
4793 case MONO_PATCH_INFO_VTABLE:
4794 case MONO_PATCH_INFO_IID:
4795 case MONO_PATCH_INFO_SFLDA:
4796 case MONO_PATCH_INFO_LDSTR:
4797 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4798 case MONO_PATCH_INFO_LDTOKEN:
4799 /* from OP_AOTCONST : lis + ori */
4800 patch_load_sequence (ip, target);
4801 continue;
4802 case MONO_PATCH_INFO_R4:
4803 case MONO_PATCH_INFO_R8:
4804 g_assert_not_reached ();
4805 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4806 continue;
4807 case MONO_PATCH_INFO_EXC_NAME:
4808 g_assert_not_reached ();
4809 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4810 continue;
4811 case MONO_PATCH_INFO_NONE:
4812 case MONO_PATCH_INFO_BB_OVF:
4813 case MONO_PATCH_INFO_EXC_OVF:
4814 /* everything is dealt with at epilog output time */
4815 continue;
4816 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4817 case MONO_PATCH_INFO_INTERNAL_METHOD:
4818 case MONO_PATCH_INFO_ABS:
4819 case MONO_PATCH_INFO_RGCTX_FETCH:
4820 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4821 is_fd = TRUE;
4822 break;
4823 #endif
4824 default:
4825 break;
4827 ppc_patch_full (ip, target, is_fd);
4832 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4833 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4834 * the instruction offset immediate for all the registers.
4836 static guint8*
4837 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4839 int i;
4840 if (!save_lmf) {
4841 for (i = 13; i <= 31; i++) {
4842 if (used_int_regs & (1 << i)) {
4843 ppc_str (code, i, pos, base_reg);
4844 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4845 pos += sizeof (mgreg_t);
4848 } else {
4849 /* pos is the start of the MonoLMF structure */
4850 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4851 for (i = 13; i <= 31; i++) {
4852 ppc_str (code, i, offset, base_reg);
4853 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4854 offset += sizeof (mgreg_t);
4856 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4857 for (i = 14; i < 32; i++) {
4858 ppc_stfd (code, i, offset, base_reg);
4859 offset += sizeof (gdouble);
4862 return code;
4866 * Stack frame layout:
4868 * ------------------- sp
4869 * MonoLMF structure or saved registers
4870 * -------------------
4871 * spilled regs
4872 * -------------------
4873 * locals
4874 * -------------------
4875 * optional 8 bytes for tracing
4876 * -------------------
4877 * param area size is cfg->param_area
4878 * -------------------
4879 * linkage area size is PPC_STACK_PARAM_OFFSET
4880 * ------------------- sp
4881 * red zone
4883 guint8 *
4884 mono_arch_emit_prolog (MonoCompile *cfg)
4886 MonoMethod *method = cfg->method;
4887 MonoBasicBlock *bb;
4888 MonoMethodSignature *sig;
4889 MonoInst *inst;
4890 long alloc_size, pos, max_offset, cfa_offset;
4891 int i;
4892 guint8 *code;
4893 CallInfo *cinfo;
4894 int tracing = 0;
4895 int lmf_offset = 0;
4896 int tailcall_struct_index;
4898 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4899 tracing = 1;
4901 sig = mono_method_signature (method);
4902 cfg->code_size = 512 + sig->param_count * 32;
4903 code = cfg->native_code = g_malloc (cfg->code_size);
4905 cfa_offset = 0;
4907 /* We currently emit unwind info for aot, but don't use it */
4908 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4910 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4911 ppc_mflr (code, ppc_r0);
4912 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4913 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4916 alloc_size = cfg->stack_offset;
4917 pos = 0;
4919 if (!method->save_lmf) {
4920 for (i = 31; i >= 13; --i) {
4921 if (cfg->used_int_regs & (1 << i)) {
4922 pos += sizeof (mgreg_t);
4925 } else {
4926 pos += sizeof (MonoLMF);
4927 lmf_offset = pos;
4929 alloc_size += pos;
4930 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4931 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4932 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4933 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4936 cfg->stack_usage = alloc_size;
4937 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4938 if (alloc_size) {
4939 if (ppc_is_imm16 (-alloc_size)) {
4940 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4941 cfa_offset = alloc_size;
4942 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4943 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4944 } else {
4945 if (pos)
4946 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4947 ppc_load (code, ppc_r0, -alloc_size);
4948 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4949 cfa_offset = alloc_size;
4950 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4951 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4954 if (cfg->frame_reg != ppc_sp) {
4955 ppc_mr (code, cfg->frame_reg, ppc_sp);
4956 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4959 /* store runtime generic context */
4960 if (cfg->rgctx_var) {
4961 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4962 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4964 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4967 /* compute max_offset in order to use short forward jumps
4968 * we always do it on ppc because the immediate displacement
4969 * for jumps is too small
4971 max_offset = 0;
4972 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4973 MonoInst *ins;
4974 bb->max_offset = max_offset;
4976 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4977 max_offset += 6;
4979 MONO_BB_FOR_EACH_INS (bb, ins)
4980 max_offset += ins_native_length (cfg, ins);
4983 /* load arguments allocated to register from the stack */
4984 pos = 0;
4986 cinfo = get_call_info (sig);
4988 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4989 ArgInfo *ainfo = &cinfo->ret;
4991 inst = cfg->vret_addr;
4992 g_assert (inst);
4994 if (ppc_is_imm16 (inst->inst_offset)) {
4995 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4996 } else {
4997 ppc_load (code, ppc_r12, inst->inst_offset);
4998 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5002 tailcall_struct_index = 0;
5003 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5004 ArgInfo *ainfo = cinfo->args + i;
5005 inst = cfg->args [pos];
5007 if (cfg->verbose_level > 2)
5008 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
5009 if (inst->opcode == OP_REGVAR) {
5010 if (ainfo->regtype == RegTypeGeneral)
5011 ppc_mr (code, inst->dreg, ainfo->reg);
5012 else if (ainfo->regtype == RegTypeFP)
5013 ppc_fmr (code, inst->dreg, ainfo->reg);
5014 else if (ainfo->regtype == RegTypeBase) {
5015 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5016 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
5017 } else
5018 g_assert_not_reached ();
5020 if (cfg->verbose_level > 2)
5021 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5022 } else {
5023 /* the argument should be put on the stack: FIXME handle size != word */
5024 if (ainfo->regtype == RegTypeGeneral) {
5025 switch (ainfo->size) {
5026 case 1:
5027 if (ppc_is_imm16 (inst->inst_offset)) {
5028 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5029 } else {
5030 if (ppc_is_imm32 (inst->inst_offset)) {
5031 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5032 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
5033 } else {
5034 ppc_load (code, ppc_r12, inst->inst_offset);
5035 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5038 break;
5039 case 2:
5040 if (ppc_is_imm16 (inst->inst_offset)) {
5041 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5042 } else {
5043 if (ppc_is_imm32 (inst->inst_offset)) {
5044 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5045 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
5046 } else {
5047 ppc_load (code, ppc_r12, inst->inst_offset);
5048 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5051 break;
5052 #ifdef __mono_ppc64__
5053 case 4:
5054 if (ppc_is_imm16 (inst->inst_offset)) {
5055 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5056 } else {
5057 if (ppc_is_imm32 (inst->inst_offset)) {
5058 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5059 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5060 } else {
5061 ppc_load (code, ppc_r12, inst->inst_offset);
5062 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5065 break;
5066 case 8:
5067 if (ppc_is_imm16 (inst->inst_offset)) {
5068 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5069 } else {
5070 ppc_load (code, ppc_r12, inst->inst_offset);
5071 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5073 break;
5074 #else
5075 case 8:
5076 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5077 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5078 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5079 } else {
5080 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5081 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5082 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5083 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5085 break;
5086 #endif
5087 default:
5088 if (ppc_is_imm16 (inst->inst_offset)) {
5089 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5090 } else {
5091 if (ppc_is_imm32 (inst->inst_offset)) {
5092 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5093 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5094 } else {
5095 ppc_load (code, ppc_r12, inst->inst_offset);
5096 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5099 break;
5101 } else if (ainfo->regtype == RegTypeBase) {
5102 g_assert (ppc_is_imm16 (ainfo->offset));
5103 /* load the previous stack pointer in r12 */
5104 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5105 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5106 switch (ainfo->size) {
5107 case 1:
5108 if (ppc_is_imm16 (inst->inst_offset)) {
5109 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5110 } else {
5111 if (ppc_is_imm32 (inst->inst_offset)) {
5112 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5113 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5114 } else {
5115 ppc_load (code, ppc_r12, inst->inst_offset);
5116 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5119 break;
5120 case 2:
5121 if (ppc_is_imm16 (inst->inst_offset)) {
5122 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5123 } else {
5124 if (ppc_is_imm32 (inst->inst_offset)) {
5125 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5126 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5127 } else {
5128 ppc_load (code, ppc_r12, inst->inst_offset);
5129 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5132 break;
5133 #ifdef __mono_ppc64__
5134 case 4:
5135 if (ppc_is_imm16 (inst->inst_offset)) {
5136 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5137 } else {
5138 if (ppc_is_imm32 (inst->inst_offset)) {
5139 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5140 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5141 } else {
5142 ppc_load (code, ppc_r12, inst->inst_offset);
5143 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5146 break;
5147 case 8:
5148 if (ppc_is_imm16 (inst->inst_offset)) {
5149 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5150 } else {
5151 ppc_load (code, ppc_r12, inst->inst_offset);
5152 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5154 break;
5155 #else
5156 case 8:
5157 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5158 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5159 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5160 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5161 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5162 } else {
5163 /* use r11 to load the 2nd half of the long before we clobber r12. */
5164 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5165 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5166 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5167 ppc_stw (code, ppc_r0, 0, ppc_r12);
5168 ppc_stw (code, ppc_r11, 4, ppc_r12);
5170 break;
5171 #endif
5172 default:
5173 if (ppc_is_imm16 (inst->inst_offset)) {
5174 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5175 } else {
5176 if (ppc_is_imm32 (inst->inst_offset)) {
5177 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5178 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5179 } else {
5180 ppc_load (code, ppc_r12, inst->inst_offset);
5181 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5184 break;
5186 } else if (ainfo->regtype == RegTypeFP) {
5187 g_assert (ppc_is_imm16 (inst->inst_offset));
5188 if (ainfo->size == 8)
5189 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5190 else if (ainfo->size == 4)
5191 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5192 else
5193 g_assert_not_reached ();
5194 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5195 int doffset = inst->inst_offset;
5196 int soffset = 0;
5197 int cur_reg;
5198 int size = 0;
5199 g_assert (ppc_is_imm16 (inst->inst_offset));
5200 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5201 /* FIXME: what if there is no class? */
5202 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5203 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5204 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5205 if (ainfo->size == 4) {
5206 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5207 } else {
5208 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5210 soffset += ainfo->size;
5211 doffset += ainfo->size;
5213 } else if (ainfo->regtype == RegTypeStructByVal) {
5214 int doffset = inst->inst_offset;
5215 int soffset = 0;
5216 int cur_reg;
5217 int size = 0;
5218 g_assert (ppc_is_imm16 (inst->inst_offset));
5219 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5220 /* FIXME: what if there is no class? */
5221 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5222 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5223 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5224 #if __APPLE__
5226 * Darwin handles 1 and 2 byte
5227 * structs specially by
5228 * loading h/b into the arg
5229 * register. Only done for
5230 * pinvokes.
5232 if (size == 2)
5233 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5234 else if (size == 1)
5235 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5236 else
5237 #endif
5239 #ifdef __mono_ppc64__
5240 if (ainfo->bytes) {
5241 g_assert (cur_reg == 0);
5242 #if G_BYTE_ORDER == G_BIG_ENDIAN
5243 ppc_sldi (code, ppc_r0, ainfo->reg,
5244 (sizeof (gpointer) - ainfo->bytes) * 8);
5245 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5246 #else
5247 if (mono_class_native_size (inst->klass, NULL) == 1) {
5248 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5249 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5250 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5251 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5252 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5253 } else {
5254 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5256 #endif
5257 } else
5258 #endif
5260 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5261 inst->inst_basereg);
5264 soffset += sizeof (gpointer);
5265 doffset += sizeof (gpointer);
5267 if (ainfo->vtsize) {
5268 /* FIXME: we need to do the shifting here, too */
5269 if (ainfo->bytes)
5270 NOT_IMPLEMENTED;
5271 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5272 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5273 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5274 code = emit_memcpy (code, size - soffset,
5275 inst->inst_basereg, doffset,
5276 ppc_r12, ainfo->offset + soffset);
5277 } else {
5278 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5279 inst->inst_basereg, doffset,
5280 ppc_r12, ainfo->offset + soffset);
5283 } else if (ainfo->regtype == RegTypeStructByAddr) {
5284 /* if it was originally a RegTypeBase */
5285 if (ainfo->offset) {
5286 /* load the previous stack pointer in r12 */
5287 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5288 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5289 } else {
5290 ppc_mr (code, ppc_r12, ainfo->reg);
5293 if (cfg->tailcall_valuetype_addrs) {
5294 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5296 g_assert (ppc_is_imm16 (addr->inst_offset));
5297 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5299 tailcall_struct_index++;
5302 g_assert (ppc_is_imm16 (inst->inst_offset));
5303 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5304 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5305 } else
5306 g_assert_not_reached ();
5308 pos++;
5311 if (method->save_lmf) {
5312 if (lmf_pthread_key != -1) {
5313 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5314 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5315 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5316 } else {
5317 if (cfg->compile_aot) {
5318 /* Compute the got address which is needed by the PLT entry */
5319 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5321 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5322 (gpointer)"mono_get_lmf_addr");
5323 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5324 ppc_load_func (code, PPC_CALL_REG, 0);
5325 ppc_mtlr (code, PPC_CALL_REG);
5326 ppc_blrl (code);
5327 } else {
5328 ppc_bl (code, 0);
5331 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5332 /* lmf_offset is the offset from the previous stack pointer,
5333 * alloc_size is the total stack space allocated, so the offset
5334 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5335 * The pointer to the struct is put in ppc_r12 (new_lmf).
5336 * The callee-saved registers are already in the MonoLMF structure
5338 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5339 /* ppc_r3 is the result from mono_get_lmf_addr () */
5340 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5341 /* new_lmf->previous_lmf = *lmf_addr */
5342 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5343 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5344 /* *(lmf_addr) = r12 */
5345 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5346 /* save method info */
5347 if (cfg->compile_aot)
5348 // FIXME:
5349 ppc_load (code, ppc_r0, 0);
5350 else
5351 ppc_load_ptr (code, ppc_r0, method);
5352 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5353 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5354 /* save the current IP */
5355 if (cfg->compile_aot) {
5356 ppc_bl (code, 1);
5357 ppc_mflr (code, ppc_r0);
5358 } else {
5359 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5360 #ifdef __mono_ppc64__
5361 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5362 #else
5363 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5364 #endif
5366 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5369 if (tracing)
5370 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5372 cfg->code_len = code - cfg->native_code;
5373 g_assert (cfg->code_len <= cfg->code_size);
5374 g_free (cinfo);
5376 return code;
5379 void
5380 mono_arch_emit_epilog (MonoCompile *cfg)
5382 MonoMethod *method = cfg->method;
5383 int pos, i;
5384 int max_epilog_size = 16 + 20*4;
5385 guint8 *code;
5387 if (cfg->method->save_lmf)
5388 max_epilog_size += 128;
5390 if (mono_jit_trace_calls != NULL)
5391 max_epilog_size += 50;
5393 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5394 max_epilog_size += 50;
5396 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5397 cfg->code_size *= 2;
5398 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5399 cfg->stat_code_reallocs++;
5403 * Keep in sync with OP_JMP
5405 code = cfg->native_code + cfg->code_len;
5407 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5408 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5410 pos = 0;
5412 if (method->save_lmf) {
5413 int lmf_offset;
5414 pos += sizeof (MonoLMF);
5415 lmf_offset = pos;
5416 /* save the frame reg in r8 */
5417 ppc_mr (code, ppc_r8, cfg->frame_reg);
5418 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5419 /* r5 = previous_lmf */
5420 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5421 /* r6 = lmf_addr */
5422 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5423 /* *(lmf_addr) = previous_lmf */
5424 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5425 /* FIXME: speedup: there is no actual need to restore the registers if
5426 * we didn't actually change them (idea from Zoltan).
5428 /* restore iregs */
5429 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5430 /* restore fregs */
5431 /*for (i = 14; i < 32; i++) {
5432 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5434 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5435 /* use the saved copy of the frame reg in r8 */
5436 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5437 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5438 ppc_mtlr (code, ppc_r0);
5440 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5441 } else {
5442 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5443 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5444 if (ppc_is_imm16 (return_offset)) {
5445 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5446 } else {
5447 ppc_load (code, ppc_r12, return_offset);
5448 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5450 ppc_mtlr (code, ppc_r0);
5452 if (ppc_is_imm16 (cfg->stack_usage)) {
5453 int offset = cfg->stack_usage;
5454 for (i = 13; i <= 31; i++) {
5455 if (cfg->used_int_regs & (1 << i))
5456 offset -= sizeof (mgreg_t);
5458 if (cfg->frame_reg != ppc_sp)
5459 ppc_mr (code, ppc_r12, cfg->frame_reg);
5460 /* note r31 (possibly the frame register) is restored last */
5461 for (i = 13; i <= 31; i++) {
5462 if (cfg->used_int_regs & (1 << i)) {
5463 ppc_ldr (code, i, offset, cfg->frame_reg);
5464 offset += sizeof (mgreg_t);
5467 if (cfg->frame_reg != ppc_sp)
5468 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5469 else
5470 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5471 } else {
5472 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5473 if (cfg->used_int_regs) {
5474 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5475 for (i = 31; i >= 13; --i) {
5476 if (cfg->used_int_regs & (1 << i)) {
5477 pos += sizeof (mgreg_t);
5478 ppc_ldr (code, i, -pos, ppc_r12);
5481 ppc_mr (code, ppc_sp, ppc_r12);
5482 } else {
5483 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5488 ppc_blr (code);
5490 cfg->code_len = code - cfg->native_code;
5492 g_assert (cfg->code_len < cfg->code_size);
5495 #endif /* ifndef DISABLE_JIT */
5497 /* remove once throw_exception_by_name is eliminated */
5498 static int
5499 exception_id_by_name (const char *name)
5501 if (strcmp (name, "IndexOutOfRangeException") == 0)
5502 return MONO_EXC_INDEX_OUT_OF_RANGE;
5503 if (strcmp (name, "OverflowException") == 0)
5504 return MONO_EXC_OVERFLOW;
5505 if (strcmp (name, "ArithmeticException") == 0)
5506 return MONO_EXC_ARITHMETIC;
5507 if (strcmp (name, "DivideByZeroException") == 0)
5508 return MONO_EXC_DIVIDE_BY_ZERO;
5509 if (strcmp (name, "InvalidCastException") == 0)
5510 return MONO_EXC_INVALID_CAST;
5511 if (strcmp (name, "NullReferenceException") == 0)
5512 return MONO_EXC_NULL_REF;
5513 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5514 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5515 if (strcmp (name, "ArgumentException") == 0)
5516 return MONO_EXC_ARGUMENT;
5517 g_error ("Unknown intrinsic exception %s\n", name);
5518 return 0;
5521 #ifndef DISABLE_JIT
5522 void
5523 mono_arch_emit_exceptions (MonoCompile *cfg)
5525 MonoJumpInfo *patch_info;
5526 int i;
5527 guint8 *code;
5528 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5529 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5530 int max_epilog_size = 50;
5532 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5533 exc_throw_pos [i] = NULL;
5534 exc_throw_found [i] = 0;
5537 /* count the number of exception infos */
5540 * make sure we have enough space for exceptions
5542 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5543 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5544 i = exception_id_by_name (patch_info->data.target);
5545 if (!exc_throw_found [i]) {
5546 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5547 exc_throw_found [i] = TRUE;
5549 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5550 max_epilog_size += 12;
5551 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5552 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5553 i = exception_id_by_name (ovfj->data.exception);
5554 if (!exc_throw_found [i]) {
5555 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5556 exc_throw_found [i] = TRUE;
5558 max_epilog_size += 8;
5562 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5563 cfg->code_size *= 2;
5564 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5565 cfg->stat_code_reallocs++;
5568 code = cfg->native_code + cfg->code_len;
5570 /* add code to raise exceptions */
5571 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5572 switch (patch_info->type) {
5573 case MONO_PATCH_INFO_BB_OVF: {
5574 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5575 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5576 /* patch the initial jump */
5577 ppc_patch (ip, code);
5578 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5579 ppc_b (code, 0);
5580 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5581 /* jump back to the true target */
5582 ppc_b (code, 0);
5583 ip = ovfj->data.bb->native_offset + cfg->native_code;
5584 ppc_patch (code - 4, ip);
5585 patch_info->type = MONO_PATCH_INFO_NONE;
5586 break;
5588 case MONO_PATCH_INFO_EXC_OVF: {
5589 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5590 MonoJumpInfo *newji;
5591 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5592 unsigned char *bcl = code;
5593 /* patch the initial jump: we arrived here with a call */
5594 ppc_patch (ip, code);
5595 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5596 ppc_b (code, 0);
5597 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5598 /* patch the conditional jump to the right handler */
5599 /* make it processed next */
5600 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5601 newji->type = MONO_PATCH_INFO_EXC;
5602 newji->ip.i = bcl - cfg->native_code;
5603 newji->data.target = ovfj->data.exception;
5604 newji->next = patch_info->next;
5605 patch_info->next = newji;
5606 patch_info->type = MONO_PATCH_INFO_NONE;
5607 break;
5609 case MONO_PATCH_INFO_EXC: {
5610 MonoClass *exc_class;
5612 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5613 i = exception_id_by_name (patch_info->data.target);
5614 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5615 ppc_patch (ip, exc_throw_pos [i]);
5616 patch_info->type = MONO_PATCH_INFO_NONE;
5617 break;
5618 } else {
5619 exc_throw_pos [i] = code;
5622 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5623 g_assert (exc_class);
5625 ppc_patch (ip, code);
5626 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5627 ppc_load (code, ppc_r3, exc_class->type_token);
5628 /* we got here from a conditional call, so the calling ip is set in lr */
5629 ppc_mflr (code, ppc_r4);
5630 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5631 patch_info->data.name = "mono_arch_throw_corlib_exception";
5632 patch_info->ip.i = code - cfg->native_code;
5633 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5634 ppc_load_func (code, PPC_CALL_REG, 0);
5635 ppc_mtctr (code, PPC_CALL_REG);
5636 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5637 } else {
5638 ppc_bl (code, 0);
5640 break;
5642 default:
5643 /* do nothing */
5644 break;
5648 cfg->code_len = code - cfg->native_code;
5650 g_assert (cfg->code_len <= cfg->code_size);
5652 #endif
5654 #if DEAD_CODE
5655 static int
5656 try_offset_access (void *value, guint32 idx)
5658 register void* me __asm__ ("r2");
5659 void ***p = (void***)((char*)me + 284);
5660 int idx1 = idx / 32;
5661 int idx2 = idx % 32;
5662 if (!p [idx1])
5663 return 0;
5664 if (value != p[idx1][idx2])
5665 return 0;
5666 return 1;
5668 #endif
5670 static void
5671 setup_tls_access (void)
5673 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5674 size_t conf_size = 0;
5675 char confbuf[128];
5676 #else
5677 /* FIXME for darwin */
5678 guint32 *ins, *code;
5679 guint32 cmplwi_1023, li_0x48, blr_ins;
5680 #endif
5682 #ifdef TARGET_PS3
5683 tls_mode = TLS_MODE_FAILED;
5684 #endif
5686 if (tls_mode == TLS_MODE_FAILED)
5687 return;
5688 if (g_getenv ("MONO_NO_TLS")) {
5689 tls_mode = TLS_MODE_FAILED;
5690 return;
5693 if (tls_mode == TLS_MODE_DETECT) {
5694 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5695 tls_mode = TLS_MODE_DARWIN_G4;
5696 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5697 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5698 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5699 tls_mode = TLS_MODE_NPTL;
5700 #elif !defined(TARGET_PS3)
5701 ins = (guint32*)pthread_getspecific;
5702 /* uncond branch to the real method */
5703 if ((*ins >> 26) == 18) {
5704 gint32 val;
5705 val = (*ins & ~3) << 6;
5706 val >>= 6;
5707 if (*ins & 2) {
5708 /* absolute */
5709 ins = (guint32*)(long)val;
5710 } else {
5711 ins = (guint32*) ((char*)ins + val);
5714 code = &cmplwi_1023;
5715 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5716 code = &li_0x48;
5717 ppc_li (code, ppc_r4, 0x48);
5718 code = &blr_ins;
5719 ppc_blr (code);
5720 if (*ins == cmplwi_1023) {
5721 int found_lwz_284 = 0;
5722 guint32 ptk;
5723 for (ptk = 0; ptk < 20; ++ptk) {
5724 ++ins;
5725 if (!*ins || *ins == blr_ins)
5726 break;
5727 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5728 found_lwz_284 = 1;
5729 break;
5732 if (!found_lwz_284) {
5733 tls_mode = TLS_MODE_FAILED;
5734 return;
5736 tls_mode = TLS_MODE_LTHREADS;
5737 } else if (*ins == li_0x48) {
5738 ++ins;
5739 /* uncond branch to the real method */
5740 if ((*ins >> 26) == 18) {
5741 gint32 val;
5742 val = (*ins & ~3) << 6;
5743 val >>= 6;
5744 if (*ins & 2) {
5745 /* absolute */
5746 ins = (guint32*)(long)val;
5747 } else {
5748 ins = (guint32*) ((char*)ins + val);
5750 code = (guint32*)&val;
5751 ppc_li (code, ppc_r0, 0x7FF2);
5752 if (ins [1] == val) {
5753 /* Darwin on G4, implement */
5754 tls_mode = TLS_MODE_FAILED;
5755 return;
5756 } else {
5757 code = (guint32*)&val;
5758 ppc_mfspr (code, ppc_r3, 104);
5759 if (ins [1] != val) {
5760 tls_mode = TLS_MODE_FAILED;
5761 return;
5763 tls_mode = TLS_MODE_DARWIN_G5;
5765 } else {
5766 tls_mode = TLS_MODE_FAILED;
5767 return;
5769 } else {
5770 tls_mode = TLS_MODE_FAILED;
5771 return;
5773 #endif
5775 #ifndef TARGET_PS3
5776 if (tls_mode == TLS_MODE_DETECT)
5777 tls_mode = TLS_MODE_FAILED;
5778 if (tls_mode == TLS_MODE_FAILED)
5779 return;
5780 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5781 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5784 #if 0
5785 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5786 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5787 if (lmf_pthread_key == -1) {
5788 guint32 ptk = mono_jit_tls_id;
5789 if (ptk < 1024) {
5790 /*g_print ("MonoLMF at: %d\n", ptk);*/
5791 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5792 init_tls_failed = 1;
5793 return;
5795 lmf_pthread_key = ptk;
5798 #endif
5800 #endif
5803 void
5804 mono_arch_finish_init (void)
5806 setup_tls_access ();
5809 void
5810 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5814 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5815 #define BR_SIZE 4
5816 #define LOADSTORE_SIZE 4
5817 #define JUMP_IMM_SIZE 12
5818 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5819 #define ENABLE_WRONG_METHOD_CHECK 0
5822 * LOCKING: called with the domain lock held
5824 gpointer
5825 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5826 gpointer fail_tramp)
5828 int i;
5829 int size = 0;
5830 guint8 *code, *start;
5832 for (i = 0; i < count; ++i) {
5833 MonoIMTCheckItem *item = imt_entries [i];
5834 if (item->is_equals) {
5835 if (item->check_target_idx) {
5836 if (!item->compare_done)
5837 item->chunk_size += CMP_SIZE;
5838 if (item->has_target_code)
5839 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5840 else
5841 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5842 } else {
5843 if (fail_tramp) {
5844 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5845 if (!item->has_target_code)
5846 item->chunk_size += LOADSTORE_SIZE;
5847 } else {
5848 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5849 #if ENABLE_WRONG_METHOD_CHECK
5850 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5851 #endif
5854 } else {
5855 item->chunk_size += CMP_SIZE + BR_SIZE;
5856 imt_entries [item->check_target_idx]->compare_done = TRUE;
5858 size += item->chunk_size;
5860 /* the initial load of the vtable address */
5861 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5862 if (fail_tramp) {
5863 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5864 } else {
5865 code = mono_domain_code_reserve (domain, size);
5867 start = code;
5870 * We need to save and restore r12 because it might be
5871 * used by the caller as the vtable register, so
5872 * clobbering it will trip up the magic trampoline.
5874 * FIXME: Get rid of this by making sure that r12 is
5875 * not used as the vtable register in interface calls.
5877 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5878 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5880 for (i = 0; i < count; ++i) {
5881 MonoIMTCheckItem *item = imt_entries [i];
5882 item->code_target = code;
5883 if (item->is_equals) {
5884 if (item->check_target_idx) {
5885 if (!item->compare_done) {
5886 ppc_load (code, ppc_r0, (gsize)item->key);
5887 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5889 item->jmp_code = code;
5890 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5891 if (item->has_target_code) {
5892 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5893 } else {
5894 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5895 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5897 ppc_mtctr (code, ppc_r0);
5898 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5899 } else {
5900 if (fail_tramp) {
5901 ppc_load (code, ppc_r0, (gulong)item->key);
5902 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5903 item->jmp_code = code;
5904 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5905 if (item->has_target_code) {
5906 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5907 } else {
5908 g_assert (vtable);
5909 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5910 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5912 ppc_mtctr (code, ppc_r0);
5913 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5914 ppc_patch (item->jmp_code, code);
5915 ppc_load_ptr (code, ppc_r0, fail_tramp);
5916 ppc_mtctr (code, ppc_r0);
5917 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5918 item->jmp_code = NULL;
5919 } else {
5920 /* enable the commented code to assert on wrong method */
5921 #if ENABLE_WRONG_METHOD_CHECK
5922 ppc_load (code, ppc_r0, (guint32)item->key);
5923 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5924 item->jmp_code = code;
5925 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5926 #endif
5927 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5928 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5929 ppc_mtctr (code, ppc_r0);
5930 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5931 #if ENABLE_WRONG_METHOD_CHECK
5932 ppc_patch (item->jmp_code, code);
5933 ppc_break (code);
5934 item->jmp_code = NULL;
5935 #endif
5938 } else {
5939 ppc_load (code, ppc_r0, (gulong)item->key);
5940 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5941 item->jmp_code = code;
5942 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5945 /* patch the branches to get to the target items */
5946 for (i = 0; i < count; ++i) {
5947 MonoIMTCheckItem *item = imt_entries [i];
5948 if (item->jmp_code) {
5949 if (item->check_target_idx) {
5950 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5955 if (!fail_tramp)
5956 mono_stats.imt_thunks_size += code - start;
5957 g_assert (code - start <= size);
5958 mono_arch_flush_icache (start, size);
5960 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5962 return start;
5965 MonoMethod*
5966 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5968 mgreg_t *r = (mgreg_t*)regs;
5970 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5973 MonoVTable*
5974 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5976 mgreg_t *r = (mgreg_t*)regs;
5978 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5981 GSList*
5982 mono_arch_get_cie_program (void)
5984 GSList *l = NULL;
5986 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5988 return l;
5991 MonoInst*
5992 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5994 /* FIXME: */
5995 return NULL;
5998 gboolean
5999 mono_arch_print_tree (MonoInst *tree, int arity)
6001 return 0;
6004 mgreg_t
6005 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6007 if (reg == ppc_r1)
6008 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
6010 g_assert (reg >= ppc_r13);
6012 return ctx->regs [reg - ppc_r13];
6015 guint32
6016 mono_arch_get_patch_offset (guint8 *code)
6018 return 0;
6022 * mono_aot_emit_load_got_addr:
6024 * Emit code to load the got address.
6025 * On PPC, the result is placed into r30.
6027 guint8*
6028 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6030 ppc_bl (code, 1);
6031 ppc_mflr (code, ppc_r30);
6032 if (cfg)
6033 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6034 else
6035 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6036 /* arch_emit_got_address () patches this */
6037 #if defined(TARGET_POWERPC64)
6038 ppc_nop (code);
6039 ppc_nop (code);
6040 ppc_nop (code);
6041 ppc_nop (code);
6042 #else
6043 ppc_load32 (code, ppc_r0, 0);
6044 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6045 #endif
6047 return code;
6051 * mono_ppc_emit_load_aotconst:
6053 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6054 * TARGET from the mscorlib GOT in full-aot code.
6055 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
6056 * r12.
6058 guint8*
6059 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
6061 /* Load the mscorlib got address */
6062 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
6063 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6064 /* arch_emit_got_access () patches this */
6065 ppc_load32 (code, ppc_r0, 0);
6066 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
6068 return code;
6071 /* Soft Debug support */
6072 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6075 * BREAKPOINTS
6079 * mono_arch_set_breakpoint:
6081 * See mini-amd64.c for docs.
6083 void
6084 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6086 guint8 *code = ip;
6087 guint8 *orig_code = code;
6089 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6090 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6092 g_assert (code - orig_code == BREAKPOINT_SIZE);
6094 mono_arch_flush_icache (orig_code, code - orig_code);
6098 * mono_arch_clear_breakpoint:
6100 * See mini-amd64.c for docs.
6102 void
6103 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6105 guint8 *code = ip;
6106 int i;
6108 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6109 ppc_nop (code);
6111 mono_arch_flush_icache (ip, code - ip);
6115 * mono_arch_is_breakpoint_event:
6117 * See mini-amd64.c for docs.
6119 gboolean
6120 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6122 siginfo_t* sinfo = (siginfo_t*) info;
6123 /* Sometimes the address is off by 4 */
6124 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6125 return TRUE;
6126 else
6127 return FALSE;
6131 * mono_arch_skip_breakpoint:
6133 * See mini-amd64.c for docs.
6135 void
6136 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6138 /* skip the ldptr */
6139 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6143 * SINGLE STEPPING
6147 * mono_arch_start_single_stepping:
6149 * See mini-amd64.c for docs.
6151 void
6152 mono_arch_start_single_stepping (void)
6154 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6158 * mono_arch_stop_single_stepping:
6160 * See mini-amd64.c for docs.
6162 void
6163 mono_arch_stop_single_stepping (void)
6165 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6169 * mono_arch_is_single_step_event:
6171 * See mini-amd64.c for docs.
6173 gboolean
6174 mono_arch_is_single_step_event (void *info, void *sigctx)
6176 siginfo_t* sinfo = (siginfo_t*) info;
6177 /* Sometimes the address is off by 4 */
6178 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6179 return TRUE;
6180 else
6181 return FALSE;
6185 * mono_arch_skip_single_step:
6187 * See mini-amd64.c for docs.
6189 void
6190 mono_arch_skip_single_step (MonoContext *ctx)
6192 /* skip the ldptr */
6193 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6197 * mono_arch_create_seq_point_info:
6199 * See mini-amd64.c for docs.
6201 gpointer
6202 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6204 NOT_IMPLEMENTED;
6205 return NULL;
6208 void
6209 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6211 ext->lmf.previous_lmf = prev_lmf;
6212 /* Mark that this is a MonoLMFExt */
6213 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6214 ext->lmf.ebp = (gssize)ext;
6217 #endif
6219 gboolean
6220 mono_arch_opcode_supported (int opcode)
6222 switch (opcode) {
6223 case OP_ATOMIC_ADD_I4:
6224 case OP_ATOMIC_CAS_I4:
6225 #ifdef TARGET_POWERPC64
6226 case OP_ATOMIC_ADD_I8:
6227 case OP_ATOMIC_CAS_I8:
6228 #endif
6229 return TRUE;
6230 default:
6231 return FALSE;
6236 #if 0
6237 // FIXME: To get the test case finally_block_ending_in_dead_bb to work properly we need to define the following
6238 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6239 // #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6241 gpointer
6242 mono_arch_create_handler_block_trampoline (void)
6244 . . .
6246 #endif