2010-04-07 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / mini-ppc.c
blob6c962bab95f38d31e8e65deb1a67816919d2108a
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/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/utils/mono-proclib.h>
18 #include <mono/utils/mono-mmap.h>
20 #include "mini-ppc.h"
21 #ifdef TARGET_POWERPC64
22 #include "cpu-ppc64.h"
23 #else
24 #include "cpu-ppc.h"
25 #endif
26 #include "trace.h"
27 #include "ir-emit.h"
28 #ifdef __APPLE__
29 #include <sys/sysctl.h>
30 #endif
31 #ifdef __linux__
32 #include <unistd.h>
33 #endif
35 #define FORCE_INDIR_CALL 1
37 enum {
38 TLS_MODE_DETECT,
39 TLS_MODE_FAILED,
40 TLS_MODE_LTHREADS,
41 TLS_MODE_NPTL,
42 TLS_MODE_DARWIN_G4,
43 TLS_MODE_DARWIN_G5
46 /* cpu_hw_caps contains the flags defined below */
47 static int cpu_hw_caps = 0;
48 static int cachelinesize = 0;
49 static int cachelineinc = 0;
50 enum {
51 PPC_ICACHE_SNOOP = 1 << 0,
52 PPC_MULTIPLE_LS_UNITS = 1 << 1,
53 PPC_SMP_CAPABLE = 1 << 2,
54 PPC_ISA_2X = 1 << 3,
55 PPC_ISA_64 = 1 << 4,
56 PPC_MOVE_FPR_GPR = 1 << 5,
57 PPC_HW_CAP_END
60 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
65 static CRITICAL_SECTION mini_arch_mutex;
67 int mono_exc_esp_offset = 0;
68 static int tls_mode = TLS_MODE_DETECT;
69 static int lmf_pthread_key = -1;
70 static int monodomain_key = -1;
73 * The code generated for sequence points reads from this location, which is
74 * made read-only when single stepping is enabled.
76 static gpointer ss_trigger_page;
78 /* Enabled breakpoints read from this trigger page */
79 static gpointer bp_trigger_page;
81 static int
82 offsets_from_pthread_key (guint32 key, int *offset2)
84 int idx1 = key / 32;
85 int idx2 = key % 32;
86 *offset2 = idx2 * sizeof (gpointer);
87 return 284 + idx1 * sizeof (gpointer);
90 #define emit_linuxthreads_tls(code,dreg,key) do {\
91 int off1, off2; \
92 off1 = offsets_from_pthread_key ((key), &off2); \
93 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
94 ppc_ldptr ((code), (dreg), off2, (dreg)); \
95 } while (0);
97 #define emit_darwing5_tls(code,dreg,key) do {\
98 int off1 = 0x48 + key * sizeof (gpointer); \
99 ppc_mfspr ((code), (dreg), 104); \
100 ppc_ldptr ((code), (dreg), off1, (dreg)); \
101 } while (0);
103 /* FIXME: ensure the sc call preserves all but r3 */
104 #define emit_darwing4_tls(code,dreg,key) do {\
105 int off1 = 0x48 + key * sizeof (gpointer); \
106 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
107 ppc_li ((code), ppc_r0, 0x7FF2); \
108 ppc_sc ((code)); \
109 ppc_lwz ((code), (dreg), off1, ppc_r3); \
110 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
111 } while (0);
113 #ifdef PPC_THREAD_PTR_REG
114 #define emit_nptl_tls(code,dreg,key) do { \
115 int off1 = key; \
116 int off2 = key >> 15; \
117 if ((off2 == 0) || (off2 == -1)) { \
118 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
119 } else { \
120 int off3 = (off2 + 1) > 1; \
121 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
122 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
124 } while (0);
125 #else
126 #define emit_nptl_tls(code,dreg,key) do { \
127 g_assert_not_reached (); \
128 } while (0)
129 #endif
131 #define emit_tls_access(code,dreg,key) do { \
132 switch (tls_mode) { \
133 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
134 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
135 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
137 default: g_assert_not_reached (); \
139 } while (0)
141 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
142 MonoInst *inst; \
143 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
144 inst->type = STACK_R8; \
145 inst->dreg = (dr); \
146 inst->inst_p0 = (void*)(addr); \
147 mono_bblock_add_inst (cfg->cbb, inst); \
148 } while (0)
150 const char*
151 mono_arch_regname (int reg) {
152 static const char rnames[][4] = {
153 "r0", "sp", "r2", "r3", "r4",
154 "r5", "r6", "r7", "r8", "r9",
155 "r10", "r11", "r12", "r13", "r14",
156 "r15", "r16", "r17", "r18", "r19",
157 "r20", "r21", "r22", "r23", "r24",
158 "r25", "r26", "r27", "r28", "r29",
159 "r30", "r31"
161 if (reg >= 0 && reg < 32)
162 return rnames [reg];
163 return "unknown";
166 const char*
167 mono_arch_fregname (int reg) {
168 static const char rnames[][4] = {
169 "f0", "f1", "f2", "f3", "f4",
170 "f5", "f6", "f7", "f8", "f9",
171 "f10", "f11", "f12", "f13", "f14",
172 "f15", "f16", "f17", "f18", "f19",
173 "f20", "f21", "f22", "f23", "f24",
174 "f25", "f26", "f27", "f28", "f29",
175 "f30", "f31"
177 if (reg >= 0 && reg < 32)
178 return rnames [reg];
179 return "unknown";
182 /* this function overwrites r0, r11, r12 */
183 static guint8*
184 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
186 /* unrolled, use the counter in big */
187 if (size > sizeof (gpointer) * 5) {
188 long shifted = size / SIZEOF_VOID_P;
189 guint8 *copy_loop_start, *copy_loop_jump;
191 ppc_load (code, ppc_r0, shifted);
192 ppc_mtctr (code, ppc_r0);
193 g_assert (sreg == ppc_r11);
194 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
195 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
196 copy_loop_start = code;
197 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
198 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 copy_loop_jump = code;
200 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
201 ppc_patch (copy_loop_jump, copy_loop_start);
202 size -= shifted * sizeof (gpointer);
203 doffset = soffset = 0;
204 dreg = ppc_r12;
206 #ifdef __mono_ppc64__
207 /* the hardware has multiple load/store units and the move is long
208 enough to use more then one regiester, then use load/load/store/store
209 to execute 2 instructions per cycle. */
210 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
211 while (size >= 16) {
212 ppc_ldptr (code, ppc_r0, soffset, sreg);
213 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
214 ppc_stptr (code, ppc_r0, doffset, dreg);
215 ppc_stptr (code, ppc_r12, doffset+8, dreg);
216 size -= 16;
217 soffset += 16;
218 doffset += 16;
221 while (size >= 8) {
222 ppc_ldr (code, ppc_r0, soffset, sreg);
223 ppc_str (code, ppc_r0, doffset, dreg);
224 size -= 8;
225 soffset += 8;
226 doffset += 8;
228 #else
229 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
230 while (size >= 8) {
231 ppc_lwz (code, ppc_r0, soffset, sreg);
232 ppc_lwz (code, ppc_r12, soffset+4, sreg);
233 ppc_stw (code, ppc_r0, doffset, dreg);
234 ppc_stw (code, ppc_r12, doffset+4, dreg);
235 size -= 8;
236 soffset += 8;
237 doffset += 8;
240 #endif
241 while (size >= 4) {
242 ppc_lwz (code, ppc_r0, soffset, sreg);
243 ppc_stw (code, ppc_r0, doffset, dreg);
244 size -= 4;
245 soffset += 4;
246 doffset += 4;
248 while (size >= 2) {
249 ppc_lhz (code, ppc_r0, soffset, sreg);
250 ppc_sth (code, ppc_r0, doffset, dreg);
251 size -= 2;
252 soffset += 2;
253 doffset += 2;
255 while (size >= 1) {
256 ppc_lbz (code, ppc_r0, soffset, sreg);
257 ppc_stb (code, ppc_r0, doffset, dreg);
258 size -= 1;
259 soffset += 1;
260 doffset += 1;
262 return code;
266 * mono_arch_get_argument_info:
267 * @csig: a method signature
268 * @param_count: the number of parameters to consider
269 * @arg_info: an array to store the result infos
271 * Gathers information on parameters such as size, alignment and
272 * padding. arg_info should be large enought to hold param_count + 1 entries.
274 * Returns the size of the activation frame.
277 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
279 #ifdef __mono_ppc64__
280 NOT_IMPLEMENTED;
281 return -1;
282 #else
283 int k, frame_size = 0;
284 int size, align, pad;
285 int offset = 8;
287 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
288 frame_size += sizeof (gpointer);
289 offset += 4;
292 arg_info [0].offset = offset;
294 if (csig->hasthis) {
295 frame_size += sizeof (gpointer);
296 offset += 4;
299 arg_info [0].size = frame_size;
301 for (k = 0; k < param_count; k++) {
303 if (csig->pinvoke)
304 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
305 else
306 size = mini_type_stack_size (NULL, csig->params [k], &align);
308 /* ignore alignment for now */
309 align = 1;
311 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
312 arg_info [k].pad = pad;
313 frame_size += size;
314 arg_info [k + 1].pad = 0;
315 arg_info [k + 1].size = size;
316 offset += pad;
317 arg_info [k + 1].offset = offset;
318 offset += size;
321 align = MONO_ARCH_FRAME_ALIGNMENT;
322 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
323 arg_info [k].pad = pad;
325 return frame_size;
326 #endif
329 #ifdef __mono_ppc64__
330 static gboolean
331 is_load_sequence (guint32 *seq)
333 return ppc_opcode (seq [0]) == 15 && /* lis */
334 ppc_opcode (seq [1]) == 24 && /* ori */
335 ppc_opcode (seq [2]) == 30 && /* sldi */
336 ppc_opcode (seq [3]) == 25 && /* oris */
337 ppc_opcode (seq [4]) == 24; /* ori */
340 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
341 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
342 #endif
344 /* code must point to the blrl */
345 gboolean
346 mono_ppc_is_direct_call_sequence (guint32 *code)
348 #ifdef __mono_ppc64__
349 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
351 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
352 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
353 if (ppc_opcode (code [-2]) == 58 && ppc_opcode (code [-3]) == 58) { /* ld/ld */
354 if (!is_load_sequence (&code [-8]))
355 return FALSE;
356 /* one of the loads must be "ld r2,8(rX)" */
357 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == 8) ||
358 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == 8);
360 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
361 return is_load_sequence (&code [-8]);
362 else
363 return is_load_sequence (&code [-6]);
365 return FALSE;
366 #else
367 g_assert(*code == 0x4e800021);
369 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
370 return ppc_opcode (code [-1]) == 31 &&
371 ppc_opcode (code [-2]) == 24 &&
372 ppc_opcode (code [-3]) == 15;
373 #endif
376 gpointer
377 mono_arch_get_vcall_slot (guint8 *code_ptr, mgreg_t *regs, int *displacement)
379 char *o = NULL;
380 int reg, offset = 0;
381 guint32* code = (guint32*)code_ptr;
382 mgreg_t *r = (mgreg_t*)regs;
384 *displacement = 0;
386 /* This is the 'blrl' instruction */
387 --code;
389 /* Sanity check: instruction must be 'blrl' */
390 if (*code != 0x4e800021)
391 return NULL;
393 if (mono_ppc_is_direct_call_sequence (code))
394 return NULL;
396 /* FIXME: more sanity checks here */
397 /* OK, we're now at the 'blrl' instruction. Now walk backwards
398 till we get to a 'mtlr rA' */
399 for (; --code;) {
400 if((*code & 0x7c0803a6) == 0x7c0803a6) {
401 gint16 soff;
402 /* Here we are: we reached the 'mtlr rA'.
403 Extract the register from the instruction */
404 reg = (*code & 0x03e00000) >> 21;
405 --code;
406 /* ok, this is a lwz reg, offset (vtreg)
407 * it is emitted with:
408 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
410 soff = (*code & 0xffff);
411 offset = soff;
412 reg = (*code >> 16) & 0x1f;
413 g_assert (reg != ppc_r1);
414 /*g_print ("patching reg is %d\n", reg);*/
415 o = (gpointer)(gsize)r [reg];
416 break;
419 *displacement = offset;
420 return o;
423 #define MAX_ARCH_DELEGATE_PARAMS 7
425 static gpointer
426 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
428 guint8 *code, *start;
430 if (has_target) {
431 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
433 start = code = mono_global_codeman_reserve (size);
434 if (!aot)
435 code = mono_ppc_create_pre_code_ftnptr (code);
437 /* Replace the this argument with the target */
438 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
439 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
440 /* it's a function descriptor */
441 /* Can't use ldptr as it doesn't work with r0 */
442 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
443 #endif
444 ppc_mtctr (code, ppc_r0);
445 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
446 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
448 g_assert ((code - start) <= size);
450 mono_arch_flush_icache (start, size);
451 } else {
452 int size, i;
454 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
455 start = code = mono_global_codeman_reserve (size);
456 if (!aot)
457 code = mono_ppc_create_pre_code_ftnptr (code);
459 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
460 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
461 /* it's a function descriptor */
462 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
463 #endif
464 ppc_mtctr (code, ppc_r0);
465 /* slide down the arguments */
466 for (i = 0; i < param_count; ++i) {
467 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
469 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
471 g_assert ((code - start) <= size);
473 mono_arch_flush_icache (start, size);
476 if (code_len)
477 *code_len = code - start;
479 return start;
482 GSList*
483 mono_arch_get_delegate_invoke_impls (void)
485 GSList *res = NULL;
486 guint8 *code;
487 guint32 code_len;
488 int i;
490 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
491 res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len));
493 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
494 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
495 res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len));
498 return res;
501 gpointer
502 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
504 guint8 *code, *start;
506 /* FIXME: Support more cases */
507 if (MONO_TYPE_ISSTRUCT (sig->ret))
508 return NULL;
510 if (has_target) {
511 static guint8* cached = NULL;
513 if (cached)
514 return cached;
516 if (mono_aot_only)
517 start = mono_aot_get_named_code ("delegate_invoke_impl_has_target");
518 else
519 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
521 mono_memory_barrier ();
523 cached = start;
524 } else {
525 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
526 int i;
528 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
529 return NULL;
530 for (i = 0; i < sig->param_count; ++i)
531 if (!mono_is_regsize_var (sig->params [i]))
532 return NULL;
535 code = cache [sig->param_count];
536 if (code)
537 return code;
539 if (mono_aot_only) {
540 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
541 start = mono_aot_get_named_code (name);
542 g_free (name);
543 } else {
544 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
547 mono_memory_barrier ();
549 cache [sig->param_count] = start;
551 return start;
554 gpointer
555 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
557 mgreg_t *r = (mgreg_t*)regs;
559 /* FIXME: handle returning a struct */
560 if (MONO_TYPE_ISSTRUCT (sig->ret))
561 return (gpointer)(gsize)r [ppc_r4];
562 return (gpointer)(gsize)r [ppc_r3];
565 typedef struct {
566 long int type;
567 long int value;
568 } AuxVec;
570 #ifdef USE_ENVIRON_HACK
571 static AuxVec*
572 linux_find_auxv (int *count)
574 AuxVec *vec;
575 int c = 0;
576 char **result = __environ;
577 /* Scan over the env vector looking for the ending NULL */
578 for (; *result != NULL; ++result) {
580 /* Bump the pointer one more step, which should be the auxv. */
581 ++result;
582 vec = (AuxVec *)result;
583 if (vec->type != 22 /*AT_IGNOREPPC*/) {
584 *count = 0;
585 return NULL;
587 while (vec->type != 0 /*AT_NULL*/) {
588 vec++;
589 c++;
591 *count = c;
592 return (AuxVec *)result;
594 #endif
596 #define MAX_AUX_ENTRIES 128
598 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
599 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
601 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
603 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
604 #define ISA_64 0x40000000
606 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
607 #define ISA_MOVE_FPR_GPR 0x00000200
609 * Initialize the cpu to execute managed code.
611 void
612 mono_arch_cpu_init (void)
614 #ifdef __APPLE__
615 int mib [3];
616 size_t len;
617 mib [0] = CTL_HW;
618 mib [1] = HW_CACHELINE;
619 len = sizeof (cachelinesize);
620 if (sysctl (mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
621 perror ("sysctl");
622 cachelinesize = 128;
623 } else {
624 cachelineinc = cachelinesize;
626 #elif defined(__linux__)
627 AuxVec vec [MAX_AUX_ENTRIES];
628 int i, vec_entries = 0;
629 /* sadly this will work only with 2.6 kernels... */
630 FILE* f = fopen ("/proc/self/auxv", "rb");
631 if (f) {
632 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
633 fclose (f);
634 #ifdef USE_ENVIRON_HACK
635 } else {
636 AuxVec *evec = linux_find_auxv (&vec_entries);
637 if (vec_entries)
638 memcpy (&vec, evec, sizeof (AuxVec) * MIN (vec_entries, MAX_AUX_ENTRIES));
639 #endif
641 for (i = 0; i < vec_entries; i++) {
642 int type = vec [i].type;
643 if (type == 19) { /* AT_DCACHEBSIZE */
644 cachelinesize = vec [i].value;
645 continue;
646 } else if (type == 16) { /* AT_HWCAP */
647 if (vec [i].value & 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
648 cpu_hw_caps |= PPC_ICACHE_SNOOP;
649 if (vec [i].value & ISA_2X)
650 cpu_hw_caps |= PPC_ISA_2X;
651 if (vec [i].value & ISA_64)
652 cpu_hw_caps |= PPC_ISA_64;
653 if (vec [i].value & ISA_MOVE_FPR_GPR)
654 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
655 continue;
656 } else if (type == 15) { /* AT_PLATFORM */
657 const char *arch = (char*)vec [i].value;
658 if (strcmp (arch, "ppc970") == 0 ||
659 (strncmp (arch, "power", 5) == 0 && arch [5] >= '4' && arch [5] <= '7'))
660 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
661 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
662 continue;
665 #elif defined(G_COMPILER_CODEWARRIOR)
666 cachelinesize = 32;
667 cachelineinc = 32;
668 #elif defined(MONO_CROSS_COMPILE)
669 #else
670 //#error Need a way to get cache line size
671 #endif
672 if (!cachelinesize)
673 cachelinesize = 32;
674 if (!cachelineinc)
675 cachelineinc = cachelinesize;
677 if (mono_cpu_count () > 1)
678 cpu_hw_caps |= PPC_SMP_CAPABLE;
682 * Initialize architecture specific code.
684 void
685 mono_arch_init (void)
687 InitializeCriticalSection (&mini_arch_mutex);
689 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
690 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
691 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
695 * Cleanup architecture specific code.
697 void
698 mono_arch_cleanup (void)
700 DeleteCriticalSection (&mini_arch_mutex);
704 * This function returns the optimizations supported on this cpu.
706 guint32
707 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
709 guint32 opts = 0;
711 /* no ppc-specific optimizations yet */
712 *exclude_mask = 0;
713 return opts;
716 #ifdef __mono_ppc64__
717 #define CASE_PPC32(c)
718 #define CASE_PPC64(c) case c:
719 #else
720 #define CASE_PPC32(c) case c:
721 #define CASE_PPC64(c)
722 #endif
724 static gboolean
725 is_regsize_var (MonoType *t) {
726 if (t->byref)
727 return TRUE;
728 t = mini_type_get_underlying_type (NULL, t);
729 switch (t->type) {
730 case MONO_TYPE_I4:
731 case MONO_TYPE_U4:
732 CASE_PPC64 (MONO_TYPE_I8)
733 CASE_PPC64 (MONO_TYPE_U8)
734 case MONO_TYPE_I:
735 case MONO_TYPE_U:
736 case MONO_TYPE_PTR:
737 case MONO_TYPE_FNPTR:
738 return TRUE;
739 case MONO_TYPE_OBJECT:
740 case MONO_TYPE_STRING:
741 case MONO_TYPE_CLASS:
742 case MONO_TYPE_SZARRAY:
743 case MONO_TYPE_ARRAY:
744 return TRUE;
745 case MONO_TYPE_GENERICINST:
746 if (!mono_type_generic_inst_is_valuetype (t))
747 return TRUE;
748 return FALSE;
749 case MONO_TYPE_VALUETYPE:
750 return FALSE;
752 return FALSE;
755 #ifndef DISABLE_JIT
756 GList *
757 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
759 GList *vars = NULL;
760 int i;
762 for (i = 0; i < cfg->num_varinfo; i++) {
763 MonoInst *ins = cfg->varinfo [i];
764 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
766 /* unused vars */
767 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
768 continue;
770 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
771 continue;
773 /* we can only allocate 32 bit values */
774 if (is_regsize_var (ins->inst_vtype)) {
775 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
776 g_assert (i == vmv->idx);
777 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
781 return vars;
783 #endif /* ifndef DISABLE_JIT */
785 GList *
786 mono_arch_get_global_int_regs (MonoCompile *cfg)
788 GList *regs = NULL;
789 int i, top = 32;
790 if (cfg->frame_reg != ppc_sp)
791 top = 31;
792 /* ppc_r13 is used by the system on PPC EABI */
793 for (i = 14; i < top; ++i) {
795 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
796 * since the trampolines can clobber r11.
798 if (!(cfg->compile_aot && i == 29))
799 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
802 return regs;
806 * mono_arch_regalloc_cost:
808 * Return the cost, in number of memory references, of the action of
809 * allocating the variable VMV into a register during global register
810 * allocation.
812 guint32
813 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
815 /* FIXME: */
816 return 2;
819 void
820 mono_arch_flush_icache (guint8 *code, gint size)
822 #ifdef MONO_CROSS_COMPILE
823 #else
824 register guint8 *p;
825 guint8 *endp, *start;
827 p = start = code;
828 endp = p + size;
829 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
830 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
831 #if defined(G_COMPILER_CODEWARRIOR)
832 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
833 for (p = start; p < endp; p += cachelineinc) {
834 asm { dcbf 0, p };
836 } else {
837 for (p = start; p < endp; p += cachelineinc) {
838 asm { dcbst 0, p };
841 asm { sync };
842 p = code;
843 for (p = start; p < endp; p += cachelineinc) {
844 asm {
845 icbi 0, p
846 sync
849 asm {
850 sync
851 isync
853 #else
854 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
855 * The sync is required to insure that the store queue is completely empty.
856 * While the icbi performs no cache operations, icbi/isync is required to
857 * kill local prefetch.
859 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
860 asm ("sync");
861 asm ("icbi 0,%0;" : : "r"(code) : "memory");
862 asm ("isync");
863 return;
865 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
866 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
867 for (p = start; p < endp; p += cachelineinc) {
868 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
870 } else {
871 for (p = start; p < endp; p += cachelineinc) {
872 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
875 asm ("sync");
876 p = code;
877 for (p = start; p < endp; p += cachelineinc) {
878 /* for ISA2.0+ implementations we should not need any extra sync between the
879 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
880 * So I am not sure which chip had this problem but its not an issue on
881 * of the ISA V2 chips.
883 if (cpu_hw_caps & PPC_ISA_2X)
884 asm ("icbi 0,%0;" : : "r"(p) : "memory");
885 else
886 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
888 if (!(cpu_hw_caps & PPC_ISA_2X))
889 asm ("sync");
890 asm ("isync");
891 #endif
892 #endif
895 void
896 mono_arch_flush_register_windows (void)
900 #ifdef __APPLE__
901 #define ALWAYS_ON_STACK(s) s
902 #define FP_ALSO_IN_REG(s) s
903 #else
904 #ifdef __mono_ppc64__
905 #define ALWAYS_ON_STACK(s) s
906 #define FP_ALSO_IN_REG(s) s
907 #else
908 #define ALWAYS_ON_STACK(s)
909 #define FP_ALSO_IN_REG(s)
910 #endif
911 #define ALIGN_DOUBLES
912 #endif
914 enum {
915 RegTypeGeneral,
916 RegTypeBase,
917 RegTypeFP,
918 RegTypeStructByVal,
919 RegTypeStructByAddr
922 typedef struct {
923 gint32 offset;
924 guint32 vtsize; /* in param area */
925 guint8 reg;
926 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
927 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
928 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
929 guint8 bytes : 4; /* size in bytes - only valid for
930 RegTypeStructByVal if the struct fits
931 in one word, otherwise it's 0*/
932 } ArgInfo;
934 typedef struct {
935 int nargs;
936 guint32 stack_usage;
937 guint32 struct_ret;
938 ArgInfo ret;
939 ArgInfo sig_cookie;
940 ArgInfo args [1];
941 } CallInfo;
943 #define DEBUG(a)
945 static void inline
946 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
948 #ifdef __mono_ppc64__
949 g_assert (simple);
950 #endif
952 if (simple) {
953 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
954 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
955 ainfo->reg = ppc_sp; /* in the caller */
956 ainfo->regtype = RegTypeBase;
957 *stack_size += sizeof (gpointer);
958 } else {
959 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
960 ainfo->reg = *gr;
962 } else {
963 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
964 #ifdef ALIGN_DOUBLES
965 //*stack_size += (*stack_size % 8);
966 #endif
967 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
968 ainfo->reg = ppc_sp; /* in the caller */
969 ainfo->regtype = RegTypeBase;
970 *stack_size += 8;
971 } else {
972 #ifdef ALIGN_DOUBLES
973 if (!((*gr) & 1))
974 (*gr) ++;
975 #endif
976 ALWAYS_ON_STACK (*stack_size += 8);
977 ainfo->reg = *gr;
979 (*gr) ++;
981 (*gr) ++;
984 #if defined(__APPLE__) || defined(__mono_ppc64__)
985 static gboolean
986 has_only_a_r48_field (MonoClass *klass)
988 gpointer iter;
989 MonoClassField *f;
990 gboolean have_field = FALSE;
991 iter = NULL;
992 while ((f = mono_class_get_fields (klass, &iter))) {
993 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
994 if (have_field)
995 return FALSE;
996 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
997 have_field = TRUE;
998 else
999 return FALSE;
1002 return have_field;
1004 #endif
1006 static CallInfo*
1007 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
1009 guint i, fr, gr;
1010 int n = sig->hasthis + sig->param_count;
1011 MonoType *simpletype;
1012 guint32 stack_size = 0;
1013 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1015 fr = PPC_FIRST_FPARG_REG;
1016 gr = PPC_FIRST_ARG_REG;
1018 /* FIXME: handle returning a struct */
1019 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1020 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1021 cinfo->struct_ret = PPC_FIRST_ARG_REG;
1024 n = 0;
1025 if (sig->hasthis) {
1026 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1027 n++;
1029 DEBUG(printf("params: %d\n", sig->param_count));
1030 for (i = 0; i < sig->param_count; ++i) {
1031 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1032 /* Prevent implicit arguments and sig_cookie from
1033 being passed in registers */
1034 gr = PPC_LAST_ARG_REG + 1;
1035 /* FIXME: don't we have to set fr, too? */
1036 /* Emit the signature cookie just before the implicit arguments */
1037 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1039 DEBUG(printf("param %d: ", i));
1040 if (sig->params [i]->byref) {
1041 DEBUG(printf("byref\n"));
1042 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1043 n++;
1044 continue;
1046 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1047 switch (simpletype->type) {
1048 case MONO_TYPE_BOOLEAN:
1049 case MONO_TYPE_I1:
1050 case MONO_TYPE_U1:
1051 cinfo->args [n].size = 1;
1052 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1053 n++;
1054 break;
1055 case MONO_TYPE_CHAR:
1056 case MONO_TYPE_I2:
1057 case MONO_TYPE_U2:
1058 cinfo->args [n].size = 2;
1059 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1060 n++;
1061 break;
1062 case MONO_TYPE_I4:
1063 case MONO_TYPE_U4:
1064 cinfo->args [n].size = 4;
1065 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1066 n++;
1067 break;
1068 case MONO_TYPE_I:
1069 case MONO_TYPE_U:
1070 case MONO_TYPE_PTR:
1071 case MONO_TYPE_FNPTR:
1072 case MONO_TYPE_CLASS:
1073 case MONO_TYPE_OBJECT:
1074 case MONO_TYPE_STRING:
1075 case MONO_TYPE_SZARRAY:
1076 case MONO_TYPE_ARRAY:
1077 cinfo->args [n].size = sizeof (gpointer);
1078 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1079 n++;
1080 break;
1081 case MONO_TYPE_GENERICINST:
1082 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1083 cinfo->args [n].size = sizeof (gpointer);
1084 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1085 n++;
1086 break;
1088 /* Fall through */
1089 case MONO_TYPE_VALUETYPE:
1090 case MONO_TYPE_TYPEDBYREF: {
1091 gint size;
1092 MonoClass *klass;
1094 klass = mono_class_from_mono_type (sig->params [i]);
1095 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1096 size = sizeof (MonoTypedRef);
1097 else if (is_pinvoke)
1098 size = mono_class_native_size (klass, NULL);
1099 else
1100 size = mono_class_value_size (klass, NULL);
1102 #if defined(__APPLE__) || defined(__mono_ppc64__)
1103 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1104 cinfo->args [n].size = size;
1106 /* It was 7, now it is 8 in LinuxPPC */
1107 if (fr <= PPC_LAST_FPARG_REG) {
1108 cinfo->args [n].regtype = RegTypeFP;
1109 cinfo->args [n].reg = fr;
1110 fr ++;
1111 FP_ALSO_IN_REG (gr ++);
1112 if (size == 8)
1113 FP_ALSO_IN_REG (gr ++);
1114 ALWAYS_ON_STACK (stack_size += size);
1115 } else {
1116 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1117 cinfo->args [n].regtype = RegTypeBase;
1118 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1119 stack_size += 8;
1121 n++;
1122 break;
1124 #endif
1125 DEBUG(printf ("load %d bytes struct\n",
1126 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1128 #if PPC_PASS_STRUCTS_BY_VALUE
1130 int align_size = size;
1131 int nregs = 0;
1132 int rest = PPC_LAST_ARG_REG - gr + 1;
1133 int n_in_regs;
1135 align_size += (sizeof (gpointer) - 1);
1136 align_size &= ~(sizeof (gpointer) - 1);
1137 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1138 n_in_regs = MIN (rest, nregs);
1139 if (n_in_regs < 0)
1140 n_in_regs = 0;
1141 #ifdef __APPLE__
1142 /* FIXME: check this */
1143 if (size >= 3 && size % 4 != 0)
1144 n_in_regs = 0;
1145 #endif
1146 cinfo->args [n].regtype = RegTypeStructByVal;
1147 cinfo->args [n].vtregs = n_in_regs;
1148 cinfo->args [n].size = n_in_regs;
1149 cinfo->args [n].vtsize = nregs - n_in_regs;
1150 cinfo->args [n].reg = gr;
1152 #ifdef __mono_ppc64__
1153 if (nregs == 1 && is_pinvoke)
1154 cinfo->args [n].bytes = size;
1155 else
1156 #endif
1157 cinfo->args [n].bytes = 0;
1158 gr += n_in_regs;
1159 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1160 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1161 stack_size += nregs * sizeof (gpointer);
1163 #else
1164 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1165 cinfo->args [n].regtype = RegTypeStructByAddr;
1166 cinfo->args [n].vtsize = size;
1167 #endif
1168 n++;
1169 break;
1171 case MONO_TYPE_U8:
1172 case MONO_TYPE_I8:
1173 cinfo->args [n].size = 8;
1174 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1175 n++;
1176 break;
1177 case MONO_TYPE_R4:
1178 cinfo->args [n].size = 4;
1180 /* It was 7, now it is 8 in LinuxPPC */
1181 if (fr <= PPC_LAST_FPARG_REG) {
1182 cinfo->args [n].regtype = RegTypeFP;
1183 cinfo->args [n].reg = fr;
1184 fr ++;
1185 FP_ALSO_IN_REG (gr ++);
1186 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1187 } else {
1188 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1189 cinfo->args [n].regtype = RegTypeBase;
1190 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1191 stack_size += SIZEOF_REGISTER;
1193 n++;
1194 break;
1195 case MONO_TYPE_R8:
1196 cinfo->args [n].size = 8;
1197 /* It was 7, now it is 8 in LinuxPPC */
1198 if (fr <= PPC_LAST_FPARG_REG) {
1199 cinfo->args [n].regtype = RegTypeFP;
1200 cinfo->args [n].reg = fr;
1201 fr ++;
1202 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1203 ALWAYS_ON_STACK (stack_size += 8);
1204 } else {
1205 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1206 cinfo->args [n].regtype = RegTypeBase;
1207 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1208 stack_size += 8;
1210 n++;
1211 break;
1212 default:
1213 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1217 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1218 /* Prevent implicit arguments and sig_cookie from
1219 being passed in registers */
1220 gr = PPC_LAST_ARG_REG + 1;
1221 /* Emit the signature cookie just before the implicit arguments */
1222 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1226 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1227 switch (simpletype->type) {
1228 case MONO_TYPE_BOOLEAN:
1229 case MONO_TYPE_I1:
1230 case MONO_TYPE_U1:
1231 case MONO_TYPE_I2:
1232 case MONO_TYPE_U2:
1233 case MONO_TYPE_CHAR:
1234 case MONO_TYPE_I4:
1235 case MONO_TYPE_U4:
1236 case MONO_TYPE_I:
1237 case MONO_TYPE_U:
1238 case MONO_TYPE_PTR:
1239 case MONO_TYPE_FNPTR:
1240 case MONO_TYPE_CLASS:
1241 case MONO_TYPE_OBJECT:
1242 case MONO_TYPE_SZARRAY:
1243 case MONO_TYPE_ARRAY:
1244 case MONO_TYPE_STRING:
1245 cinfo->ret.reg = ppc_r3;
1246 break;
1247 case MONO_TYPE_U8:
1248 case MONO_TYPE_I8:
1249 cinfo->ret.reg = ppc_r3;
1250 break;
1251 case MONO_TYPE_R4:
1252 case MONO_TYPE_R8:
1253 cinfo->ret.reg = ppc_f1;
1254 cinfo->ret.regtype = RegTypeFP;
1255 break;
1256 case MONO_TYPE_GENERICINST:
1257 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1258 cinfo->ret.reg = ppc_r3;
1259 break;
1261 break;
1262 case MONO_TYPE_VALUETYPE:
1263 break;
1264 case MONO_TYPE_TYPEDBYREF:
1265 case MONO_TYPE_VOID:
1266 break;
1267 default:
1268 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1272 /* align stack size to 16 */
1273 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1274 stack_size = (stack_size + 15) & ~15;
1276 cinfo->stack_usage = stack_size;
1277 return cinfo;
1280 static void
1281 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1283 #if !PPC_PASS_STRUCTS_BY_VALUE
1284 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1285 int num_structs = 0;
1286 int i;
1288 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1289 return;
1291 for (i = 0; i < sig->param_count; ++i) {
1292 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1293 if (type->type == MONO_TYPE_VALUETYPE)
1294 num_structs++;
1297 if (num_structs) {
1298 cfg->tailcall_valuetype_addrs =
1299 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1300 for (i = 0; i < num_structs; ++i) {
1301 cfg->tailcall_valuetype_addrs [i] =
1302 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1303 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1306 #endif
1310 * Set var information according to the calling convention. ppc version.
1311 * The locals var stuff should most likely be split in another method.
1313 void
1314 mono_arch_allocate_vars (MonoCompile *m)
1316 MonoMethodSignature *sig;
1317 MonoMethodHeader *header;
1318 MonoInst *inst;
1319 int i, offset, size, align, curinst;
1320 int frame_reg = ppc_sp;
1321 gint32 *offsets;
1322 guint32 locals_stack_size, locals_stack_align;
1324 allocate_tailcall_valuetype_addrs (m);
1326 m->flags |= MONO_CFG_HAS_SPILLUP;
1328 /* allow room for the vararg method args: void* and long/double */
1329 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1330 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1331 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1332 * call convs needs to be handled this way.
1334 if (m->flags & MONO_CFG_HAS_VARARGS)
1335 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1336 /* gtk-sharp and other broken code will dllimport vararg functions even with
1337 * non-varargs signatures. Since there is little hope people will get this right
1338 * we assume they won't.
1340 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1341 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1343 header = m->header;
1346 * We use the frame register also for any method that has
1347 * exception clauses. This way, when the handlers are called,
1348 * the code will reference local variables using the frame reg instead of
1349 * the stack pointer: if we had to restore the stack pointer, we'd
1350 * corrupt the method frames that are already on the stack (since
1351 * filters get called before stack unwinding happens) when the filter
1352 * code would call any method (this also applies to finally etc.).
1354 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1355 frame_reg = ppc_r31;
1356 m->frame_reg = frame_reg;
1357 if (frame_reg != ppc_sp) {
1358 m->used_int_regs |= 1 << frame_reg;
1361 sig = mono_method_signature (m->method);
1363 offset = 0;
1364 curinst = 0;
1365 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1366 m->ret->opcode = OP_REGVAR;
1367 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1368 } else {
1369 /* FIXME: handle long values? */
1370 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1371 case MONO_TYPE_VOID:
1372 break;
1373 case MONO_TYPE_R4:
1374 case MONO_TYPE_R8:
1375 m->ret->opcode = OP_REGVAR;
1376 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1377 break;
1378 default:
1379 m->ret->opcode = OP_REGVAR;
1380 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1381 break;
1384 /* local vars are at a positive offset from the stack pointer */
1386 * also note that if the function uses alloca, we use ppc_r31
1387 * to point at the local variables.
1389 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1390 /* align the offset to 16 bytes: not sure this is needed here */
1391 //offset += 16 - 1;
1392 //offset &= ~(16 - 1);
1394 /* add parameter area size for called functions */
1395 offset += m->param_area;
1396 offset += 16 - 1;
1397 offset &= ~(16 - 1);
1399 /* allow room to save the return value */
1400 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1401 offset += 8;
1403 /* the MonoLMF structure is stored just below the stack pointer */
1405 #if 0
1406 /* this stuff should not be needed on ppc and the new jit,
1407 * because a call on ppc to the handlers doesn't change the
1408 * stack pointer and the jist doesn't manipulate the stack pointer
1409 * for operations involving valuetypes.
1411 /* reserve space to store the esp */
1412 offset += sizeof (gpointer);
1414 /* this is a global constant */
1415 mono_exc_esp_offset = offset;
1416 #endif
1418 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1419 offset += sizeof(gpointer) - 1;
1420 offset &= ~(sizeof(gpointer) - 1);
1422 m->vret_addr->opcode = OP_REGOFFSET;
1423 m->vret_addr->inst_basereg = frame_reg;
1424 m->vret_addr->inst_offset = offset;
1426 if (G_UNLIKELY (m->verbose_level > 1)) {
1427 printf ("vret_addr =");
1428 mono_print_ins (m->vret_addr);
1431 offset += sizeof(gpointer);
1434 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1435 if (locals_stack_align) {
1436 offset += (locals_stack_align - 1);
1437 offset &= ~(locals_stack_align - 1);
1439 for (i = m->locals_start; i < m->num_varinfo; i++) {
1440 if (offsets [i] != -1) {
1441 MonoInst *inst = m->varinfo [i];
1442 inst->opcode = OP_REGOFFSET;
1443 inst->inst_basereg = frame_reg;
1444 inst->inst_offset = offset + offsets [i];
1446 g_print ("allocating local %d (%s) to %d\n",
1447 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1451 offset += locals_stack_size;
1453 curinst = 0;
1454 if (sig->hasthis) {
1455 inst = m->args [curinst];
1456 if (inst->opcode != OP_REGVAR) {
1457 inst->opcode = OP_REGOFFSET;
1458 inst->inst_basereg = frame_reg;
1459 offset += sizeof (gpointer) - 1;
1460 offset &= ~(sizeof (gpointer) - 1);
1461 inst->inst_offset = offset;
1462 offset += sizeof (gpointer);
1464 curinst++;
1467 for (i = 0; i < sig->param_count; ++i) {
1468 inst = m->args [curinst];
1469 if (inst->opcode != OP_REGVAR) {
1470 inst->opcode = OP_REGOFFSET;
1471 inst->inst_basereg = frame_reg;
1472 if (sig->pinvoke) {
1473 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1474 inst->backend.is_pinvoke = 1;
1475 } else {
1476 size = mono_type_size (sig->params [i], &align);
1478 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1479 size = align = sizeof (gpointer);
1480 offset += align - 1;
1481 offset &= ~(align - 1);
1482 inst->inst_offset = offset;
1483 offset += size;
1485 curinst++;
1488 /* some storage for fp conversions */
1489 offset += 8 - 1;
1490 offset &= ~(8 - 1);
1491 m->arch.fp_conv_var_offset = offset;
1492 offset += 8;
1494 /* align the offset to 16 bytes */
1495 offset += 16 - 1;
1496 offset &= ~(16 - 1);
1498 /* change sign? */
1499 m->stack_offset = offset;
1501 if (sig->call_convention == MONO_CALL_VARARG) {
1502 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1504 m->sig_cookie = cinfo->sig_cookie.offset;
1506 g_free(cinfo);
1510 void
1511 mono_arch_create_vars (MonoCompile *cfg)
1513 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1515 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1516 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1520 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1521 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1524 static void
1525 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1527 int sig_reg = mono_alloc_ireg (cfg);
1529 /* FIXME: Add support for signature tokens to AOT */
1530 cfg->disable_aot = TRUE;
1532 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1533 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1534 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1537 void
1538 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1540 MonoInst *in, *ins;
1541 MonoMethodSignature *sig;
1542 int i, n;
1543 CallInfo *cinfo;
1545 sig = call->signature;
1546 n = sig->param_count + sig->hasthis;
1548 cinfo = calculate_sizes (sig, sig->pinvoke);
1550 for (i = 0; i < n; ++i) {
1551 ArgInfo *ainfo = cinfo->args + i;
1552 MonoType *t;
1554 if (i >= sig->hasthis)
1555 t = sig->params [i - sig->hasthis];
1556 else
1557 t = &mono_defaults.int_class->byval_arg;
1558 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1560 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1561 emit_sig_cookie (cfg, call, cinfo);
1563 in = call->args [i];
1565 if (ainfo->regtype == RegTypeGeneral) {
1566 #ifndef __mono_ppc64__
1567 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1568 MONO_INST_NEW (cfg, ins, OP_MOVE);
1569 ins->dreg = mono_alloc_ireg (cfg);
1570 ins->sreg1 = in->dreg + 1;
1571 MONO_ADD_INS (cfg->cbb, ins);
1572 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1574 MONO_INST_NEW (cfg, ins, OP_MOVE);
1575 ins->dreg = mono_alloc_ireg (cfg);
1576 ins->sreg1 = in->dreg + 2;
1577 MONO_ADD_INS (cfg->cbb, ins);
1578 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1579 } else
1580 #endif
1582 MONO_INST_NEW (cfg, ins, OP_MOVE);
1583 ins->dreg = mono_alloc_ireg (cfg);
1584 ins->sreg1 = in->dreg;
1585 MONO_ADD_INS (cfg->cbb, ins);
1587 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1589 } else if (ainfo->regtype == RegTypeStructByAddr) {
1590 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1591 ins->opcode = OP_OUTARG_VT;
1592 ins->sreg1 = in->dreg;
1593 ins->klass = in->klass;
1594 ins->inst_p0 = call;
1595 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1596 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1597 MONO_ADD_INS (cfg->cbb, ins);
1598 } else if (ainfo->regtype == RegTypeStructByVal) {
1599 /* this is further handled in mono_arch_emit_outarg_vt () */
1600 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1601 ins->opcode = OP_OUTARG_VT;
1602 ins->sreg1 = in->dreg;
1603 ins->klass = in->klass;
1604 ins->inst_p0 = call;
1605 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1606 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1607 MONO_ADD_INS (cfg->cbb, ins);
1608 } else if (ainfo->regtype == RegTypeBase) {
1609 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1610 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1611 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1612 if (t->type == MONO_TYPE_R8)
1613 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1614 else
1615 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1616 } else {
1617 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1619 } else if (ainfo->regtype == RegTypeFP) {
1620 if (t->type == MONO_TYPE_VALUETYPE) {
1621 /* this is further handled in mono_arch_emit_outarg_vt () */
1622 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1623 ins->opcode = OP_OUTARG_VT;
1624 ins->sreg1 = in->dreg;
1625 ins->klass = in->klass;
1626 ins->inst_p0 = call;
1627 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1628 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1629 MONO_ADD_INS (cfg->cbb, ins);
1631 cfg->flags |= MONO_CFG_HAS_FPOUT;
1632 } else {
1633 int dreg = mono_alloc_freg (cfg);
1635 if (ainfo->size == 4) {
1636 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1637 } else {
1638 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1639 ins->dreg = dreg;
1640 ins->sreg1 = in->dreg;
1641 MONO_ADD_INS (cfg->cbb, ins);
1644 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1645 cfg->flags |= MONO_CFG_HAS_FPOUT;
1647 } else {
1648 g_assert_not_reached ();
1652 /* Emit the signature cookie in the case that there is no
1653 additional argument */
1654 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1655 emit_sig_cookie (cfg, call, cinfo);
1657 if (cinfo->struct_ret) {
1658 MonoInst *vtarg;
1660 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1661 vtarg->sreg1 = call->vret_var->dreg;
1662 vtarg->dreg = mono_alloc_preg (cfg);
1663 MONO_ADD_INS (cfg->cbb, vtarg);
1665 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1668 call->stack_usage = cinfo->stack_usage;
1669 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1670 cfg->flags |= MONO_CFG_HAS_CALLS;
1672 g_free (cinfo);
1675 void
1676 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1678 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1679 ArgInfo *ainfo = ins->inst_p1;
1680 int ovf_size = ainfo->vtsize;
1681 int doffset = ainfo->offset;
1682 int i, soffset, dreg;
1684 if (ainfo->regtype == RegTypeStructByVal) {
1685 #ifdef __APPLE__
1686 guint32 size = 0;
1687 #endif
1688 soffset = 0;
1689 #ifdef __APPLE__
1691 * Darwin pinvokes needs some special handling for 1
1692 * and 2 byte arguments
1694 g_assert (ins->klass);
1695 if (call->signature->pinvoke)
1696 size = mono_class_native_size (ins->klass, NULL);
1697 if (size == 2 || size == 1) {
1698 int tmpr = mono_alloc_ireg (cfg);
1699 if (size == 1)
1700 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1701 else
1702 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1703 dreg = mono_alloc_ireg (cfg);
1704 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1705 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1706 } else
1707 #endif
1708 for (i = 0; i < ainfo->vtregs; ++i) {
1709 int antipadding = 0;
1710 if (ainfo->bytes) {
1711 g_assert (i == 0);
1712 antipadding = sizeof (gpointer) - ainfo->bytes;
1714 dreg = mono_alloc_ireg (cfg);
1715 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1716 if (antipadding)
1717 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1718 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1719 soffset += sizeof (gpointer);
1721 if (ovf_size != 0)
1722 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1723 } else if (ainfo->regtype == RegTypeFP) {
1724 int tmpr = mono_alloc_freg (cfg);
1725 if (ainfo->size == 4)
1726 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1727 else
1728 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1729 dreg = mono_alloc_freg (cfg);
1730 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1731 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1732 } else {
1733 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1734 MonoInst *load;
1735 guint32 size;
1737 /* FIXME: alignment? */
1738 if (call->signature->pinvoke) {
1739 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1740 vtcopy->backend.is_pinvoke = 1;
1741 } else {
1742 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1744 if (size > 0)
1745 g_assert (ovf_size > 0);
1747 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1748 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1750 if (ainfo->offset)
1751 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1752 else
1753 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1757 void
1758 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1760 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1761 mono_method_signature (method)->ret);
1763 if (!ret->byref) {
1764 #ifndef __mono_ppc64__
1765 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1766 MonoInst *ins;
1768 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1769 ins->sreg1 = val->dreg + 1;
1770 ins->sreg2 = val->dreg + 2;
1771 MONO_ADD_INS (cfg->cbb, ins);
1772 return;
1774 #endif
1775 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1776 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1777 return;
1780 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1783 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1784 gboolean
1785 mono_arch_is_inst_imm (gint64 imm)
1787 return TRUE;
1791 * Allow tracing to work with this interface (with an optional argument)
1794 void*
1795 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1797 guchar *code = p;
1799 ppc_load_ptr (code, ppc_r3, cfg->method);
1800 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1801 ppc_load_func (code, ppc_r0, func);
1802 ppc_mtlr (code, ppc_r0);
1803 ppc_blrl (code);
1804 return code;
1807 enum {
1808 SAVE_NONE,
1809 SAVE_STRUCT,
1810 SAVE_ONE,
1811 SAVE_TWO,
1812 SAVE_FP
1815 void*
1816 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1818 guchar *code = p;
1819 int save_mode = SAVE_NONE;
1820 int offset;
1821 MonoMethod *method = cfg->method;
1822 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1823 mono_method_signature (method)->ret)->type;
1824 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1825 save_offset += 15;
1826 save_offset &= ~15;
1828 offset = code - cfg->native_code;
1829 /* we need about 16 instructions */
1830 if (offset > (cfg->code_size - 16 * 4)) {
1831 cfg->code_size *= 2;
1832 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1833 code = cfg->native_code + offset;
1836 switch (rtype) {
1837 case MONO_TYPE_VOID:
1838 /* special case string .ctor icall */
1839 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1840 save_mode = SAVE_ONE;
1841 else
1842 save_mode = SAVE_NONE;
1843 break;
1844 #ifndef __mono_ppc64__
1845 case MONO_TYPE_I8:
1846 case MONO_TYPE_U8:
1847 save_mode = SAVE_TWO;
1848 break;
1849 #endif
1850 case MONO_TYPE_R4:
1851 case MONO_TYPE_R8:
1852 save_mode = SAVE_FP;
1853 break;
1854 case MONO_TYPE_VALUETYPE:
1855 save_mode = SAVE_STRUCT;
1856 break;
1857 default:
1858 save_mode = SAVE_ONE;
1859 break;
1862 switch (save_mode) {
1863 case SAVE_TWO:
1864 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1865 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1866 if (enable_arguments) {
1867 ppc_mr (code, ppc_r5, ppc_r4);
1868 ppc_mr (code, ppc_r4, ppc_r3);
1870 break;
1871 case SAVE_ONE:
1872 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1873 if (enable_arguments) {
1874 ppc_mr (code, ppc_r4, ppc_r3);
1876 break;
1877 case SAVE_FP:
1878 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1879 if (enable_arguments) {
1880 /* FIXME: what reg? */
1881 ppc_fmr (code, ppc_f3, ppc_f1);
1882 /* FIXME: use 8 byte load on PPC64 */
1883 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1884 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1886 break;
1887 case SAVE_STRUCT:
1888 if (enable_arguments) {
1889 /* FIXME: get the actual address */
1890 ppc_mr (code, ppc_r4, ppc_r3);
1892 break;
1893 case SAVE_NONE:
1894 default:
1895 break;
1898 ppc_load_ptr (code, ppc_r3, cfg->method);
1899 ppc_load_func (code, ppc_r0, func);
1900 ppc_mtlr (code, ppc_r0);
1901 ppc_blrl (code);
1903 switch (save_mode) {
1904 case SAVE_TWO:
1905 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1906 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1907 break;
1908 case SAVE_ONE:
1909 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1910 break;
1911 case SAVE_FP:
1912 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1913 break;
1914 case SAVE_NONE:
1915 default:
1916 break;
1919 return code;
1922 * Conditional branches have a small offset, so if it is likely overflowed,
1923 * we do a branch to the end of the method (uncond branches have much larger
1924 * offsets) where we perform the conditional and jump back unconditionally.
1925 * It's slightly slower, since we add two uncond branches, but it's very simple
1926 * with the current patch implementation and such large methods are likely not
1927 * going to be perf critical anyway.
1929 typedef struct {
1930 union {
1931 MonoBasicBlock *bb;
1932 const char *exception;
1933 } data;
1934 guint32 ip_offset;
1935 guint16 b0_cond;
1936 guint16 b1_cond;
1937 } MonoOvfJump;
1939 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1940 if (0 && ins->inst_true_bb->native_offset) { \
1941 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1942 } else { \
1943 int br_disp = ins->inst_true_bb->max_offset - offset; \
1944 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1945 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1946 ovfj->data.bb = ins->inst_true_bb; \
1947 ovfj->ip_offset = 0; \
1948 ovfj->b0_cond = (b0); \
1949 ovfj->b1_cond = (b1); \
1950 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1951 ppc_b (code, 0); \
1952 } else { \
1953 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1954 ppc_bc (code, (b0), (b1), 0); \
1958 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1960 /* emit an exception if condition is fail
1962 * We assign the extra code used to throw the implicit exceptions
1963 * to cfg->bb_exit as far as the big branch handling is concerned
1965 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1966 do { \
1967 int br_disp = cfg->bb_exit->max_offset - offset; \
1968 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1969 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1970 ovfj->data.exception = (exc_name); \
1971 ovfj->ip_offset = code - cfg->native_code; \
1972 ovfj->b0_cond = (b0); \
1973 ovfj->b1_cond = (b1); \
1974 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1975 ppc_bl (code, 0); \
1976 cfg->bb_exit->max_offset += 24; \
1977 } else { \
1978 mono_add_patch_info (cfg, code - cfg->native_code, \
1979 MONO_PATCH_INFO_EXC, exc_name); \
1980 ppc_bcl (code, (b0), (b1), 0); \
1982 } while (0);
1984 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1986 void
1987 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1991 static int
1992 normalize_opcode (int opcode)
1994 switch (opcode) {
1995 #ifndef __mono_ilp32__
1996 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1997 return OP_LOAD_MEMBASE;
1998 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1999 return OP_LOAD_MEMINDEX;
2000 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2001 return OP_STORE_MEMBASE_REG;
2002 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2003 return OP_STORE_MEMBASE_IMM;
2004 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2005 return OP_STORE_MEMINDEX;
2006 #endif
2007 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2008 return OP_SHR_IMM;
2009 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2010 return OP_SHR_UN_IMM;
2011 default:
2012 return opcode;
2016 void
2017 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2019 MonoInst *ins, *n, *last_ins = NULL;
2021 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2022 switch (normalize_opcode (ins->opcode)) {
2023 case OP_MUL_IMM:
2024 /* remove unnecessary multiplication with 1 */
2025 if (ins->inst_imm == 1) {
2026 if (ins->dreg != ins->sreg1) {
2027 ins->opcode = OP_MOVE;
2028 } else {
2029 MONO_DELETE_INS (bb, ins);
2030 continue;
2032 } else {
2033 int power2 = mono_is_power_of_two (ins->inst_imm);
2034 if (power2 > 0) {
2035 ins->opcode = OP_SHL_IMM;
2036 ins->inst_imm = power2;
2039 break;
2040 case OP_LOAD_MEMBASE:
2042 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2043 * OP_LOAD_MEMBASE offset(basereg), reg
2045 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2046 ins->inst_basereg == last_ins->inst_destbasereg &&
2047 ins->inst_offset == last_ins->inst_offset) {
2048 if (ins->dreg == last_ins->sreg1) {
2049 MONO_DELETE_INS (bb, ins);
2050 continue;
2051 } else {
2052 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2053 ins->opcode = OP_MOVE;
2054 ins->sreg1 = last_ins->sreg1;
2058 * Note: reg1 must be different from the basereg in the second load
2059 * OP_LOAD_MEMBASE offset(basereg), reg1
2060 * OP_LOAD_MEMBASE offset(basereg), reg2
2061 * -->
2062 * OP_LOAD_MEMBASE offset(basereg), reg1
2063 * OP_MOVE reg1, reg2
2065 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2066 ins->inst_basereg != last_ins->dreg &&
2067 ins->inst_basereg == last_ins->inst_basereg &&
2068 ins->inst_offset == last_ins->inst_offset) {
2070 if (ins->dreg == last_ins->dreg) {
2071 MONO_DELETE_INS (bb, ins);
2072 continue;
2073 } else {
2074 ins->opcode = OP_MOVE;
2075 ins->sreg1 = last_ins->dreg;
2078 //g_assert_not_reached ();
2080 #if 0
2082 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2083 * OP_LOAD_MEMBASE offset(basereg), reg
2084 * -->
2085 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2086 * OP_ICONST reg, imm
2088 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2089 ins->inst_basereg == last_ins->inst_destbasereg &&
2090 ins->inst_offset == last_ins->inst_offset) {
2091 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2092 ins->opcode = OP_ICONST;
2093 ins->inst_c0 = last_ins->inst_imm;
2094 g_assert_not_reached (); // check this rule
2095 #endif
2097 break;
2098 case OP_LOADU1_MEMBASE:
2099 case OP_LOADI1_MEMBASE:
2100 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2101 ins->inst_basereg == last_ins->inst_destbasereg &&
2102 ins->inst_offset == last_ins->inst_offset) {
2103 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2104 ins->sreg1 = last_ins->sreg1;
2106 break;
2107 case OP_LOADU2_MEMBASE:
2108 case OP_LOADI2_MEMBASE:
2109 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2110 ins->inst_basereg == last_ins->inst_destbasereg &&
2111 ins->inst_offset == last_ins->inst_offset) {
2112 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2113 ins->sreg1 = last_ins->sreg1;
2115 break;
2116 #ifdef __mono_ppc64__
2117 case OP_LOADU4_MEMBASE:
2118 case OP_LOADI4_MEMBASE:
2119 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2120 ins->inst_basereg == last_ins->inst_destbasereg &&
2121 ins->inst_offset == last_ins->inst_offset) {
2122 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2123 ins->sreg1 = last_ins->sreg1;
2125 break;
2126 #endif
2127 case OP_MOVE:
2128 ins->opcode = OP_MOVE;
2130 * OP_MOVE reg, reg
2132 if (ins->dreg == ins->sreg1) {
2133 MONO_DELETE_INS (bb, ins);
2134 continue;
2137 * OP_MOVE sreg, dreg
2138 * OP_MOVE dreg, sreg
2140 if (last_ins && last_ins->opcode == OP_MOVE &&
2141 ins->sreg1 == last_ins->dreg &&
2142 ins->dreg == last_ins->sreg1) {
2143 MONO_DELETE_INS (bb, ins);
2144 continue;
2146 break;
2148 last_ins = ins;
2149 ins = ins->next;
2151 bb->last_ins = last_ins;
2154 void
2155 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2157 switch (ins->opcode) {
2158 case OP_ICONV_TO_R_UN: {
2159 #if G_BYTE_ORDER == G_BIG_ENDIAN
2160 static const guint64 adjust_val = 0x4330000000000000ULL;
2161 #else
2162 static const guint64 adjust_val = 0x0000000000003043ULL;
2163 #endif
2164 int msw_reg = mono_alloc_ireg (cfg);
2165 int adj_reg = mono_alloc_freg (cfg);
2166 int tmp_reg = mono_alloc_freg (cfg);
2167 int basereg = ppc_sp;
2168 int offset = -8;
2169 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2170 if (!ppc_is_imm16 (offset + 4)) {
2171 basereg = mono_alloc_ireg (cfg);
2172 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2174 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2175 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2176 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2177 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2178 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2179 ins->opcode = OP_NOP;
2180 break;
2182 #ifndef __mono_ppc64__
2183 case OP_ICONV_TO_R4:
2184 case OP_ICONV_TO_R8: {
2185 /* If we have a PPC_FEATURE_64 machine we can avoid
2186 this and use the fcfid instruction. Otherwise
2187 on an old 32-bit chip and we have to do this the
2188 hard way. */
2189 if (!(cpu_hw_caps & PPC_ISA_64)) {
2190 /* FIXME: change precision for CEE_CONV_R4 */
2191 static const guint64 adjust_val = 0x4330000080000000ULL;
2192 int msw_reg = mono_alloc_ireg (cfg);
2193 int xored = mono_alloc_ireg (cfg);
2194 int adj_reg = mono_alloc_freg (cfg);
2195 int tmp_reg = mono_alloc_freg (cfg);
2196 int basereg = ppc_sp;
2197 int offset = -8;
2198 if (!ppc_is_imm16 (offset + 4)) {
2199 basereg = mono_alloc_ireg (cfg);
2200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2202 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2203 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2204 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2205 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2206 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2207 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2208 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2209 if (ins->opcode == OP_ICONV_TO_R4)
2210 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2211 ins->opcode = OP_NOP;
2213 break;
2215 #endif
2216 case OP_CKFINITE: {
2217 int msw_reg = mono_alloc_ireg (cfg);
2218 int basereg = ppc_sp;
2219 int offset = -8;
2220 if (!ppc_is_imm16 (offset + 4)) {
2221 basereg = mono_alloc_ireg (cfg);
2222 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2224 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2225 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2226 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2227 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2228 ins->opcode = OP_NOP;
2229 break;
2231 #ifdef __mono_ppc64__
2232 case OP_IADD_OVF:
2233 case OP_IADD_OVF_UN:
2234 case OP_ISUB_OVF: {
2235 int shifted1_reg = mono_alloc_ireg (cfg);
2236 int shifted2_reg = mono_alloc_ireg (cfg);
2237 int result_shifted_reg = mono_alloc_ireg (cfg);
2239 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2240 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2241 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2242 if (ins->opcode == OP_IADD_OVF_UN)
2243 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2244 else
2245 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2246 ins->opcode = OP_NOP;
2248 #endif
2252 void
2253 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2255 switch (ins->opcode) {
2256 case OP_LADD_OVF:
2257 /* ADC sets the condition code */
2258 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2259 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2260 NULLIFY_INS (ins);
2261 break;
2262 case OP_LADD_OVF_UN:
2263 /* ADC sets the condition code */
2264 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2265 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2266 NULLIFY_INS (ins);
2267 break;
2268 case OP_LSUB_OVF:
2269 /* SBB sets the condition code */
2270 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2271 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2272 NULLIFY_INS (ins);
2273 break;
2274 case OP_LSUB_OVF_UN:
2275 /* SBB sets the condition code */
2276 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2277 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2278 NULLIFY_INS (ins);
2279 break;
2280 case OP_LNEG:
2281 /* This is the old version from inssel-long32.brg */
2282 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 1, ins->sreg1 + 1);
2283 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 2, ins->sreg1 + 2);
2284 /* ADC sets the condition codes */
2285 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 1, ins->dreg + 1, 1);
2286 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->dreg + 2, 0);
2287 NULLIFY_INS (ins);
2288 break;
2289 default:
2290 break;
2295 * the branch_b0_table should maintain the order of these
2296 * opcodes.
2297 case CEE_BEQ:
2298 case CEE_BGE:
2299 case CEE_BGT:
2300 case CEE_BLE:
2301 case CEE_BLT:
2302 case CEE_BNE_UN:
2303 case CEE_BGE_UN:
2304 case CEE_BGT_UN:
2305 case CEE_BLE_UN:
2306 case CEE_BLT_UN:
2308 static const guchar
2309 branch_b0_table [] = {
2310 PPC_BR_TRUE,
2311 PPC_BR_FALSE,
2312 PPC_BR_TRUE,
2313 PPC_BR_FALSE,
2314 PPC_BR_TRUE,
2316 PPC_BR_FALSE,
2317 PPC_BR_FALSE,
2318 PPC_BR_TRUE,
2319 PPC_BR_FALSE,
2320 PPC_BR_TRUE
2323 static const guchar
2324 branch_b1_table [] = {
2325 PPC_BR_EQ,
2326 PPC_BR_LT,
2327 PPC_BR_GT,
2328 PPC_BR_GT,
2329 PPC_BR_LT,
2331 PPC_BR_EQ,
2332 PPC_BR_LT,
2333 PPC_BR_GT,
2334 PPC_BR_GT,
2335 PPC_BR_LT
2338 #define NEW_INS(cfg,dest,op) do { \
2339 MONO_INST_NEW((cfg), (dest), (op)); \
2340 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2341 } while (0)
2343 static int
2344 map_to_reg_reg_op (int op)
2346 switch (op) {
2347 case OP_ADD_IMM:
2348 return OP_IADD;
2349 case OP_SUB_IMM:
2350 return OP_ISUB;
2351 case OP_AND_IMM:
2352 return OP_IAND;
2353 case OP_COMPARE_IMM:
2354 return OP_COMPARE;
2355 case OP_ICOMPARE_IMM:
2356 return OP_ICOMPARE;
2357 case OP_LCOMPARE_IMM:
2358 return OP_LCOMPARE;
2359 case OP_ADDCC_IMM:
2360 return OP_IADDCC;
2361 case OP_ADC_IMM:
2362 return OP_IADC;
2363 case OP_SUBCC_IMM:
2364 return OP_ISUBCC;
2365 case OP_SBB_IMM:
2366 return OP_ISBB;
2367 case OP_OR_IMM:
2368 return OP_IOR;
2369 case OP_XOR_IMM:
2370 return OP_IXOR;
2371 case OP_MUL_IMM:
2372 return OP_IMUL;
2373 case OP_LOAD_MEMBASE:
2374 return OP_LOAD_MEMINDEX;
2375 case OP_LOADI4_MEMBASE:
2376 return OP_LOADI4_MEMINDEX;
2377 case OP_LOADU4_MEMBASE:
2378 return OP_LOADU4_MEMINDEX;
2379 case OP_LOADI8_MEMBASE:
2380 return OP_LOADI8_MEMINDEX;
2381 case OP_LOADU1_MEMBASE:
2382 return OP_LOADU1_MEMINDEX;
2383 case OP_LOADI2_MEMBASE:
2384 return OP_LOADI2_MEMINDEX;
2385 case OP_LOADU2_MEMBASE:
2386 return OP_LOADU2_MEMINDEX;
2387 case OP_LOADI1_MEMBASE:
2388 return OP_LOADI1_MEMINDEX;
2389 case OP_LOADR4_MEMBASE:
2390 return OP_LOADR4_MEMINDEX;
2391 case OP_LOADR8_MEMBASE:
2392 return OP_LOADR8_MEMINDEX;
2393 case OP_STOREI1_MEMBASE_REG:
2394 return OP_STOREI1_MEMINDEX;
2395 case OP_STOREI2_MEMBASE_REG:
2396 return OP_STOREI2_MEMINDEX;
2397 case OP_STOREI4_MEMBASE_REG:
2398 return OP_STOREI4_MEMINDEX;
2399 case OP_STOREI8_MEMBASE_REG:
2400 return OP_STOREI8_MEMINDEX;
2401 case OP_STORE_MEMBASE_REG:
2402 return OP_STORE_MEMINDEX;
2403 case OP_STORER4_MEMBASE_REG:
2404 return OP_STORER4_MEMINDEX;
2405 case OP_STORER8_MEMBASE_REG:
2406 return OP_STORER8_MEMINDEX;
2407 case OP_STORE_MEMBASE_IMM:
2408 return OP_STORE_MEMBASE_REG;
2409 case OP_STOREI1_MEMBASE_IMM:
2410 return OP_STOREI1_MEMBASE_REG;
2411 case OP_STOREI2_MEMBASE_IMM:
2412 return OP_STOREI2_MEMBASE_REG;
2413 case OP_STOREI4_MEMBASE_IMM:
2414 return OP_STOREI4_MEMBASE_REG;
2415 case OP_STOREI8_MEMBASE_IMM:
2416 return OP_STOREI8_MEMBASE_REG;
2418 return mono_op_imm_to_op (op);
2421 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2423 #define compare_opcode_is_unsigned(opcode) \
2424 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2425 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2426 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2427 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2428 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2429 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2430 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2431 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2434 * Remove from the instruction list the instructions that can't be
2435 * represented with very simple instructions with no register
2436 * requirements.
2438 void
2439 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2441 MonoInst *ins, *next, *temp, *last_ins = NULL;
2442 int imm;
2444 MONO_BB_FOR_EACH_INS (bb, ins) {
2445 loop_start:
2446 switch (ins->opcode) {
2447 case OP_IDIV_UN_IMM:
2448 case OP_IDIV_IMM:
2449 case OP_IREM_IMM:
2450 case OP_IREM_UN_IMM:
2451 NEW_INS (cfg, temp, OP_ICONST);
2452 temp->inst_c0 = ins->inst_imm;
2453 temp->dreg = mono_alloc_ireg (cfg);
2454 ins->sreg2 = temp->dreg;
2455 if (ins->opcode == OP_IDIV_IMM)
2456 ins->opcode = OP_IDIV;
2457 else if (ins->opcode == OP_IREM_IMM)
2458 ins->opcode = OP_IREM;
2459 else if (ins->opcode == OP_IDIV_UN_IMM)
2460 ins->opcode = OP_IDIV_UN;
2461 else if (ins->opcode == OP_IREM_UN_IMM)
2462 ins->opcode = OP_IREM_UN;
2463 last_ins = temp;
2464 /* handle rem separately */
2465 goto loop_start;
2466 case OP_IREM:
2467 case OP_IREM_UN:
2468 CASE_PPC64 (OP_LREM)
2469 CASE_PPC64 (OP_LREM_UN) {
2470 MonoInst *mul;
2471 /* we change a rem dest, src1, src2 to
2472 * div temp1, src1, src2
2473 * mul temp2, temp1, src2
2474 * sub dest, src1, temp2
2476 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2477 NEW_INS (cfg, mul, OP_IMUL);
2478 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2479 ins->opcode = OP_ISUB;
2480 } else {
2481 NEW_INS (cfg, mul, OP_LMUL);
2482 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2483 ins->opcode = OP_LSUB;
2485 temp->sreg1 = ins->sreg1;
2486 temp->sreg2 = ins->sreg2;
2487 temp->dreg = mono_alloc_ireg (cfg);
2488 mul->sreg1 = temp->dreg;
2489 mul->sreg2 = ins->sreg2;
2490 mul->dreg = mono_alloc_ireg (cfg);
2491 ins->sreg2 = mul->dreg;
2492 break;
2494 case OP_IADD_IMM:
2495 CASE_PPC64 (OP_LADD_IMM)
2496 case OP_ADD_IMM:
2497 case OP_ADDCC_IMM:
2498 if (!ppc_is_imm16 (ins->inst_imm)) {
2499 NEW_INS (cfg, temp, OP_ICONST);
2500 temp->inst_c0 = ins->inst_imm;
2501 temp->dreg = mono_alloc_ireg (cfg);
2502 ins->sreg2 = temp->dreg;
2503 ins->opcode = map_to_reg_reg_op (ins->opcode);
2505 break;
2506 case OP_ISUB_IMM:
2507 CASE_PPC64 (OP_LSUB_IMM)
2508 case OP_SUB_IMM:
2509 if (!ppc_is_imm16 (-ins->inst_imm)) {
2510 NEW_INS (cfg, temp, OP_ICONST);
2511 temp->inst_c0 = ins->inst_imm;
2512 temp->dreg = mono_alloc_ireg (cfg);
2513 ins->sreg2 = temp->dreg;
2514 ins->opcode = map_to_reg_reg_op (ins->opcode);
2516 break;
2517 case OP_IAND_IMM:
2518 case OP_IOR_IMM:
2519 case OP_IXOR_IMM:
2520 case OP_LAND_IMM:
2521 case OP_LOR_IMM:
2522 case OP_LXOR_IMM:
2523 case OP_AND_IMM:
2524 case OP_OR_IMM:
2525 case OP_XOR_IMM: {
2526 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2527 #ifdef __mono_ppc64__
2528 if (ins->inst_imm & 0xffffffff00000000ULL)
2529 is_imm = TRUE;
2530 #endif
2531 if (is_imm) {
2532 NEW_INS (cfg, temp, OP_ICONST);
2533 temp->inst_c0 = ins->inst_imm;
2534 temp->dreg = mono_alloc_ireg (cfg);
2535 ins->sreg2 = temp->dreg;
2536 ins->opcode = map_to_reg_reg_op (ins->opcode);
2538 break;
2540 case OP_ISBB_IMM:
2541 case OP_IADC_IMM:
2542 case OP_SBB_IMM:
2543 case OP_SUBCC_IMM:
2544 case OP_ADC_IMM:
2545 NEW_INS (cfg, temp, OP_ICONST);
2546 temp->inst_c0 = ins->inst_imm;
2547 temp->dreg = mono_alloc_ireg (cfg);
2548 ins->sreg2 = temp->dreg;
2549 ins->opcode = map_to_reg_reg_op (ins->opcode);
2550 break;
2551 case OP_COMPARE_IMM:
2552 case OP_ICOMPARE_IMM:
2553 CASE_PPC64 (OP_LCOMPARE_IMM)
2554 next = ins->next;
2555 /* Branch opts can eliminate the branch */
2556 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2557 ins->opcode = OP_NOP;
2558 break;
2560 g_assert(next);
2561 if (compare_opcode_is_unsigned (next->opcode)) {
2562 if (!ppc_is_uimm16 (ins->inst_imm)) {
2563 NEW_INS (cfg, temp, OP_ICONST);
2564 temp->inst_c0 = ins->inst_imm;
2565 temp->dreg = mono_alloc_ireg (cfg);
2566 ins->sreg2 = temp->dreg;
2567 ins->opcode = map_to_reg_reg_op (ins->opcode);
2569 } else {
2570 if (!ppc_is_imm16 (ins->inst_imm)) {
2571 NEW_INS (cfg, temp, OP_ICONST);
2572 temp->inst_c0 = ins->inst_imm;
2573 temp->dreg = mono_alloc_ireg (cfg);
2574 ins->sreg2 = temp->dreg;
2575 ins->opcode = map_to_reg_reg_op (ins->opcode);
2578 break;
2579 case OP_IMUL_IMM:
2580 case OP_MUL_IMM:
2581 if (ins->inst_imm == 1) {
2582 ins->opcode = OP_MOVE;
2583 break;
2585 if (ins->inst_imm == 0) {
2586 ins->opcode = OP_ICONST;
2587 ins->inst_c0 = 0;
2588 break;
2590 imm = mono_is_power_of_two (ins->inst_imm);
2591 if (imm > 0) {
2592 ins->opcode = OP_SHL_IMM;
2593 ins->inst_imm = imm;
2594 break;
2596 if (!ppc_is_imm16 (ins->inst_imm)) {
2597 NEW_INS (cfg, temp, OP_ICONST);
2598 temp->inst_c0 = ins->inst_imm;
2599 temp->dreg = mono_alloc_ireg (cfg);
2600 ins->sreg2 = temp->dreg;
2601 ins->opcode = map_to_reg_reg_op (ins->opcode);
2603 break;
2604 case OP_LOCALLOC_IMM:
2605 NEW_INS (cfg, temp, OP_ICONST);
2606 temp->inst_c0 = ins->inst_imm;
2607 temp->dreg = mono_alloc_ireg (cfg);
2608 ins->sreg1 = temp->dreg;
2609 ins->opcode = OP_LOCALLOC;
2610 break;
2611 case OP_LOAD_MEMBASE:
2612 case OP_LOADI4_MEMBASE:
2613 CASE_PPC64 (OP_LOADI8_MEMBASE)
2614 case OP_LOADU4_MEMBASE:
2615 case OP_LOADI2_MEMBASE:
2616 case OP_LOADU2_MEMBASE:
2617 case OP_LOADI1_MEMBASE:
2618 case OP_LOADU1_MEMBASE:
2619 case OP_LOADR4_MEMBASE:
2620 case OP_LOADR8_MEMBASE:
2621 case OP_STORE_MEMBASE_REG:
2622 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2623 case OP_STOREI4_MEMBASE_REG:
2624 case OP_STOREI2_MEMBASE_REG:
2625 case OP_STOREI1_MEMBASE_REG:
2626 case OP_STORER4_MEMBASE_REG:
2627 case OP_STORER8_MEMBASE_REG:
2628 /* we can do two things: load the immed in a register
2629 * and use an indexed load, or see if the immed can be
2630 * represented as an ad_imm + a load with a smaller offset
2631 * that fits. We just do the first for now, optimize later.
2633 if (ppc_is_imm16 (ins->inst_offset))
2634 break;
2635 NEW_INS (cfg, temp, OP_ICONST);
2636 temp->inst_c0 = ins->inst_offset;
2637 temp->dreg = mono_alloc_ireg (cfg);
2638 ins->sreg2 = temp->dreg;
2639 ins->opcode = map_to_reg_reg_op (ins->opcode);
2640 break;
2641 case OP_STORE_MEMBASE_IMM:
2642 case OP_STOREI1_MEMBASE_IMM:
2643 case OP_STOREI2_MEMBASE_IMM:
2644 case OP_STOREI4_MEMBASE_IMM:
2645 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2646 NEW_INS (cfg, temp, OP_ICONST);
2647 temp->inst_c0 = ins->inst_imm;
2648 temp->dreg = mono_alloc_ireg (cfg);
2649 ins->sreg1 = temp->dreg;
2650 ins->opcode = map_to_reg_reg_op (ins->opcode);
2651 last_ins = temp;
2652 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2653 case OP_R8CONST:
2654 case OP_R4CONST:
2655 if (cfg->compile_aot) {
2656 /* Keep these in the aot case */
2657 break;
2659 NEW_INS (cfg, temp, OP_ICONST);
2660 temp->inst_c0 = (gulong)ins->inst_p0;
2661 temp->dreg = mono_alloc_ireg (cfg);
2662 ins->inst_basereg = temp->dreg;
2663 ins->inst_offset = 0;
2664 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2665 last_ins = temp;
2666 /* make it handle the possibly big ins->inst_offset
2667 * later optimize to use lis + load_membase
2669 goto loop_start;
2671 last_ins = ins;
2673 bb->last_ins = last_ins;
2674 bb->max_vreg = cfg->next_vreg;
2677 static guchar*
2678 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2680 long offset = cfg->arch.fp_conv_var_offset;
2681 long sub_offset;
2682 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2683 #ifdef __mono_ppc64__
2684 if (size == 8) {
2685 ppc_fctidz (code, ppc_f0, sreg);
2686 sub_offset = 0;
2687 } else
2688 #endif
2690 ppc_fctiwz (code, ppc_f0, sreg);
2691 sub_offset = 4;
2693 if (ppc_is_imm16 (offset + sub_offset)) {
2694 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2695 if (size == 8)
2696 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2697 else
2698 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2699 } else {
2700 ppc_load (code, dreg, offset);
2701 ppc_add (code, dreg, dreg, cfg->frame_reg);
2702 ppc_stfd (code, ppc_f0, 0, dreg);
2703 if (size == 8)
2704 ppc_ldr (code, dreg, sub_offset, dreg);
2705 else
2706 ppc_lwz (code, dreg, sub_offset, dreg);
2708 if (!is_signed) {
2709 if (size == 1)
2710 ppc_andid (code, dreg, dreg, 0xff);
2711 else if (size == 2)
2712 ppc_andid (code, dreg, dreg, 0xffff);
2713 #ifdef __mono_ppc64__
2714 else if (size == 4)
2715 ppc_clrldi (code, dreg, dreg, 32);
2716 #endif
2717 } else {
2718 if (size == 1)
2719 ppc_extsb (code, dreg, dreg);
2720 else if (size == 2)
2721 ppc_extsh (code, dreg, dreg);
2722 #ifdef __mono_ppc64__
2723 else if (size == 4)
2724 ppc_extsw (code, dreg, dreg);
2725 #endif
2727 return code;
2730 typedef struct {
2731 guchar *code;
2732 const guchar *target;
2733 int absolute;
2734 int found;
2735 } PatchData;
2737 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2739 static int
2740 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2741 #ifdef __mono_ppc64__
2742 g_assert_not_reached ();
2743 #else
2744 PatchData *pdata = (PatchData*)user_data;
2745 guchar *code = data;
2746 guint32 *thunks = data;
2747 guint32 *endthunks = (guint32*)(code + bsize);
2748 guint32 load [2];
2749 guchar *templ;
2750 int count = 0;
2751 int difflow, diffhigh;
2753 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2754 difflow = (char*)pdata->code - (char*)thunks;
2755 diffhigh = (char*)pdata->code - (char*)endthunks;
2756 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2757 return 0;
2759 templ = (guchar*)load;
2760 ppc_load_sequence (templ, ppc_r0, pdata->target);
2762 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2763 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2764 while (thunks < endthunks) {
2765 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2766 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2767 ppc_patch (pdata->code, (guchar*)thunks);
2768 pdata->found = 1;
2770 static int num_thunks = 0;
2771 num_thunks++;
2772 if ((num_thunks % 20) == 0)
2773 g_print ("num_thunks lookup: %d\n", num_thunks);
2775 return 1;
2776 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2777 /* found a free slot instead: emit thunk */
2778 code = (guchar*)thunks;
2779 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2780 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2781 ppc_mtctr (code, ppc_r0);
2782 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2783 mono_arch_flush_icache ((guchar*)thunks, 16);
2785 ppc_patch (pdata->code, (guchar*)thunks);
2786 pdata->found = 1;
2788 static int num_thunks = 0;
2789 num_thunks++;
2790 if ((num_thunks % 20) == 0)
2791 g_print ("num_thunks: %d\n", num_thunks);
2793 return 1;
2795 /* skip 16 bytes, the size of the thunk */
2796 thunks += 4;
2797 count++;
2799 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2801 #endif
2802 return 0;
2805 static void
2806 handle_thunk (int absolute, guchar *code, const guchar *target) {
2807 MonoDomain *domain = mono_domain_get ();
2808 PatchData pdata;
2810 pdata.code = code;
2811 pdata.target = target;
2812 pdata.absolute = absolute;
2813 pdata.found = 0;
2815 mono_domain_lock (domain);
2816 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2818 if (!pdata.found) {
2819 /* this uses the first available slot */
2820 pdata.found = 2;
2821 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2823 mono_domain_unlock (domain);
2825 if (pdata.found != 1)
2826 g_print ("thunk failed for %p from %p\n", target, code);
2827 g_assert (pdata.found == 1);
2830 static void
2831 patch_ins (guint8 *code, guint32 ins)
2833 *(guint32*)code = GUINT32_TO_BE (ins);
2834 mono_arch_flush_icache (code, 4);
2837 void
2838 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2840 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2841 guint32 prim = ins >> 26;
2842 guint32 ovf;
2844 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2845 if (prim == 18) {
2846 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2847 gint diff = target - code;
2848 g_assert (!is_fd);
2849 if (diff >= 0){
2850 if (diff <= 33554431){
2851 ins = (18 << 26) | (diff) | (ins & 1);
2852 patch_ins (code, ins);
2853 return;
2855 } else {
2856 /* diff between 0 and -33554432 */
2857 if (diff >= -33554432){
2858 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2859 patch_ins (code, ins);
2860 return;
2864 if ((glong)target >= 0){
2865 if ((glong)target <= 33554431){
2866 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2867 patch_ins (code, ins);
2868 return;
2870 } else {
2871 if ((glong)target >= -33554432){
2872 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2873 patch_ins (code, ins);
2874 return;
2878 handle_thunk (TRUE, code, target);
2879 return;
2881 g_assert_not_reached ();
2885 if (prim == 16) {
2886 g_assert (!is_fd);
2887 // absolute address
2888 if (ins & 2) {
2889 guint32 li = (gulong)target;
2890 ins = (ins & 0xffff0000) | (ins & 3);
2891 ovf = li & 0xffff0000;
2892 if (ovf != 0 && ovf != 0xffff0000)
2893 g_assert_not_reached ();
2894 li &= 0xffff;
2895 ins |= li;
2896 // FIXME: assert the top bits of li are 0
2897 } else {
2898 gint diff = target - code;
2899 ins = (ins & 0xffff0000) | (ins & 3);
2900 ovf = diff & 0xffff0000;
2901 if (ovf != 0 && ovf != 0xffff0000)
2902 g_assert_not_reached ();
2903 diff &= 0xffff;
2904 ins |= diff;
2906 patch_ins (code, ins);
2907 return;
2910 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2911 #ifdef __mono_ppc64__
2912 guint32 *seq = (guint32*)code;
2913 guint32 *branch_ins;
2915 /* the trampoline code will try to patch the blrl, blr, bcctr */
2916 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2917 branch_ins = seq;
2918 if (ppc_opcode (seq [-3]) == 58 || ppc_opcode (seq [-3]) == 31) /* ld || mr */
2919 code -= 32;
2920 else
2921 code -= 24;
2922 } else {
2923 if (ppc_opcode (seq [5]) == 58 || ppc_opcode (seq [5]) == 31) /* ld || mr */
2924 branch_ins = seq + 8;
2925 else
2926 branch_ins = seq + 6;
2929 seq = (guint32*)code;
2930 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2931 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2933 if (ppc_opcode (seq [5]) == 58) { /* ld */
2934 g_assert (ppc_opcode (seq [6]) == 58); /* ld */
2936 if (!is_fd) {
2937 guint8 *buf = (guint8*)&seq [5];
2938 ppc_mr (buf, ppc_r0, ppc_r11);
2939 ppc_nop (buf);
2941 } else {
2942 if (is_fd)
2943 target = mono_get_addr_from_ftnptr ((gpointer)target);
2946 /* FIXME: make this thread safe */
2947 /* FIXME: we're assuming we're using r11 here */
2948 ppc_load_ptr_sequence (code, ppc_r11, target);
2949 mono_arch_flush_icache ((guint8*)seq, 28);
2950 #else
2951 guint32 *seq;
2952 /* the trampoline code will try to patch the blrl, blr, bcctr */
2953 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2954 code -= 12;
2956 /* this is the lis/ori/mtlr/blrl sequence */
2957 seq = (guint32*)code;
2958 g_assert ((seq [0] >> 26) == 15);
2959 g_assert ((seq [1] >> 26) == 24);
2960 g_assert ((seq [2] >> 26) == 31);
2961 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2962 /* FIXME: make this thread safe */
2963 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2964 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2965 mono_arch_flush_icache (code - 8, 8);
2966 #endif
2967 } else {
2968 g_assert_not_reached ();
2970 // g_print ("patched with 0x%08x\n", ins);
2973 void
2974 ppc_patch (guchar *code, const guchar *target)
2976 ppc_patch_full (code, target, FALSE);
2979 void
2980 mono_ppc_patch (guchar *code, const guchar *target)
2982 ppc_patch (code, target);
2985 static guint8*
2986 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2988 switch (ins->opcode) {
2989 case OP_FCALL:
2990 case OP_FCALL_REG:
2991 case OP_FCALL_MEMBASE:
2992 if (ins->dreg != ppc_f1)
2993 ppc_fmr (code, ins->dreg, ppc_f1);
2994 break;
2997 return code;
3001 * emit_load_volatile_arguments:
3003 * Load volatile arguments from the stack to the original input registers.
3004 * Required before a tail call.
3006 static guint8*
3007 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
3009 MonoMethod *method = cfg->method;
3010 MonoMethodSignature *sig;
3011 MonoInst *inst;
3012 CallInfo *cinfo;
3013 guint32 i, pos;
3014 int struct_index = 0;
3016 sig = mono_method_signature (method);
3018 /* This is the opposite of the code in emit_prolog */
3020 pos = 0;
3022 cinfo = calculate_sizes (sig, sig->pinvoke);
3024 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3025 ArgInfo *ainfo = &cinfo->ret;
3026 inst = cfg->vret_addr;
3027 g_assert (ppc_is_imm16 (inst->inst_offset));
3028 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3030 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3031 ArgInfo *ainfo = cinfo->args + i;
3032 inst = cfg->args [pos];
3034 g_assert (inst->opcode != OP_REGVAR);
3035 g_assert (ppc_is_imm16 (inst->inst_offset));
3037 switch (ainfo->regtype) {
3038 case RegTypeGeneral:
3039 switch (ainfo->size) {
3040 case 1:
3041 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3042 break;
3043 case 2:
3044 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3045 break;
3046 #ifdef __mono_ppc64__
3047 case 4:
3048 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3049 break;
3050 #endif
3051 default:
3052 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3053 break;
3055 break;
3057 case RegTypeFP:
3058 switch (ainfo->size) {
3059 case 4:
3060 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3061 break;
3062 case 8:
3063 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3064 break;
3065 default:
3066 g_assert_not_reached ();
3068 break;
3070 case RegTypeBase: {
3071 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
3072 &inst->klass->byval_arg);
3074 #ifndef __mono_ppc64__
3075 if (type->type == MONO_TYPE_I8)
3076 NOT_IMPLEMENTED;
3077 #endif
3079 if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_I8) {
3080 ppc_ldptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3081 ppc_stptr (code, ppc_r0, ainfo->offset, ainfo->reg);
3082 } else if (type->type == MONO_TYPE_I4) {
3083 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3084 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
3085 } else {
3086 NOT_IMPLEMENTED;
3089 break;
3092 case RegTypeStructByVal: {
3093 #ifdef __APPLE__
3094 guint32 size = 0;
3095 #endif
3096 int j;
3098 /* FIXME: */
3099 if (ainfo->vtsize)
3100 NOT_IMPLEMENTED;
3101 #ifdef __APPLE__
3103 * Darwin pinvokes needs some special handling
3104 * for 1 and 2 byte arguments
3106 if (method->signature->pinvoke)
3107 size = mono_class_native_size (inst->klass, NULL);
3108 if (size == 1 || size == 2) {
3109 /* FIXME: */
3110 NOT_IMPLEMENTED;
3111 } else
3112 #endif
3113 for (j = 0; j < ainfo->vtregs; ++j) {
3114 ppc_ldptr (code, ainfo->reg + j,
3115 inst->inst_offset + j * sizeof (gpointer),
3116 inst->inst_basereg);
3117 /* FIXME: shift to the right */
3118 if (ainfo->bytes)
3119 NOT_IMPLEMENTED;
3121 break;
3124 case RegTypeStructByAddr: {
3125 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
3127 g_assert (ppc_is_imm16 (addr->inst_offset));
3128 g_assert (!ainfo->offset);
3129 ppc_ldptr (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
3131 struct_index++;
3132 break;
3135 default:
3136 g_assert_not_reached ();
3139 pos ++;
3142 g_free (cinfo);
3144 return code;
3147 /* This must be kept in sync with emit_load_volatile_arguments(). */
3148 static int
3149 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3151 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3152 MonoMethodSignature *sig;
3153 MonoCallInst *call;
3154 CallInfo *cinfo;
3155 int i;
3157 if (ins->opcode != OP_JMP)
3158 return len;
3160 call = (MonoCallInst*)ins;
3161 sig = mono_method_signature (cfg->method);
3162 cinfo = calculate_sizes (sig, sig->pinvoke);
3164 if (MONO_TYPE_ISSTRUCT (sig->ret))
3165 len += 4;
3166 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3167 ArgInfo *ainfo = cinfo->args + i;
3169 switch (ainfo->regtype) {
3170 case RegTypeGeneral:
3171 case RegTypeFP:
3172 len += 4;
3173 break;
3175 case RegTypeBase:
3176 len += 8;
3177 break;
3179 case RegTypeStructByVal:
3180 len += 4 * ainfo->size;
3181 break;
3183 case RegTypeStructByAddr:
3184 len += 4;
3185 break;
3187 default:
3188 g_assert_not_reached ();
3192 g_free (cinfo);
3194 return len;
3197 static guint8*
3198 emit_reserve_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_r11, -size);
3213 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3216 return code;
3219 static guint8*
3220 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3222 long size = cfg->param_area;
3224 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3225 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3227 if (!size)
3228 return code;
3230 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3231 if (ppc_is_imm16 (size)) {
3232 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3233 } else {
3234 ppc_load (code, ppc_r11, size);
3235 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3238 return code;
3241 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3243 #ifndef DISABLE_JIT
3244 void
3245 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3247 MonoInst *ins, *next;
3248 MonoCallInst *call;
3249 guint offset;
3250 guint8 *code = cfg->native_code + cfg->code_len;
3251 MonoInst *last_ins = NULL;
3252 guint last_offset = 0;
3253 int max_len, cpos;
3254 int L;
3256 /* we don't align basic blocks of loops on ppc */
3258 if (cfg->verbose_level > 2)
3259 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3261 cpos = bb->max_offset;
3263 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3264 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3265 //g_assert (!mono_compile_aot);
3266 //cpos += 6;
3267 //if (bb->cil_code)
3268 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3269 /* this is not thread save, but good enough */
3270 /* fixme: howto handle overflows? */
3271 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3274 MONO_BB_FOR_EACH_INS (bb, ins) {
3275 offset = code - cfg->native_code;
3277 max_len = ins_native_length (cfg, ins);
3279 if (offset > (cfg->code_size - max_len - 16)) {
3280 cfg->code_size *= 2;
3281 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3282 code = cfg->native_code + offset;
3284 // if (ins->cil_code)
3285 // g_print ("cil code\n");
3286 mono_debug_record_line_number (cfg, ins, offset);
3288 switch (normalize_opcode (ins->opcode)) {
3289 case OP_RELAXED_NOP:
3290 case OP_NOP:
3291 case OP_DUMMY_USE:
3292 case OP_DUMMY_STORE:
3293 case OP_NOT_REACHED:
3294 case OP_NOT_NULL:
3295 break;
3296 case OP_SEQ_POINT: {
3297 int i;
3299 if (cfg->compile_aot)
3300 NOT_IMPLEMENTED;
3303 * Read from the single stepping trigger page. This will cause a
3304 * SIGSEGV when single stepping is enabled.
3305 * We do this _before_ the breakpoint, so single stepping after
3306 * a breakpoint is hit will step to the next IL offset.
3308 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3309 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3310 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3313 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3316 * A placeholder for a possible breakpoint inserted by
3317 * mono_arch_set_breakpoint ().
3319 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3320 ppc_nop (code);
3321 break;
3323 case OP_TLS_GET:
3324 emit_tls_access (code, ins->dreg, ins->inst_offset);
3325 break;
3326 case OP_BIGMUL:
3327 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3328 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3329 ppc_mr (code, ppc_r4, ppc_r0);
3330 break;
3331 case OP_BIGMUL_UN:
3332 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3333 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3334 ppc_mr (code, ppc_r4, ppc_r0);
3335 break;
3336 case OP_MEMORY_BARRIER:
3337 ppc_sync (code);
3338 break;
3339 case OP_STOREI1_MEMBASE_REG:
3340 if (ppc_is_imm16 (ins->inst_offset)) {
3341 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3342 } else {
3343 if (ppc_is_imm32 (ins->inst_offset)) {
3344 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3345 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3346 } else {
3347 ppc_load (code, ppc_r0, ins->inst_offset);
3348 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3351 break;
3352 case OP_STOREI2_MEMBASE_REG:
3353 if (ppc_is_imm16 (ins->inst_offset)) {
3354 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3355 } else {
3356 if (ppc_is_imm32 (ins->inst_offset)) {
3357 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3358 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3359 } else {
3360 ppc_load (code, ppc_r0, ins->inst_offset);
3361 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3364 break;
3365 case OP_STORE_MEMBASE_REG:
3366 if (ppc_is_imm16 (ins->inst_offset)) {
3367 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3368 } else {
3369 if (ppc_is_imm32 (ins->inst_offset)) {
3370 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3371 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3372 } else {
3373 ppc_load (code, ppc_r0, ins->inst_offset);
3374 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3377 break;
3378 #ifdef __mono_ilp32__
3379 case OP_STOREI8_MEMBASE_REG:
3380 if (ppc_is_imm16 (ins->inst_offset)) {
3381 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3382 } else {
3383 ppc_load (code, ppc_r0, ins->inst_offset);
3384 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3386 break;
3387 #endif
3388 case OP_STOREI1_MEMINDEX:
3389 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3390 break;
3391 case OP_STOREI2_MEMINDEX:
3392 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3393 break;
3394 case OP_STORE_MEMINDEX:
3395 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3396 break;
3397 case OP_LOADU4_MEM:
3398 g_assert_not_reached ();
3399 break;
3400 case OP_LOAD_MEMBASE:
3401 if (ppc_is_imm16 (ins->inst_offset)) {
3402 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3403 } else {
3404 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3405 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3406 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3407 } else {
3408 ppc_load (code, ppc_r0, ins->inst_offset);
3409 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3412 break;
3413 case OP_LOADI4_MEMBASE:
3414 #ifdef __mono_ppc64__
3415 if (ppc_is_imm16 (ins->inst_offset)) {
3416 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3417 } else {
3418 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3419 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3420 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3421 } else {
3422 ppc_load (code, ppc_r0, ins->inst_offset);
3423 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3426 break;
3427 #endif
3428 case OP_LOADU4_MEMBASE:
3429 if (ppc_is_imm16 (ins->inst_offset)) {
3430 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3431 } else {
3432 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3433 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3434 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3435 } else {
3436 ppc_load (code, ppc_r0, ins->inst_offset);
3437 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3440 break;
3441 case OP_LOADI1_MEMBASE:
3442 case OP_LOADU1_MEMBASE:
3443 if (ppc_is_imm16 (ins->inst_offset)) {
3444 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3445 } else {
3446 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3447 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3448 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3449 } else {
3450 ppc_load (code, ppc_r0, ins->inst_offset);
3451 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3454 if (ins->opcode == OP_LOADI1_MEMBASE)
3455 ppc_extsb (code, ins->dreg, ins->dreg);
3456 break;
3457 case OP_LOADU2_MEMBASE:
3458 if (ppc_is_imm16 (ins->inst_offset)) {
3459 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3460 } else {
3461 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3462 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3463 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3464 } else {
3465 ppc_load (code, ppc_r0, ins->inst_offset);
3466 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3469 break;
3470 case OP_LOADI2_MEMBASE:
3471 if (ppc_is_imm16 (ins->inst_offset)) {
3472 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3473 } else {
3474 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3475 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3476 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3477 } else {
3478 ppc_load (code, ppc_r0, ins->inst_offset);
3479 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3482 break;
3483 #ifdef __mono_ilp32__
3484 case OP_LOADI8_MEMBASE:
3485 if (ppc_is_imm16 (ins->inst_offset)) {
3486 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3487 } else {
3488 ppc_load (code, ppc_r0, ins->inst_offset);
3489 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3491 break;
3492 #endif
3493 case OP_LOAD_MEMINDEX:
3494 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3495 break;
3496 case OP_LOADI4_MEMINDEX:
3497 #ifdef __mono_ppc64__
3498 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3499 break;
3500 #endif
3501 case OP_LOADU4_MEMINDEX:
3502 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3503 break;
3504 case OP_LOADU2_MEMINDEX:
3505 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3506 break;
3507 case OP_LOADI2_MEMINDEX:
3508 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3509 break;
3510 case OP_LOADU1_MEMINDEX:
3511 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3512 break;
3513 case OP_LOADI1_MEMINDEX:
3514 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3515 ppc_extsb (code, ins->dreg, ins->dreg);
3516 break;
3517 case OP_ICONV_TO_I1:
3518 CASE_PPC64 (OP_LCONV_TO_I1)
3519 ppc_extsb (code, ins->dreg, ins->sreg1);
3520 break;
3521 case OP_ICONV_TO_I2:
3522 CASE_PPC64 (OP_LCONV_TO_I2)
3523 ppc_extsh (code, ins->dreg, ins->sreg1);
3524 break;
3525 case OP_ICONV_TO_U1:
3526 CASE_PPC64 (OP_LCONV_TO_U1)
3527 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3528 break;
3529 case OP_ICONV_TO_U2:
3530 CASE_PPC64 (OP_LCONV_TO_U2)
3531 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3532 break;
3533 case OP_COMPARE:
3534 case OP_ICOMPARE:
3535 CASE_PPC64 (OP_LCOMPARE)
3536 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3537 next = ins->next;
3538 if (next && compare_opcode_is_unsigned (next->opcode))
3539 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3540 else
3541 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3542 break;
3543 case OP_COMPARE_IMM:
3544 case OP_ICOMPARE_IMM:
3545 CASE_PPC64 (OP_LCOMPARE_IMM)
3546 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3547 next = ins->next;
3548 if (next && compare_opcode_is_unsigned (next->opcode)) {
3549 if (ppc_is_uimm16 (ins->inst_imm)) {
3550 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3551 } else {
3552 g_assert_not_reached ();
3554 } else {
3555 if (ppc_is_imm16 (ins->inst_imm)) {
3556 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3557 } else {
3558 g_assert_not_reached ();
3561 break;
3562 case OP_BREAK:
3563 ppc_break (code);
3564 break;
3565 case OP_ADDCC:
3566 case OP_IADDCC:
3567 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3568 break;
3569 case OP_IADD:
3570 CASE_PPC64 (OP_LADD)
3571 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3572 break;
3573 case OP_ADC:
3574 case OP_IADC:
3575 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3576 break;
3577 case OP_ADDCC_IMM:
3578 if (ppc_is_imm16 (ins->inst_imm)) {
3579 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3580 } else {
3581 g_assert_not_reached ();
3583 break;
3584 case OP_ADD_IMM:
3585 case OP_IADD_IMM:
3586 CASE_PPC64 (OP_LADD_IMM)
3587 if (ppc_is_imm16 (ins->inst_imm)) {
3588 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3589 } else {
3590 g_assert_not_reached ();
3592 break;
3593 case OP_IADD_OVF:
3594 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3596 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3597 ppc_mfspr (code, ppc_r0, ppc_xer);
3598 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3599 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3600 break;
3601 case OP_IADD_OVF_UN:
3602 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3604 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3605 ppc_mfspr (code, ppc_r0, ppc_xer);
3606 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3607 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3608 break;
3609 case OP_ISUB_OVF:
3610 CASE_PPC64 (OP_LSUB_OVF)
3611 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3613 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3614 ppc_mfspr (code, ppc_r0, ppc_xer);
3615 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3616 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3617 break;
3618 case OP_ISUB_OVF_UN:
3619 CASE_PPC64 (OP_LSUB_OVF_UN)
3620 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3622 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3623 ppc_mfspr (code, ppc_r0, ppc_xer);
3624 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3625 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3626 break;
3627 case OP_ADD_OVF_CARRY:
3628 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3630 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3631 ppc_mfspr (code, ppc_r0, ppc_xer);
3632 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3633 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3634 break;
3635 case OP_ADD_OVF_UN_CARRY:
3636 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3638 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3639 ppc_mfspr (code, ppc_r0, ppc_xer);
3640 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3641 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3642 break;
3643 case OP_SUB_OVF_CARRY:
3644 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3646 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3647 ppc_mfspr (code, ppc_r0, ppc_xer);
3648 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3649 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3650 break;
3651 case OP_SUB_OVF_UN_CARRY:
3652 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3654 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3655 ppc_mfspr (code, ppc_r0, ppc_xer);
3656 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3657 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3658 break;
3659 case OP_SUBCC:
3660 case OP_ISUBCC:
3661 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3662 break;
3663 case OP_ISUB:
3664 CASE_PPC64 (OP_LSUB)
3665 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3666 break;
3667 case OP_SBB:
3668 case OP_ISBB:
3669 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3670 break;
3671 case OP_SUB_IMM:
3672 case OP_ISUB_IMM:
3673 CASE_PPC64 (OP_LSUB_IMM)
3674 // we add the negated value
3675 if (ppc_is_imm16 (-ins->inst_imm))
3676 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3677 else {
3678 g_assert_not_reached ();
3680 break;
3681 case OP_PPC_SUBFIC:
3682 g_assert (ppc_is_imm16 (ins->inst_imm));
3683 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3684 break;
3685 case OP_PPC_SUBFZE:
3686 ppc_subfze (code, ins->dreg, ins->sreg1);
3687 break;
3688 case OP_IAND:
3689 CASE_PPC64 (OP_LAND)
3690 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3691 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3692 break;
3693 case OP_AND_IMM:
3694 case OP_IAND_IMM:
3695 CASE_PPC64 (OP_LAND_IMM)
3696 if (!(ins->inst_imm & 0xffff0000)) {
3697 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3698 } else if (!(ins->inst_imm & 0xffff)) {
3699 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3700 } else {
3701 g_assert_not_reached ();
3703 break;
3704 case OP_IDIV:
3705 CASE_PPC64 (OP_LDIV) {
3706 guint8 *divisor_is_m1;
3707 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3709 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3710 divisor_is_m1 = code;
3711 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3712 ppc_lis (code, ppc_r0, 0x8000);
3713 #ifdef __mono_ppc64__
3714 if (ins->opcode == OP_LDIV)
3715 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3716 #endif
3717 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3718 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3719 ppc_patch (divisor_is_m1, code);
3720 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3722 if (ins->opcode == OP_IDIV)
3723 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3724 #ifdef __mono_ppc64__
3725 else
3726 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3727 #endif
3728 ppc_mfspr (code, ppc_r0, ppc_xer);
3729 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3730 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3731 break;
3733 case OP_IDIV_UN:
3734 CASE_PPC64 (OP_LDIV_UN)
3735 if (ins->opcode == OP_IDIV_UN)
3736 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3737 #ifdef __mono_ppc64__
3738 else
3739 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3740 #endif
3741 ppc_mfspr (code, ppc_r0, ppc_xer);
3742 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3743 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3744 break;
3745 case OP_DIV_IMM:
3746 case OP_IREM:
3747 case OP_IREM_UN:
3748 case OP_REM_IMM:
3749 g_assert_not_reached ();
3750 case OP_IOR:
3751 CASE_PPC64 (OP_LOR)
3752 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3753 break;
3754 case OP_OR_IMM:
3755 case OP_IOR_IMM:
3756 CASE_PPC64 (OP_LOR_IMM)
3757 if (!(ins->inst_imm & 0xffff0000)) {
3758 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3759 } else if (!(ins->inst_imm & 0xffff)) {
3760 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3761 } else {
3762 g_assert_not_reached ();
3764 break;
3765 case OP_IXOR:
3766 CASE_PPC64 (OP_LXOR)
3767 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3768 break;
3769 case OP_IXOR_IMM:
3770 case OP_XOR_IMM:
3771 CASE_PPC64 (OP_LXOR_IMM)
3772 if (!(ins->inst_imm & 0xffff0000)) {
3773 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3774 } else if (!(ins->inst_imm & 0xffff)) {
3775 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3776 } else {
3777 g_assert_not_reached ();
3779 break;
3780 case OP_ISHL:
3781 CASE_PPC64 (OP_LSHL)
3782 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3783 break;
3784 case OP_SHL_IMM:
3785 case OP_ISHL_IMM:
3786 CASE_PPC64 (OP_LSHL_IMM)
3787 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3788 break;
3789 case OP_ISHR:
3790 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3791 break;
3792 case OP_SHR_IMM:
3793 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3794 break;
3795 case OP_SHR_UN_IMM:
3796 if (MASK_SHIFT_IMM (ins->inst_imm))
3797 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3798 else
3799 ppc_mr (code, ins->dreg, ins->sreg1);
3800 break;
3801 case OP_ISHR_UN:
3802 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3803 break;
3804 case OP_INOT:
3805 CASE_PPC64 (OP_LNOT)
3806 ppc_not (code, ins->dreg, ins->sreg1);
3807 break;
3808 case OP_INEG:
3809 CASE_PPC64 (OP_LNEG)
3810 ppc_neg (code, ins->dreg, ins->sreg1);
3811 break;
3812 case OP_IMUL:
3813 CASE_PPC64 (OP_LMUL)
3814 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3815 break;
3816 case OP_IMUL_IMM:
3817 case OP_MUL_IMM:
3818 CASE_PPC64 (OP_LMUL_IMM)
3819 if (ppc_is_imm16 (ins->inst_imm)) {
3820 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3821 } else {
3822 g_assert_not_reached ();
3824 break;
3825 case OP_IMUL_OVF:
3826 CASE_PPC64 (OP_LMUL_OVF)
3827 /* we annot use mcrxr, since it's not implemented on some processors
3828 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3830 if (ins->opcode == OP_IMUL_OVF)
3831 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3832 #ifdef __mono_ppc64__
3833 else
3834 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3835 #endif
3836 ppc_mfspr (code, ppc_r0, ppc_xer);
3837 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3838 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3839 break;
3840 case OP_IMUL_OVF_UN:
3841 CASE_PPC64 (OP_LMUL_OVF_UN)
3842 /* we first multiply to get the high word and compare to 0
3843 * to set the flags, then the result is discarded and then
3844 * we multiply to get the lower * bits result
3846 if (ins->opcode == OP_IMUL_OVF_UN)
3847 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3848 #ifdef __mono_ppc64__
3849 else
3850 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3851 #endif
3852 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3853 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3854 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3855 break;
3856 case OP_ICONST:
3857 ppc_load (code, ins->dreg, ins->inst_c0);
3858 break;
3859 case OP_I8CONST: {
3860 ppc_load (code, ins->dreg, ins->inst_l);
3861 break;
3863 case OP_LOAD_GOTADDR:
3864 /* The PLT implementation depends on this */
3865 g_assert (ins->dreg == ppc_r30);
3867 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3868 break;
3869 case OP_GOT_ENTRY:
3870 // FIXME: Fix max instruction length
3871 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3872 /* arch_emit_got_access () patches this */
3873 ppc_load32 (code, ppc_r0, 0);
3874 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3875 break;
3876 case OP_AOTCONST:
3877 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3878 ppc_load_sequence (code, ins->dreg, 0);
3879 break;
3880 CASE_PPC32 (OP_ICONV_TO_I4)
3881 CASE_PPC32 (OP_ICONV_TO_U4)
3882 case OP_MOVE:
3883 ppc_mr (code, ins->dreg, ins->sreg1);
3884 break;
3885 case OP_SETLRET: {
3886 int saved = ins->sreg1;
3887 if (ins->sreg1 == ppc_r3) {
3888 ppc_mr (code, ppc_r0, ins->sreg1);
3889 saved = ppc_r0;
3891 if (ins->sreg2 != ppc_r3)
3892 ppc_mr (code, ppc_r3, ins->sreg2);
3893 if (saved != ppc_r4)
3894 ppc_mr (code, ppc_r4, saved);
3895 break;
3897 case OP_FMOVE:
3898 ppc_fmr (code, ins->dreg, ins->sreg1);
3899 break;
3900 case OP_FCONV_TO_R4:
3901 ppc_frsp (code, ins->dreg, ins->sreg1);
3902 break;
3903 case OP_JMP: {
3904 int i, pos;
3907 * Keep in sync with mono_arch_emit_epilog
3909 g_assert (!cfg->method->save_lmf);
3911 * Note: we can use ppc_r11 here because it is dead anyway:
3912 * we're leaving the method.
3914 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3915 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3916 if (ppc_is_imm16 (ret_offset)) {
3917 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3918 } else {
3919 ppc_load (code, ppc_r11, ret_offset);
3920 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3922 ppc_mtlr (code, ppc_r0);
3925 code = emit_load_volatile_arguments (cfg, code);
3927 if (ppc_is_imm16 (cfg->stack_usage)) {
3928 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3929 } else {
3930 /* cfg->stack_usage is an int, so we can use
3931 * an addis/addi sequence here even in 64-bit. */
3932 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3933 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3935 if (!cfg->method->save_lmf) {
3936 /*for (i = 31; i >= 14; --i) {
3937 if (cfg->used_float_regs & (1 << i)) {
3938 pos += sizeof (double);
3939 ppc_lfd (code, i, -pos, cfg->frame_reg);
3942 pos = 0;
3943 for (i = 31; i >= 13; --i) {
3944 if (cfg->used_int_regs & (1 << i)) {
3945 pos += sizeof (gpointer);
3946 ppc_ldptr (code, i, -pos, ppc_r11);
3949 } else {
3950 /* FIXME restore from MonoLMF: though this can't happen yet */
3952 ppc_mr (code, ppc_sp, ppc_r11);
3953 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3954 if (cfg->compile_aot) {
3955 /* arch_emit_got_access () patches this */
3956 ppc_load32 (code, ppc_r0, 0);
3957 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3958 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3959 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3960 #else
3961 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3962 #endif
3963 ppc_mtctr (code, ppc_r0);
3964 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3965 } else {
3966 ppc_b (code, 0);
3968 break;
3970 case OP_CHECK_THIS:
3971 /* ensure ins->sreg1 is not NULL */
3972 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3973 break;
3974 case OP_ARGLIST: {
3975 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3976 if (ppc_is_imm16 (cookie_offset)) {
3977 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3978 } else {
3979 ppc_load (code, ppc_r0, cookie_offset);
3980 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3982 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3983 break;
3985 case OP_FCALL:
3986 case OP_LCALL:
3987 case OP_VCALL:
3988 case OP_VCALL2:
3989 case OP_VOIDCALL:
3990 case OP_CALL:
3991 call = (MonoCallInst*)ins;
3992 if (ins->flags & MONO_INST_HAS_METHOD)
3993 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3994 else
3995 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3996 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3997 ppc_load_func (code, ppc_r0, 0);
3998 ppc_mtlr (code, ppc_r0);
3999 ppc_blrl (code);
4000 } else {
4001 ppc_bl (code, 0);
4003 /* FIXME: this should be handled somewhere else in the new jit */
4004 code = emit_move_return_value (cfg, ins, code);
4005 break;
4006 case OP_FCALL_REG:
4007 case OP_LCALL_REG:
4008 case OP_VCALL_REG:
4009 case OP_VCALL2_REG:
4010 case OP_VOIDCALL_REG:
4011 case OP_CALL_REG:
4012 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4013 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4014 /* FIXME: if we know that this is a method, we
4015 can omit this load */
4016 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4017 ppc_mtlr (code, ppc_r0);
4018 #else
4019 ppc_mtlr (code, ins->sreg1);
4020 #endif
4021 ppc_blrl (code);
4022 /* FIXME: this should be handled somewhere else in the new jit */
4023 code = emit_move_return_value (cfg, ins, code);
4024 break;
4025 case OP_FCALL_MEMBASE:
4026 case OP_LCALL_MEMBASE:
4027 case OP_VCALL_MEMBASE:
4028 case OP_VCALL2_MEMBASE:
4029 case OP_VOIDCALL_MEMBASE:
4030 case OP_CALL_MEMBASE:
4031 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
4032 /* The trampolines clobber this */
4033 ppc_mr (code, ppc_r29, ins->sreg1);
4034 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4035 } else {
4036 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4038 ppc_mtlr (code, ppc_r0);
4039 ppc_blrl (code);
4040 /* FIXME: this should be handled somewhere else in the new jit */
4041 code = emit_move_return_value (cfg, ins, code);
4042 break;
4043 case OP_LOCALLOC: {
4044 guint8 * zero_loop_jump, * zero_loop_start;
4045 /* keep alignment */
4046 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4047 int area_offset = alloca_waste;
4048 area_offset &= ~31;
4049 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
4050 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4051 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
4052 /* use ctr to store the number of words to 0 if needed */
4053 if (ins->flags & MONO_INST_INIT) {
4054 /* we zero 4 bytes at a time:
4055 * we add 7 instead of 3 so that we set the counter to
4056 * at least 1, otherwise the bdnz instruction will make
4057 * it negative and iterate billions of times.
4059 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4060 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4061 ppc_mtctr (code, ppc_r0);
4063 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4064 ppc_neg (code, ppc_r11, ppc_r11);
4065 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
4067 /* FIXME: make this loop work in 8 byte
4068 increments on PPC64 */
4069 if (ins->flags & MONO_INST_INIT) {
4070 /* adjust the dest reg by -4 so we can use stwu */
4071 /* we actually adjust -8 because we let the loop
4072 * run at least once
4074 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4075 ppc_li (code, ppc_r11, 0);
4076 zero_loop_start = code;
4077 ppc_stwu (code, ppc_r11, 4, ins->dreg);
4078 zero_loop_jump = code;
4079 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4080 ppc_patch (zero_loop_jump, zero_loop_start);
4082 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4083 break;
4085 case OP_THROW: {
4086 //ppc_break (code);
4087 ppc_mr (code, ppc_r3, ins->sreg1);
4088 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4089 (gpointer)"mono_arch_throw_exception");
4090 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4091 ppc_load_func (code, ppc_r0, 0);
4092 ppc_mtlr (code, ppc_r0);
4093 ppc_blrl (code);
4094 } else {
4095 ppc_bl (code, 0);
4097 break;
4099 case OP_RETHROW: {
4100 //ppc_break (code);
4101 ppc_mr (code, ppc_r3, ins->sreg1);
4102 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4103 (gpointer)"mono_arch_rethrow_exception");
4104 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4105 ppc_load_func (code, ppc_r0, 0);
4106 ppc_mtlr (code, ppc_r0);
4107 ppc_blrl (code);
4108 } else {
4109 ppc_bl (code, 0);
4111 break;
4113 case OP_START_HANDLER: {
4114 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4115 g_assert (spvar->inst_basereg != ppc_sp);
4116 code = emit_reserve_param_area (cfg, code);
4117 ppc_mflr (code, ppc_r0);
4118 if (ppc_is_imm16 (spvar->inst_offset)) {
4119 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4120 } else {
4121 ppc_load (code, ppc_r11, spvar->inst_offset);
4122 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
4124 break;
4126 case OP_ENDFILTER: {
4127 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4128 g_assert (spvar->inst_basereg != ppc_sp);
4129 code = emit_unreserve_param_area (cfg, code);
4130 if (ins->sreg1 != ppc_r3)
4131 ppc_mr (code, ppc_r3, ins->sreg1);
4132 if (ppc_is_imm16 (spvar->inst_offset)) {
4133 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4134 } else {
4135 ppc_load (code, ppc_r11, spvar->inst_offset);
4136 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
4138 ppc_mtlr (code, ppc_r0);
4139 ppc_blr (code);
4140 break;
4142 case OP_ENDFINALLY: {
4143 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4144 g_assert (spvar->inst_basereg != ppc_sp);
4145 code = emit_unreserve_param_area (cfg, code);
4146 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4147 ppc_mtlr (code, ppc_r0);
4148 ppc_blr (code);
4149 break;
4151 case OP_CALL_HANDLER:
4152 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4153 ppc_bl (code, 0);
4154 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4155 break;
4156 case OP_LABEL:
4157 ins->inst_c0 = code - cfg->native_code;
4158 break;
4159 case OP_BR:
4160 /*if (ins->inst_target_bb->native_offset) {
4161 ppc_b (code, 0);
4162 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4163 } else*/ {
4164 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4165 ppc_b (code, 0);
4167 break;
4168 case OP_BR_REG:
4169 ppc_mtctr (code, ins->sreg1);
4170 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4171 break;
4172 case OP_CEQ:
4173 case OP_ICEQ:
4174 CASE_PPC64 (OP_LCEQ)
4175 ppc_li (code, ins->dreg, 0);
4176 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4177 ppc_li (code, ins->dreg, 1);
4178 break;
4179 case OP_CLT:
4180 case OP_CLT_UN:
4181 case OP_ICLT:
4182 case OP_ICLT_UN:
4183 CASE_PPC64 (OP_LCLT)
4184 CASE_PPC64 (OP_LCLT_UN)
4185 ppc_li (code, ins->dreg, 1);
4186 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4187 ppc_li (code, ins->dreg, 0);
4188 break;
4189 case OP_CGT:
4190 case OP_CGT_UN:
4191 case OP_ICGT:
4192 case OP_ICGT_UN:
4193 CASE_PPC64 (OP_LCGT)
4194 CASE_PPC64 (OP_LCGT_UN)
4195 ppc_li (code, ins->dreg, 1);
4196 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4197 ppc_li (code, ins->dreg, 0);
4198 break;
4199 case OP_COND_EXC_EQ:
4200 case OP_COND_EXC_NE_UN:
4201 case OP_COND_EXC_LT:
4202 case OP_COND_EXC_LT_UN:
4203 case OP_COND_EXC_GT:
4204 case OP_COND_EXC_GT_UN:
4205 case OP_COND_EXC_GE:
4206 case OP_COND_EXC_GE_UN:
4207 case OP_COND_EXC_LE:
4208 case OP_COND_EXC_LE_UN:
4209 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4210 break;
4211 case OP_COND_EXC_IEQ:
4212 case OP_COND_EXC_INE_UN:
4213 case OP_COND_EXC_ILT:
4214 case OP_COND_EXC_ILT_UN:
4215 case OP_COND_EXC_IGT:
4216 case OP_COND_EXC_IGT_UN:
4217 case OP_COND_EXC_IGE:
4218 case OP_COND_EXC_IGE_UN:
4219 case OP_COND_EXC_ILE:
4220 case OP_COND_EXC_ILE_UN:
4221 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4222 break;
4223 case OP_IBEQ:
4224 case OP_IBNE_UN:
4225 case OP_IBLT:
4226 case OP_IBLT_UN:
4227 case OP_IBGT:
4228 case OP_IBGT_UN:
4229 case OP_IBGE:
4230 case OP_IBGE_UN:
4231 case OP_IBLE:
4232 case OP_IBLE_UN:
4233 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4234 break;
4236 /* floating point opcodes */
4237 case OP_R8CONST:
4238 g_assert (cfg->compile_aot);
4240 /* FIXME: Optimize this */
4241 ppc_bl (code, 1);
4242 ppc_mflr (code, ppc_r11);
4243 ppc_b (code, 3);
4244 *(double*)code = *(double*)ins->inst_p0;
4245 code += 8;
4246 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4247 break;
4248 case OP_R4CONST:
4249 g_assert_not_reached ();
4250 break;
4251 case OP_STORER8_MEMBASE_REG:
4252 if (ppc_is_imm16 (ins->inst_offset)) {
4253 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4254 } else {
4255 if (ppc_is_imm32 (ins->inst_offset)) {
4256 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4257 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4258 } else {
4259 ppc_load (code, ppc_r0, ins->inst_offset);
4260 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4263 break;
4264 case OP_LOADR8_MEMBASE:
4265 if (ppc_is_imm16 (ins->inst_offset)) {
4266 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4267 } else {
4268 if (ppc_is_imm32 (ins->inst_offset)) {
4269 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4270 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4271 } else {
4272 ppc_load (code, ppc_r0, ins->inst_offset);
4273 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4276 break;
4277 case OP_STORER4_MEMBASE_REG:
4278 ppc_frsp (code, ins->sreg1, ins->sreg1);
4279 if (ppc_is_imm16 (ins->inst_offset)) {
4280 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4281 } else {
4282 if (ppc_is_imm32 (ins->inst_offset)) {
4283 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4284 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4285 } else {
4286 ppc_load (code, ppc_r0, ins->inst_offset);
4287 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4290 break;
4291 case OP_LOADR4_MEMBASE:
4292 if (ppc_is_imm16 (ins->inst_offset)) {
4293 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4294 } else {
4295 if (ppc_is_imm32 (ins->inst_offset)) {
4296 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4297 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4298 } else {
4299 ppc_load (code, ppc_r0, ins->inst_offset);
4300 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4303 break;
4304 case OP_LOADR4_MEMINDEX:
4305 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4306 break;
4307 case OP_LOADR8_MEMINDEX:
4308 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4309 break;
4310 case OP_STORER4_MEMINDEX:
4311 ppc_frsp (code, ins->sreg1, ins->sreg1);
4312 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4313 break;
4314 case OP_STORER8_MEMINDEX:
4315 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4316 break;
4317 case CEE_CONV_R_UN:
4318 case CEE_CONV_R4: /* FIXME: change precision */
4319 case CEE_CONV_R8:
4320 g_assert_not_reached ();
4321 case OP_FCONV_TO_I1:
4322 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4323 break;
4324 case OP_FCONV_TO_U1:
4325 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4326 break;
4327 case OP_FCONV_TO_I2:
4328 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4329 break;
4330 case OP_FCONV_TO_U2:
4331 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4332 break;
4333 case OP_FCONV_TO_I4:
4334 case OP_FCONV_TO_I:
4335 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4336 break;
4337 case OP_FCONV_TO_U4:
4338 case OP_FCONV_TO_U:
4339 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4340 break;
4341 case OP_LCONV_TO_R_UN:
4342 g_assert_not_reached ();
4343 /* Implemented as helper calls */
4344 break;
4345 case OP_LCONV_TO_OVF_I4_2:
4346 case OP_LCONV_TO_OVF_I: {
4347 #ifdef __mono_ppc64__
4348 NOT_IMPLEMENTED;
4349 #else
4350 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4351 // Check if its negative
4352 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4353 negative_branch = code;
4354 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4355 // Its positive msword == 0
4356 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4357 msword_positive_branch = code;
4358 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4360 ovf_ex_target = code;
4361 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4362 // Negative
4363 ppc_patch (negative_branch, code);
4364 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4365 msword_negative_branch = code;
4366 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4367 ppc_patch (msword_negative_branch, ovf_ex_target);
4369 ppc_patch (msword_positive_branch, code);
4370 if (ins->dreg != ins->sreg1)
4371 ppc_mr (code, ins->dreg, ins->sreg1);
4372 break;
4373 #endif
4375 case OP_SQRT:
4376 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4377 break;
4378 case OP_FADD:
4379 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4380 break;
4381 case OP_FSUB:
4382 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4383 break;
4384 case OP_FMUL:
4385 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4386 break;
4387 case OP_FDIV:
4388 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4389 break;
4390 case OP_FNEG:
4391 ppc_fneg (code, ins->dreg, ins->sreg1);
4392 break;
4393 case OP_FREM:
4394 /* emulated */
4395 g_assert_not_reached ();
4396 break;
4397 case OP_FCOMPARE:
4398 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4399 break;
4400 case OP_FCEQ:
4401 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4402 ppc_li (code, ins->dreg, 0);
4403 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4404 ppc_li (code, ins->dreg, 1);
4405 break;
4406 case OP_FCLT:
4407 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4408 ppc_li (code, ins->dreg, 1);
4409 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4410 ppc_li (code, ins->dreg, 0);
4411 break;
4412 case OP_FCLT_UN:
4413 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4414 ppc_li (code, ins->dreg, 1);
4415 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4416 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4417 ppc_li (code, ins->dreg, 0);
4418 break;
4419 case OP_FCGT:
4420 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4421 ppc_li (code, ins->dreg, 1);
4422 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4423 ppc_li (code, ins->dreg, 0);
4424 break;
4425 case OP_FCGT_UN:
4426 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4427 ppc_li (code, ins->dreg, 1);
4428 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4429 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4430 ppc_li (code, ins->dreg, 0);
4431 break;
4432 case OP_FBEQ:
4433 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4434 break;
4435 case OP_FBNE_UN:
4436 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4437 break;
4438 case OP_FBLT:
4439 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4440 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4441 break;
4442 case OP_FBLT_UN:
4443 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4444 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4445 break;
4446 case OP_FBGT:
4447 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4448 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4449 break;
4450 case OP_FBGT_UN:
4451 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4452 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4453 break;
4454 case OP_FBGE:
4455 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4456 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4457 break;
4458 case OP_FBGE_UN:
4459 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4460 break;
4461 case OP_FBLE:
4462 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4463 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4464 break;
4465 case OP_FBLE_UN:
4466 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4467 break;
4468 case OP_CKFINITE:
4469 g_assert_not_reached ();
4470 case OP_CHECK_FINITE: {
4471 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4472 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4473 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4474 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4475 break;
4476 case OP_JUMP_TABLE:
4477 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4478 #ifdef __mono_ppc64__
4479 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4480 #else
4481 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4482 #endif
4483 break;
4486 #ifdef __mono_ppc64__
4487 case OP_ICONV_TO_I4:
4488 case OP_SEXT_I4:
4489 ppc_extsw (code, ins->dreg, ins->sreg1);
4490 break;
4491 case OP_ICONV_TO_U4:
4492 case OP_ZEXT_I4:
4493 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4494 break;
4495 case OP_ICONV_TO_R4:
4496 case OP_ICONV_TO_R8:
4497 case OP_LCONV_TO_R4:
4498 case OP_LCONV_TO_R8: {
4499 int tmp;
4500 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4501 ppc_extsw (code, ppc_r0, ins->sreg1);
4502 tmp = ppc_r0;
4503 } else {
4504 tmp = ins->sreg1;
4506 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4507 ppc_mffgpr (code, ins->dreg, tmp);
4508 } else {
4509 ppc_str (code, tmp, -8, ppc_r1);
4510 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4512 ppc_fcfid (code, ins->dreg, ins->dreg);
4513 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4514 ppc_frsp (code, ins->dreg, ins->dreg);
4515 break;
4517 case OP_LSHR:
4518 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4519 break;
4520 case OP_LSHR_UN:
4521 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4522 break;
4523 case OP_COND_EXC_C:
4524 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4526 ppc_mfspr (code, ppc_r0, ppc_xer);
4527 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4528 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4529 break;
4530 case OP_COND_EXC_OV:
4531 ppc_mfspr (code, ppc_r0, ppc_xer);
4532 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4533 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4534 break;
4535 case OP_LBEQ:
4536 case OP_LBNE_UN:
4537 case OP_LBLT:
4538 case OP_LBLT_UN:
4539 case OP_LBGT:
4540 case OP_LBGT_UN:
4541 case OP_LBGE:
4542 case OP_LBGE_UN:
4543 case OP_LBLE:
4544 case OP_LBLE_UN:
4545 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4546 break;
4547 case OP_FCONV_TO_I8:
4548 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4549 break;
4550 case OP_FCONV_TO_U8:
4551 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4552 break;
4553 case OP_STOREI4_MEMBASE_REG:
4554 if (ppc_is_imm16 (ins->inst_offset)) {
4555 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4556 } else {
4557 ppc_load (code, ppc_r0, ins->inst_offset);
4558 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4560 break;
4561 case OP_STOREI4_MEMINDEX:
4562 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4563 break;
4564 case OP_ISHR_IMM:
4565 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4566 break;
4567 case OP_ISHR_UN_IMM:
4568 if (ins->inst_imm & 0x1f)
4569 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4570 else
4571 ppc_mr (code, ins->dreg, ins->sreg1);
4572 break;
4573 case OP_ATOMIC_ADD_NEW_I4:
4574 case OP_ATOMIC_ADD_NEW_I8: {
4575 guint8 *loop = code, *branch;
4576 g_assert (ins->inst_offset == 0);
4577 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4578 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4579 else
4580 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4581 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4582 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4583 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4584 else
4585 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4586 branch = code;
4587 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4588 ppc_patch (branch, loop);
4589 ppc_mr (code, ins->dreg, ppc_r0);
4590 break;
4592 #else
4593 case OP_ICONV_TO_R4:
4594 case OP_ICONV_TO_R8: {
4595 if (cpu_hw_caps & PPC_ISA_64) {
4596 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4597 ppc_stw (code, ppc_r0, -8, ppc_r1);
4598 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4599 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4600 ppc_fcfid (code, ins->dreg, ins->dreg);
4601 if (ins->opcode == OP_ICONV_TO_R4)
4602 ppc_frsp (code, ins->dreg, ins->dreg);
4604 break;
4606 #endif
4607 case OP_ATOMIC_CAS_I4:
4608 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4609 int location = ins->sreg1;
4610 int value = ins->sreg2;
4611 int comparand = ins->sreg3;
4612 guint8 *start, *not_equal, *lost_reservation;
4614 start = code;
4615 if (ins->opcode == OP_ATOMIC_CAS_I4)
4616 ppc_lwarx (code, ppc_r0, 0, location);
4617 #ifdef __mono_ppc64__
4618 else
4619 ppc_ldarx (code, ppc_r0, 0, location);
4620 #endif
4621 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4623 not_equal = code;
4624 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4625 if (ins->opcode == OP_ATOMIC_CAS_I4)
4626 ppc_stwcxd (code, value, 0, location);
4627 #ifdef __mono_ppc64__
4628 else
4629 ppc_stdcxd (code, value, 0, location);
4630 #endif
4632 lost_reservation = code;
4633 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4634 ppc_patch (lost_reservation, start);
4636 ppc_patch (not_equal, code);
4637 ppc_mr (code, ins->dreg, ppc_r0);
4638 break;
4641 default:
4642 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4643 g_assert_not_reached ();
4646 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4647 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4648 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4649 g_assert_not_reached ();
4652 cpos += max_len;
4654 last_ins = ins;
4655 last_offset = offset;
4658 cfg->code_len = code - cfg->native_code;
4660 #endif /* !DISABLE_JIT */
4662 void
4663 mono_arch_register_lowlevel_calls (void)
4665 /* The signature doesn't matter */
4666 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4669 #ifdef __mono_ppc64__
4670 #define patch_load_sequence(ip,val) do {\
4671 guint16 *__load = (guint16*)(ip); \
4672 g_assert (sizeof (val) == sizeof (gsize)); \
4673 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4674 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4675 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4676 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4677 } while (0)
4678 #else
4679 #define patch_load_sequence(ip,val) do {\
4680 guint16 *__lis_ori = (guint16*)(ip); \
4681 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4682 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4683 } while (0)
4684 #endif
4686 #ifndef DISABLE_JIT
4687 void
4688 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4690 MonoJumpInfo *patch_info;
4691 gboolean compile_aot = !run_cctors;
4693 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4694 unsigned char *ip = patch_info->ip.i + code;
4695 unsigned char *target;
4696 gboolean is_fd = FALSE;
4698 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4700 if (compile_aot) {
4701 switch (patch_info->type) {
4702 case MONO_PATCH_INFO_BB:
4703 case MONO_PATCH_INFO_LABEL:
4704 break;
4705 default:
4706 /* No need to patch these */
4707 continue;
4711 switch (patch_info->type) {
4712 case MONO_PATCH_INFO_IP:
4713 patch_load_sequence (ip, ip);
4714 continue;
4715 case MONO_PATCH_INFO_METHOD_REL:
4716 g_assert_not_reached ();
4717 *((gpointer *)(ip)) = code + patch_info->data.offset;
4718 continue;
4719 case MONO_PATCH_INFO_SWITCH: {
4720 gpointer *table = (gpointer *)patch_info->data.table->table;
4721 int i;
4723 patch_load_sequence (ip, table);
4725 for (i = 0; i < patch_info->data.table->table_size; i++) {
4726 table [i] = (glong)patch_info->data.table->table [i] + code;
4728 /* we put into the table the absolute address, no need for ppc_patch in this case */
4729 continue;
4731 case MONO_PATCH_INFO_METHODCONST:
4732 case MONO_PATCH_INFO_CLASS:
4733 case MONO_PATCH_INFO_IMAGE:
4734 case MONO_PATCH_INFO_FIELD:
4735 case MONO_PATCH_INFO_VTABLE:
4736 case MONO_PATCH_INFO_IID:
4737 case MONO_PATCH_INFO_SFLDA:
4738 case MONO_PATCH_INFO_LDSTR:
4739 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4740 case MONO_PATCH_INFO_LDTOKEN:
4741 /* from OP_AOTCONST : lis + ori */
4742 patch_load_sequence (ip, target);
4743 continue;
4744 case MONO_PATCH_INFO_R4:
4745 case MONO_PATCH_INFO_R8:
4746 g_assert_not_reached ();
4747 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4748 continue;
4749 case MONO_PATCH_INFO_EXC_NAME:
4750 g_assert_not_reached ();
4751 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4752 continue;
4753 case MONO_PATCH_INFO_NONE:
4754 case MONO_PATCH_INFO_BB_OVF:
4755 case MONO_PATCH_INFO_EXC_OVF:
4756 /* everything is dealt with at epilog output time */
4757 continue;
4758 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4759 case MONO_PATCH_INFO_INTERNAL_METHOD:
4760 case MONO_PATCH_INFO_ABS:
4761 case MONO_PATCH_INFO_CLASS_INIT:
4762 case MONO_PATCH_INFO_RGCTX_FETCH:
4763 is_fd = TRUE;
4764 break;
4765 #endif
4766 default:
4767 break;
4769 ppc_patch_full (ip, target, is_fd);
4774 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4775 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4776 * the instruction offset immediate for all the registers.
4778 static guint8*
4779 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4781 int i;
4782 if (!save_lmf) {
4783 for (i = 13; i <= 31; i++) {
4784 if (used_int_regs & (1 << i)) {
4785 ppc_str (code, i, pos, base_reg);
4786 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4787 pos += sizeof (mgreg_t);
4790 } else {
4791 /* pos is the start of the MonoLMF structure */
4792 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4793 for (i = 13; i <= 31; i++) {
4794 ppc_str (code, i, offset, base_reg);
4795 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4796 offset += sizeof (mgreg_t);
4798 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4799 for (i = 14; i < 32; i++) {
4800 ppc_stfd (code, i, offset, base_reg);
4801 offset += sizeof (gdouble);
4804 return code;
4808 * Stack frame layout:
4810 * ------------------- sp
4811 * MonoLMF structure or saved registers
4812 * -------------------
4813 * spilled regs
4814 * -------------------
4815 * locals
4816 * -------------------
4817 * optional 8 bytes for tracing
4818 * -------------------
4819 * param area size is cfg->param_area
4820 * -------------------
4821 * linkage area size is PPC_STACK_PARAM_OFFSET
4822 * ------------------- sp
4823 * red zone
4825 guint8 *
4826 mono_arch_emit_prolog (MonoCompile *cfg)
4828 MonoMethod *method = cfg->method;
4829 MonoBasicBlock *bb;
4830 MonoMethodSignature *sig;
4831 MonoInst *inst;
4832 long alloc_size, pos, max_offset, cfa_offset;
4833 int i;
4834 guint8 *code;
4835 CallInfo *cinfo;
4836 int tracing = 0;
4837 int lmf_offset = 0;
4838 int tailcall_struct_index;
4840 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4841 tracing = 1;
4843 sig = mono_method_signature (method);
4844 cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4845 code = cfg->native_code = g_malloc (cfg->code_size);
4847 cfa_offset = 0;
4849 /* We currently emit unwind info for aot, but don't use it */
4850 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4852 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4853 ppc_mflr (code, ppc_r0);
4854 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4855 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4858 alloc_size = cfg->stack_offset;
4859 pos = 0;
4861 if (!method->save_lmf) {
4862 for (i = 31; i >= 13; --i) {
4863 if (cfg->used_int_regs & (1 << i)) {
4864 pos += sizeof (mgreg_t);
4867 } else {
4868 pos += sizeof (MonoLMF);
4869 lmf_offset = pos;
4871 alloc_size += pos;
4872 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4873 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4874 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4875 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4878 cfg->stack_usage = alloc_size;
4879 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4880 if (alloc_size) {
4881 if (ppc_is_imm16 (-alloc_size)) {
4882 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4883 cfa_offset = alloc_size;
4884 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4885 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4886 } else {
4887 if (pos)
4888 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4889 ppc_load (code, ppc_r0, -alloc_size);
4890 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4891 cfa_offset = alloc_size;
4892 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4893 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4896 if (cfg->frame_reg != ppc_sp) {
4897 ppc_mr (code, cfg->frame_reg, ppc_sp);
4898 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4901 /* store runtime generic context */
4902 if (cfg->rgctx_var) {
4903 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4904 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4906 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4909 /* compute max_offset in order to use short forward jumps
4910 * we always do it on ppc because the immediate displacement
4911 * for jumps is too small
4913 max_offset = 0;
4914 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4915 MonoInst *ins;
4916 bb->max_offset = max_offset;
4918 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4919 max_offset += 6;
4921 MONO_BB_FOR_EACH_INS (bb, ins)
4922 max_offset += ins_native_length (cfg, ins);
4925 /* load arguments allocated to register from the stack */
4926 pos = 0;
4928 cinfo = calculate_sizes (sig, sig->pinvoke);
4930 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4931 ArgInfo *ainfo = &cinfo->ret;
4933 inst = cfg->vret_addr;
4934 g_assert (inst);
4936 if (ppc_is_imm16 (inst->inst_offset)) {
4937 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4938 } else {
4939 ppc_load (code, ppc_r11, inst->inst_offset);
4940 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4944 tailcall_struct_index = 0;
4945 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4946 ArgInfo *ainfo = cinfo->args + i;
4947 inst = cfg->args [pos];
4949 if (cfg->verbose_level > 2)
4950 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4951 if (inst->opcode == OP_REGVAR) {
4952 if (ainfo->regtype == RegTypeGeneral)
4953 ppc_mr (code, inst->dreg, ainfo->reg);
4954 else if (ainfo->regtype == RegTypeFP)
4955 ppc_fmr (code, inst->dreg, ainfo->reg);
4956 else if (ainfo->regtype == RegTypeBase) {
4957 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4958 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4959 } else
4960 g_assert_not_reached ();
4962 if (cfg->verbose_level > 2)
4963 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4964 } else {
4965 /* the argument should be put on the stack: FIXME handle size != word */
4966 if (ainfo->regtype == RegTypeGeneral) {
4967 switch (ainfo->size) {
4968 case 1:
4969 if (ppc_is_imm16 (inst->inst_offset)) {
4970 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4971 } else {
4972 if (ppc_is_imm32 (inst->inst_offset)) {
4973 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4974 ppc_stb (code, ainfo->reg, ppc_r11, inst->inst_offset);
4975 } else {
4976 ppc_load (code, ppc_r11, inst->inst_offset);
4977 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4980 break;
4981 case 2:
4982 if (ppc_is_imm16 (inst->inst_offset)) {
4983 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4984 } else {
4985 if (ppc_is_imm32 (inst->inst_offset)) {
4986 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4987 ppc_sth (code, ainfo->reg, ppc_r11, inst->inst_offset);
4988 } else {
4989 ppc_load (code, ppc_r11, inst->inst_offset);
4990 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4993 break;
4994 #ifdef __mono_ppc64__
4995 case 4:
4996 if (ppc_is_imm16 (inst->inst_offset)) {
4997 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4998 } else {
4999 if (ppc_is_imm32 (inst->inst_offset)) {
5000 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5001 ppc_stw (code, ainfo->reg, ppc_r11, inst->inst_offset);
5002 } else {
5003 ppc_load (code, ppc_r11, inst->inst_offset);
5004 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5007 break;
5008 case 8:
5009 if (ppc_is_imm16 (inst->inst_offset)) {
5010 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5011 } else {
5012 ppc_load (code, ppc_r11, inst->inst_offset);
5013 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
5015 break;
5016 #else
5017 case 8:
5018 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5019 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5020 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5021 } else {
5022 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5023 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5024 ppc_stw (code, ainfo->reg, 0, ppc_r11);
5025 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
5027 break;
5028 #endif
5029 default:
5030 if (ppc_is_imm16 (inst->inst_offset)) {
5031 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5032 } else {
5033 if (ppc_is_imm32 (inst->inst_offset)) {
5034 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5035 ppc_stptr (code, ainfo->reg, ppc_r11, inst->inst_offset);
5036 } else {
5037 ppc_load (code, ppc_r11, inst->inst_offset);
5038 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5041 break;
5043 } else if (ainfo->regtype == RegTypeBase) {
5044 g_assert (ppc_is_imm16 (ainfo->offset));
5045 /* load the previous stack pointer in r11 */
5046 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5047 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
5048 switch (ainfo->size) {
5049 case 1:
5050 if (ppc_is_imm16 (inst->inst_offset)) {
5051 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5052 } else {
5053 if (ppc_is_imm32 (inst->inst_offset)) {
5054 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5055 ppc_stb (code, ppc_r0, ppc_r11, inst->inst_offset);
5056 } else {
5057 ppc_load (code, ppc_r11, inst->inst_offset);
5058 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5061 break;
5062 case 2:
5063 if (ppc_is_imm16 (inst->inst_offset)) {
5064 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5065 } else {
5066 if (ppc_is_imm32 (inst->inst_offset)) {
5067 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5068 ppc_sth (code, ppc_r0, ppc_r11, inst->inst_offset);
5069 } else {
5070 ppc_load (code, ppc_r11, inst->inst_offset);
5071 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5074 break;
5075 #ifdef __mono_ppc64__
5076 case 4:
5077 if (ppc_is_imm16 (inst->inst_offset)) {
5078 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5079 } else {
5080 if (ppc_is_imm32 (inst->inst_offset)) {
5081 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5082 ppc_stw (code, ppc_r0, ppc_r11, inst->inst_offset);
5083 } else {
5084 ppc_load (code, ppc_r11, inst->inst_offset);
5085 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5088 break;
5089 case 8:
5090 if (ppc_is_imm16 (inst->inst_offset)) {
5091 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5092 } else {
5093 ppc_load (code, ppc_r11, inst->inst_offset);
5094 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
5096 break;
5097 #else
5098 case 8:
5099 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5100 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5101 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5102 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
5103 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5104 } else {
5105 /* use r12 to load the 2nd half of the long before we clobber r11. */
5106 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
5107 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5108 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5109 ppc_stw (code, ppc_r0, 0, ppc_r11);
5110 ppc_stw (code, ppc_r12, 4, ppc_r11);
5112 break;
5113 #endif
5114 default:
5115 if (ppc_is_imm16 (inst->inst_offset)) {
5116 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5117 } else {
5118 if (ppc_is_imm32 (inst->inst_offset)) {
5119 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5120 ppc_stptr (code, ppc_r0, ppc_r11, inst->inst_offset);
5121 } else {
5122 ppc_load (code, ppc_r11, inst->inst_offset);
5123 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
5126 break;
5128 } else if (ainfo->regtype == RegTypeFP) {
5129 g_assert (ppc_is_imm16 (inst->inst_offset));
5130 if (ainfo->size == 8)
5131 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5132 else if (ainfo->size == 4)
5133 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5134 else
5135 g_assert_not_reached ();
5136 } else if (ainfo->regtype == RegTypeStructByVal) {
5137 int doffset = inst->inst_offset;
5138 int soffset = 0;
5139 int cur_reg;
5140 int size = 0;
5141 g_assert (ppc_is_imm16 (inst->inst_offset));
5142 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5143 /* FIXME: what if there is no class? */
5144 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5145 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5146 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5147 #if __APPLE__
5149 * Darwin handles 1 and 2 byte
5150 * structs specially by
5151 * loading h/b into the arg
5152 * register. Only done for
5153 * pinvokes.
5155 if (size == 2)
5156 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5157 else if (size == 1)
5158 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5159 else
5160 #endif
5162 #ifdef __mono_ppc64__
5163 if (ainfo->bytes) {
5164 g_assert (cur_reg == 0);
5165 ppc_sldi (code, ppc_r0, ainfo->reg,
5166 (sizeof (gpointer) - ainfo->bytes) * 8);
5167 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5168 } else
5169 #endif
5171 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5172 inst->inst_basereg);
5175 soffset += sizeof (gpointer);
5176 doffset += sizeof (gpointer);
5178 if (ainfo->vtsize) {
5179 /* FIXME: we need to do the shifting here, too */
5180 if (ainfo->bytes)
5181 NOT_IMPLEMENTED;
5182 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5183 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5184 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5185 code = emit_memcpy (code, size - soffset,
5186 inst->inst_basereg, doffset,
5187 ppc_r11, ainfo->offset + soffset);
5188 } else {
5189 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5190 inst->inst_basereg, doffset,
5191 ppc_r11, ainfo->offset + soffset);
5194 } else if (ainfo->regtype == RegTypeStructByAddr) {
5195 /* if it was originally a RegTypeBase */
5196 if (ainfo->offset) {
5197 /* load the previous stack pointer in r11 */
5198 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5199 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5200 } else {
5201 ppc_mr (code, ppc_r11, ainfo->reg);
5204 if (cfg->tailcall_valuetype_addrs) {
5205 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5207 g_assert (ppc_is_imm16 (addr->inst_offset));
5208 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5210 tailcall_struct_index++;
5213 g_assert (ppc_is_imm16 (inst->inst_offset));
5214 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5215 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5216 } else
5217 g_assert_not_reached ();
5219 pos++;
5222 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5223 if (cfg->compile_aot)
5224 /* AOT code is only used in the root domain */
5225 ppc_load_ptr (code, ppc_r3, 0);
5226 else
5227 ppc_load_ptr (code, ppc_r3, cfg->domain);
5228 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
5229 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5230 ppc_load_func (code, ppc_r0, 0);
5231 ppc_mtlr (code, ppc_r0);
5232 ppc_blrl (code);
5233 } else {
5234 ppc_bl (code, 0);
5238 if (method->save_lmf) {
5239 if (lmf_pthread_key != -1) {
5240 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5241 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5242 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5243 } else {
5244 if (cfg->compile_aot) {
5245 /* Compute the got address which is needed by the PLT entry */
5246 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5248 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5249 (gpointer)"mono_get_lmf_addr");
5250 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5251 ppc_load_func (code, ppc_r0, 0);
5252 ppc_mtlr (code, ppc_r0);
5253 ppc_blrl (code);
5254 } else {
5255 ppc_bl (code, 0);
5258 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5259 /* lmf_offset is the offset from the previous stack pointer,
5260 * alloc_size is the total stack space allocated, so the offset
5261 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5262 * The pointer to the struct is put in ppc_r11 (new_lmf).
5263 * The callee-saved registers are already in the MonoLMF structure
5265 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5266 /* ppc_r3 is the result from mono_get_lmf_addr () */
5267 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5268 /* new_lmf->previous_lmf = *lmf_addr */
5269 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5270 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5271 /* *(lmf_addr) = r11 */
5272 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5273 /* save method info */
5274 if (cfg->compile_aot)
5275 // FIXME:
5276 ppc_load (code, ppc_r0, 0);
5277 else
5278 ppc_load_ptr (code, ppc_r0, method);
5279 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5280 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5281 /* save the current IP */
5282 if (cfg->compile_aot) {
5283 ppc_bl (code, 1);
5284 ppc_mflr (code, ppc_r0);
5285 } else {
5286 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5287 #ifdef __mono_ppc64__
5288 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5289 #else
5290 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5291 #endif
5293 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5296 if (tracing)
5297 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5299 cfg->code_len = code - cfg->native_code;
5300 g_assert (cfg->code_len <= cfg->code_size);
5301 g_free (cinfo);
5303 return code;
5306 void
5307 mono_arch_emit_epilog (MonoCompile *cfg)
5309 MonoMethod *method = cfg->method;
5310 int pos, i;
5311 int max_epilog_size = 16 + 20*4;
5312 guint8 *code;
5314 if (cfg->method->save_lmf)
5315 max_epilog_size += 128;
5317 if (mono_jit_trace_calls != NULL)
5318 max_epilog_size += 50;
5320 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5321 max_epilog_size += 50;
5323 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5324 cfg->code_size *= 2;
5325 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5326 mono_jit_stats.code_reallocs++;
5330 * Keep in sync with OP_JMP
5332 code = cfg->native_code + cfg->code_len;
5334 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5335 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5337 pos = 0;
5339 if (method->save_lmf) {
5340 int lmf_offset;
5341 pos += sizeof (MonoLMF);
5342 lmf_offset = pos;
5343 /* save the frame reg in r8 */
5344 ppc_mr (code, ppc_r8, cfg->frame_reg);
5345 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5346 /* r5 = previous_lmf */
5347 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5348 /* r6 = lmf_addr */
5349 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5350 /* *(lmf_addr) = previous_lmf */
5351 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5352 /* FIXME: speedup: there is no actual need to restore the registers if
5353 * we didn't actually change them (idea from Zoltan).
5355 /* restore iregs */
5356 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5357 /* restore fregs */
5358 /*for (i = 14; i < 32; i++) {
5359 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5361 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5362 /* use the saved copy of the frame reg in r8 */
5363 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5364 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5365 ppc_mtlr (code, ppc_r0);
5367 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5368 } else {
5369 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5370 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5371 if (ppc_is_imm16 (return_offset)) {
5372 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5373 } else {
5374 ppc_load (code, ppc_r11, return_offset);
5375 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5377 ppc_mtlr (code, ppc_r0);
5379 if (ppc_is_imm16 (cfg->stack_usage)) {
5380 int offset = cfg->stack_usage;
5381 for (i = 13; i <= 31; i++) {
5382 if (cfg->used_int_regs & (1 << i))
5383 offset -= sizeof (mgreg_t);
5385 if (cfg->frame_reg != ppc_sp)
5386 ppc_mr (code, ppc_r11, cfg->frame_reg);
5387 /* note r31 (possibly the frame register) is restored last */
5388 for (i = 13; i <= 31; i++) {
5389 if (cfg->used_int_regs & (1 << i)) {
5390 ppc_ldr (code, i, offset, cfg->frame_reg);
5391 offset += sizeof (mgreg_t);
5394 if (cfg->frame_reg != ppc_sp)
5395 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5396 else
5397 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5398 } else {
5399 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5400 if (cfg->used_int_regs) {
5401 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5402 for (i = 31; i >= 13; --i) {
5403 if (cfg->used_int_regs & (1 << i)) {
5404 pos += sizeof (mgreg_t);
5405 ppc_ldr (code, i, -pos, ppc_r11);
5408 ppc_mr (code, ppc_sp, ppc_r11);
5409 } else {
5410 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5415 ppc_blr (code);
5417 cfg->code_len = code - cfg->native_code;
5419 g_assert (cfg->code_len < cfg->code_size);
5422 #endif /* ifndef DISABLE_JIT */
5424 /* remove once throw_exception_by_name is eliminated */
5425 static int
5426 exception_id_by_name (const char *name)
5428 if (strcmp (name, "IndexOutOfRangeException") == 0)
5429 return MONO_EXC_INDEX_OUT_OF_RANGE;
5430 if (strcmp (name, "OverflowException") == 0)
5431 return MONO_EXC_OVERFLOW;
5432 if (strcmp (name, "ArithmeticException") == 0)
5433 return MONO_EXC_ARITHMETIC;
5434 if (strcmp (name, "DivideByZeroException") == 0)
5435 return MONO_EXC_DIVIDE_BY_ZERO;
5436 if (strcmp (name, "InvalidCastException") == 0)
5437 return MONO_EXC_INVALID_CAST;
5438 if (strcmp (name, "NullReferenceException") == 0)
5439 return MONO_EXC_NULL_REF;
5440 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5441 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5442 g_error ("Unknown intrinsic exception %s\n", name);
5443 return 0;
5446 #ifndef DISABLE_JIT
5447 void
5448 mono_arch_emit_exceptions (MonoCompile *cfg)
5450 MonoJumpInfo *patch_info;
5451 int i;
5452 guint8 *code;
5453 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5454 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5455 int max_epilog_size = 50;
5457 /* count the number of exception infos */
5460 * make sure we have enough space for exceptions
5462 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5463 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5464 i = exception_id_by_name (patch_info->data.target);
5465 if (!exc_throw_found [i]) {
5466 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5467 exc_throw_found [i] = TRUE;
5469 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5470 max_epilog_size += 12;
5471 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5472 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5473 i = exception_id_by_name (ovfj->data.exception);
5474 if (!exc_throw_found [i]) {
5475 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5476 exc_throw_found [i] = TRUE;
5478 max_epilog_size += 8;
5482 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5483 cfg->code_size *= 2;
5484 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5485 mono_jit_stats.code_reallocs++;
5488 code = cfg->native_code + cfg->code_len;
5490 /* add code to raise exceptions */
5491 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5492 switch (patch_info->type) {
5493 case MONO_PATCH_INFO_BB_OVF: {
5494 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5495 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5496 /* patch the initial jump */
5497 ppc_patch (ip, code);
5498 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5499 ppc_b (code, 0);
5500 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5501 /* jump back to the true target */
5502 ppc_b (code, 0);
5503 ip = ovfj->data.bb->native_offset + cfg->native_code;
5504 ppc_patch (code - 4, ip);
5505 patch_info->type = MONO_PATCH_INFO_NONE;
5506 break;
5508 case MONO_PATCH_INFO_EXC_OVF: {
5509 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5510 MonoJumpInfo *newji;
5511 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5512 unsigned char *bcl = code;
5513 /* patch the initial jump: we arrived here with a call */
5514 ppc_patch (ip, code);
5515 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5516 ppc_b (code, 0);
5517 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5518 /* patch the conditional jump to the right handler */
5519 /* make it processed next */
5520 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5521 newji->type = MONO_PATCH_INFO_EXC;
5522 newji->ip.i = bcl - cfg->native_code;
5523 newji->data.target = ovfj->data.exception;
5524 newji->next = patch_info->next;
5525 patch_info->next = newji;
5526 patch_info->type = MONO_PATCH_INFO_NONE;
5527 break;
5529 case MONO_PATCH_INFO_EXC: {
5530 MonoClass *exc_class;
5532 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5533 i = exception_id_by_name (patch_info->data.target);
5534 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5535 ppc_patch (ip, exc_throw_pos [i]);
5536 patch_info->type = MONO_PATCH_INFO_NONE;
5537 break;
5538 } else {
5539 exc_throw_pos [i] = code;
5542 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5543 g_assert (exc_class);
5545 ppc_patch (ip, code);
5546 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5547 ppc_load (code, ppc_r3, exc_class->type_token);
5548 /* we got here from a conditional call, so the calling ip is set in lr */
5549 ppc_mflr (code, ppc_r4);
5550 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5551 patch_info->data.name = "mono_arch_throw_corlib_exception";
5552 patch_info->ip.i = code - cfg->native_code;
5553 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5554 ppc_load_func (code, ppc_r0, 0);
5555 ppc_mtctr (code, ppc_r0);
5556 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5557 } else {
5558 ppc_bl (code, 0);
5560 break;
5562 default:
5563 /* do nothing */
5564 break;
5568 cfg->code_len = code - cfg->native_code;
5570 g_assert (cfg->code_len <= cfg->code_size);
5572 #endif
5574 #if DEAD_CODE
5575 static int
5576 try_offset_access (void *value, guint32 idx)
5578 register void* me __asm__ ("r2");
5579 void ***p = (void***)((char*)me + 284);
5580 int idx1 = idx / 32;
5581 int idx2 = idx % 32;
5582 if (!p [idx1])
5583 return 0;
5584 if (value != p[idx1][idx2])
5585 return 0;
5586 return 1;
5588 #endif
5590 static void
5591 setup_tls_access (void)
5593 guint32 ptk;
5595 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5596 size_t conf_size = 0;
5597 char confbuf[128];
5598 #else
5599 /* FIXME for darwin */
5600 guint32 *ins, *code;
5601 guint32 cmplwi_1023, li_0x48, blr_ins;
5602 #endif
5604 #ifdef TARGET_PS3
5605 tls_mode = TLS_MODE_FAILED;
5606 #endif
5608 if (tls_mode == TLS_MODE_FAILED)
5609 return;
5610 if (g_getenv ("MONO_NO_TLS")) {
5611 tls_mode = TLS_MODE_FAILED;
5612 return;
5615 if (tls_mode == TLS_MODE_DETECT) {
5616 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5617 tls_mode = TLS_MODE_DARWIN_G4;
5618 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5619 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5620 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5621 tls_mode = TLS_MODE_NPTL;
5622 #elif !defined(TARGET_PS3)
5623 ins = (guint32*)pthread_getspecific;
5624 /* uncond branch to the real method */
5625 if ((*ins >> 26) == 18) {
5626 gint32 val;
5627 val = (*ins & ~3) << 6;
5628 val >>= 6;
5629 if (*ins & 2) {
5630 /* absolute */
5631 ins = (guint32*)(long)val;
5632 } else {
5633 ins = (guint32*) ((char*)ins + val);
5636 code = &cmplwi_1023;
5637 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5638 code = &li_0x48;
5639 ppc_li (code, ppc_r4, 0x48);
5640 code = &blr_ins;
5641 ppc_blr (code);
5642 if (*ins == cmplwi_1023) {
5643 int found_lwz_284 = 0;
5644 for (ptk = 0; ptk < 20; ++ptk) {
5645 ++ins;
5646 if (!*ins || *ins == blr_ins)
5647 break;
5648 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5649 found_lwz_284 = 1;
5650 break;
5653 if (!found_lwz_284) {
5654 tls_mode = TLS_MODE_FAILED;
5655 return;
5657 tls_mode = TLS_MODE_LTHREADS;
5658 } else if (*ins == li_0x48) {
5659 ++ins;
5660 /* uncond branch to the real method */
5661 if ((*ins >> 26) == 18) {
5662 gint32 val;
5663 val = (*ins & ~3) << 6;
5664 val >>= 6;
5665 if (*ins & 2) {
5666 /* absolute */
5667 ins = (guint32*)(long)val;
5668 } else {
5669 ins = (guint32*) ((char*)ins + val);
5671 code = (guint32*)&val;
5672 ppc_li (code, ppc_r0, 0x7FF2);
5673 if (ins [1] == val) {
5674 /* Darwin on G4, implement */
5675 tls_mode = TLS_MODE_FAILED;
5676 return;
5677 } else {
5678 code = (guint32*)&val;
5679 ppc_mfspr (code, ppc_r3, 104);
5680 if (ins [1] != val) {
5681 tls_mode = TLS_MODE_FAILED;
5682 return;
5684 tls_mode = TLS_MODE_DARWIN_G5;
5686 } else {
5687 tls_mode = TLS_MODE_FAILED;
5688 return;
5690 } else {
5691 tls_mode = TLS_MODE_FAILED;
5692 return;
5694 #endif
5696 #ifndef TARGET_PS3
5697 if (tls_mode == TLS_MODE_DETECT)
5698 tls_mode = TLS_MODE_FAILED;
5699 if (tls_mode == TLS_MODE_FAILED)
5700 return;
5701 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5702 monodomain_key = mono_domain_get_tls_offset();
5704 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5705 mono_domain_get_tls_offset returning -1) then use keyed access. */
5706 if (monodomain_key == -1) {
5707 ptk = mono_domain_get_tls_key ();
5708 if (ptk < 1024) {
5709 ptk = mono_pthread_key_for_tls (ptk);
5710 if (ptk < 1024) {
5711 monodomain_key = ptk;
5716 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5717 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5719 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5720 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5721 if (lmf_pthread_key == -1) {
5722 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5723 if (ptk < 1024) {
5724 /*g_print ("MonoLMF at: %d\n", ptk);*/
5725 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5726 init_tls_failed = 1;
5727 return;
5729 lmf_pthread_key = ptk;
5732 #endif
5735 void
5736 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5738 setup_tls_access ();
5741 void
5742 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5746 #ifdef MONO_ARCH_HAVE_IMT
5748 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5749 #define BR_SIZE 4
5750 #define LOADSTORE_SIZE 4
5751 #define JUMP_IMM_SIZE 12
5752 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5753 #define ENABLE_WRONG_METHOD_CHECK 0
5756 * LOCKING: called with the domain lock held
5758 gpointer
5759 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5760 gpointer fail_tramp)
5762 int i;
5763 int size = 0;
5764 guint8 *code, *start;
5766 for (i = 0; i < count; ++i) {
5767 MonoIMTCheckItem *item = imt_entries [i];
5768 if (item->is_equals) {
5769 if (item->check_target_idx) {
5770 if (!item->compare_done)
5771 item->chunk_size += CMP_SIZE;
5772 if (item->has_target_code)
5773 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5774 else
5775 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5776 } else {
5777 if (fail_tramp) {
5778 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5779 if (!item->has_target_code)
5780 item->chunk_size += LOADSTORE_SIZE;
5781 } else {
5782 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5783 #if ENABLE_WRONG_METHOD_CHECK
5784 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5785 #endif
5788 } else {
5789 item->chunk_size += CMP_SIZE + BR_SIZE;
5790 imt_entries [item->check_target_idx]->compare_done = TRUE;
5792 size += item->chunk_size;
5794 /* the initial load of the vtable address */
5795 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5796 if (fail_tramp) {
5797 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5798 } else {
5799 code = mono_domain_code_reserve (domain, size);
5801 start = code;
5804 * We need to save and restore r11 because it might be
5805 * used by the caller as the vtable register, so
5806 * clobbering it will trip up the magic trampoline.
5808 * FIXME: Get rid of this by making sure that r11 is
5809 * not used as the vtable register in interface calls.
5811 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5812 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5814 for (i = 0; i < count; ++i) {
5815 MonoIMTCheckItem *item = imt_entries [i];
5816 item->code_target = code;
5817 if (item->is_equals) {
5818 if (item->check_target_idx) {
5819 if (!item->compare_done) {
5820 ppc_load (code, ppc_r0, (gsize)item->key);
5821 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5823 item->jmp_code = code;
5824 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5825 if (item->has_target_code) {
5826 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5827 } else {
5828 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5829 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5831 ppc_mtctr (code, ppc_r0);
5832 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5833 } else {
5834 if (fail_tramp) {
5835 ppc_load (code, ppc_r0, (gulong)item->key);
5836 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5837 item->jmp_code = code;
5838 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5839 if (item->has_target_code) {
5840 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5841 } else {
5842 g_assert (vtable);
5843 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5844 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5846 ppc_mtctr (code, ppc_r0);
5847 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5848 ppc_patch (item->jmp_code, code);
5849 ppc_load_ptr (code, ppc_r0, fail_tramp);
5850 ppc_mtctr (code, ppc_r0);
5851 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5852 item->jmp_code = NULL;
5853 } else {
5854 /* enable the commented code to assert on wrong method */
5855 #if ENABLE_WRONG_METHOD_CHECK
5856 ppc_load (code, ppc_r0, (guint32)item->key);
5857 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5858 item->jmp_code = code;
5859 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5860 #endif
5861 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5862 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5863 ppc_mtctr (code, ppc_r0);
5864 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5865 #if ENABLE_WRONG_METHOD_CHECK
5866 ppc_patch (item->jmp_code, code);
5867 ppc_break (code);
5868 item->jmp_code = NULL;
5869 #endif
5872 } else {
5873 ppc_load (code, ppc_r0, (gulong)item->key);
5874 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5875 item->jmp_code = code;
5876 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5879 /* patch the branches to get to the target items */
5880 for (i = 0; i < count; ++i) {
5881 MonoIMTCheckItem *item = imt_entries [i];
5882 if (item->jmp_code) {
5883 if (item->check_target_idx) {
5884 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5889 if (!fail_tramp)
5890 mono_stats.imt_thunks_size += code - start;
5891 g_assert (code - start <= size);
5892 mono_arch_flush_icache (start, size);
5893 return start;
5896 MonoMethod*
5897 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5899 mgreg_t *r = (mgreg_t*)regs;
5901 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5903 #endif
5905 MonoVTable*
5906 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5908 mgreg_t *r = (mgreg_t*)regs;
5910 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5913 MonoInst*
5914 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5916 /* FIXME: */
5917 return NULL;
5920 gboolean
5921 mono_arch_print_tree (MonoInst *tree, int arity)
5923 return 0;
5926 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5928 MonoInst* ins;
5930 setup_tls_access ();
5931 if (monodomain_key == -1)
5932 return NULL;
5934 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5935 ins->inst_offset = monodomain_key;
5936 return ins;
5939 gpointer
5940 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5942 if (reg == ppc_r1)
5943 return MONO_CONTEXT_GET_SP (ctx);
5945 g_assert (reg >= ppc_r13);
5947 return (gpointer)(gsize)ctx->regs [reg - ppc_r13];
5950 guint32
5951 mono_arch_get_patch_offset (guint8 *code)
5953 return 0;
5957 * mono_aot_emit_load_got_addr:
5959 * Emit code to load the got address.
5960 * On PPC, the result is placed into r30.
5962 guint8*
5963 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5965 ppc_bl (code, 1);
5966 ppc_mflr (code, ppc_r30);
5967 if (cfg)
5968 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5969 else
5970 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5971 /* arch_emit_got_address () patches this */
5972 #if defined(TARGET_POWERPC64)
5973 ppc_nop (code);
5974 ppc_nop (code);
5975 ppc_nop (code);
5976 ppc_nop (code);
5977 #else
5978 ppc_load32 (code, ppc_r0, 0);
5979 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5980 #endif
5982 return code;
5986 * mono_ppc_emit_load_aotconst:
5988 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5989 * TARGET from the mscorlib GOT in full-aot code.
5990 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5991 * r11.
5993 guint8*
5994 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5996 /* Load the mscorlib got address */
5997 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5998 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5999 /* arch_emit_got_access () patches this */
6000 ppc_load32 (code, ppc_r0, 0);
6001 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
6003 return code;
6006 /* Soft Debug support */
6007 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6010 * BREAKPOINTS
6014 * mono_arch_set_breakpoint:
6016 * See mini-amd64.c for docs.
6018 void
6019 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6021 guint8 *code = ip;
6022 guint8 *orig_code = code;
6024 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
6025 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
6027 g_assert (code - orig_code == BREAKPOINT_SIZE);
6029 mono_arch_flush_icache (orig_code, code - orig_code);
6033 * mono_arch_clear_breakpoint:
6035 * See mini-amd64.c for docs.
6037 void
6038 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6040 guint8 *code = ip;
6041 int i;
6043 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6044 ppc_nop (code);
6046 mono_arch_flush_icache (ip, code - ip);
6050 * mono_arch_is_breakpoint_event:
6052 * See mini-amd64.c for docs.
6054 gboolean
6055 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6057 siginfo_t* sinfo = (siginfo_t*) info;
6058 /* Sometimes the address is off by 4 */
6059 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6060 return TRUE;
6061 else
6062 return FALSE;
6066 * mono_arch_get_ip_for_breakpoint:
6068 * See mini-amd64.c for docs.
6070 guint8*
6071 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
6073 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6075 /* ip points at the ldptr instruction */
6076 ip -= PPC_LOAD_SEQUENCE_LENGTH;
6078 return ip;
6082 * mono_arch_skip_breakpoint:
6084 * See mini-amd64.c for docs.
6086 void
6087 mono_arch_skip_breakpoint (MonoContext *ctx)
6089 /* skip the ldptr */
6090 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6094 * SINGLE STEPPING
6098 * mono_arch_start_single_stepping:
6100 * See mini-amd64.c for docs.
6102 void
6103 mono_arch_start_single_stepping (void)
6105 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6109 * mono_arch_stop_single_stepping:
6111 * See mini-amd64.c for docs.
6113 void
6114 mono_arch_stop_single_stepping (void)
6116 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6120 * mono_arch_is_single_step_event:
6122 * See mini-amd64.c for docs.
6124 gboolean
6125 mono_arch_is_single_step_event (void *info, void *sigctx)
6127 siginfo_t* sinfo = (siginfo_t*) info;
6128 /* Sometimes the address is off by 4 */
6129 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6130 return TRUE;
6131 else
6132 return FALSE;
6136 * mono_arch_get_ip_for_single_step:
6138 * See mini-amd64.c for docs.
6140 guint8*
6141 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
6143 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6145 /* ip points after the ldptr instruction */
6146 return ip;
6150 * mono_arch_skip_single_step:
6152 * See mini-amd64.c for docs.
6154 void
6155 mono_arch_skip_single_step (MonoContext *ctx)
6157 /* skip the ldptr */
6158 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6162 * mono_arch_create_seq_point_info:
6164 * See mini-amd64.c for docs.
6166 gpointer
6167 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6169 NOT_IMPLEMENTED;
6170 return NULL;
6173 #endif