update rx (mobile builds).
[mono-project.git] / mono / mini / mini-ppc.c
blobe779862c46e361dd4b5788d7fd80191b4ff64ef0
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 (MonoGenericSharingContext *gsctx, 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 /* ld || lwz */
345 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
347 /* code must point to the blrl */
348 gboolean
349 mono_ppc_is_direct_call_sequence (guint32 *code)
351 #ifdef __mono_ppc64__
352 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
354 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
355 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
356 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
357 if (!is_load_sequence (&code [-8]))
358 return FALSE;
359 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
360 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
361 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
363 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
364 return is_load_sequence (&code [-8]);
365 else
366 return is_load_sequence (&code [-6]);
368 return FALSE;
369 #else
370 g_assert(*code == 0x4e800021);
372 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
373 return ppc_opcode (code [-1]) == 31 &&
374 ppc_opcode (code [-2]) == 24 &&
375 ppc_opcode (code [-3]) == 15;
376 #endif
379 #define MAX_ARCH_DELEGATE_PARAMS 7
381 static gpointer
382 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
384 guint8 *code, *start;
386 if (has_target) {
387 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
389 start = code = mono_global_codeman_reserve (size);
390 if (!aot)
391 code = mono_ppc_create_pre_code_ftnptr (code);
393 /* Replace the this argument with the target */
394 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
395 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
396 /* it's a function descriptor */
397 /* Can't use ldptr as it doesn't work with r0 */
398 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
399 #endif
400 ppc_mtctr (code, ppc_r0);
401 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
402 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
404 g_assert ((code - start) <= size);
406 mono_arch_flush_icache (start, size);
407 } else {
408 int size, i;
410 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
411 start = code = mono_global_codeman_reserve (size);
412 if (!aot)
413 code = mono_ppc_create_pre_code_ftnptr (code);
415 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
417 /* it's a function descriptor */
418 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
419 #endif
420 ppc_mtctr (code, ppc_r0);
421 /* slide down the arguments */
422 for (i = 0; i < param_count; ++i) {
423 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
425 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
427 g_assert ((code - start) <= size);
429 mono_arch_flush_icache (start, size);
432 if (code_len)
433 *code_len = code - start;
435 return start;
438 GSList*
439 mono_arch_get_delegate_invoke_impls (void)
441 GSList *res = NULL;
442 guint8 *code;
443 guint32 code_len;
444 int i;
446 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
447 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
449 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
450 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
451 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
454 return res;
457 gpointer
458 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
460 guint8 *code, *start;
462 /* FIXME: Support more cases */
463 if (MONO_TYPE_ISSTRUCT (sig->ret))
464 return NULL;
466 if (has_target) {
467 static guint8* cached = NULL;
469 if (cached)
470 return cached;
472 if (mono_aot_only)
473 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
474 else
475 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
477 mono_memory_barrier ();
479 cached = start;
480 } else {
481 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
482 int i;
484 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
485 return NULL;
486 for (i = 0; i < sig->param_count; ++i)
487 if (!mono_is_regsize_var (sig->params [i]))
488 return NULL;
491 code = cache [sig->param_count];
492 if (code)
493 return code;
495 if (mono_aot_only) {
496 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
497 start = mono_aot_get_trampoline (name);
498 g_free (name);
499 } else {
500 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
503 mono_memory_barrier ();
505 cache [sig->param_count] = start;
507 return start;
510 gpointer
511 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
513 mgreg_t *r = (mgreg_t*)regs;
515 return (gpointer)(gsize)r [ppc_r3];
518 typedef struct {
519 long int type;
520 long int value;
521 } AuxVec;
523 #ifdef USE_ENVIRON_HACK
524 static AuxVec*
525 linux_find_auxv (int *count)
527 AuxVec *vec;
528 int c = 0;
529 char **result = __environ;
530 /* Scan over the env vector looking for the ending NULL */
531 for (; *result != NULL; ++result) {
533 /* Bump the pointer one more step, which should be the auxv. */
534 ++result;
535 vec = (AuxVec *)result;
536 if (vec->type != 22 /*AT_IGNOREPPC*/) {
537 *count = 0;
538 return NULL;
540 while (vec->type != 0 /*AT_NULL*/) {
541 vec++;
542 c++;
544 *count = c;
545 return (AuxVec *)result;
547 #endif
549 #define MAX_AUX_ENTRIES 128
551 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
552 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
554 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
556 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
557 #define ISA_64 0x40000000
559 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
560 #define ISA_MOVE_FPR_GPR 0x00000200
562 * Initialize the cpu to execute managed code.
564 void
565 mono_arch_cpu_init (void)
570 * Initialize architecture specific code.
572 void
573 mono_arch_init (void)
575 #if defined(MONO_CROSS_COMPILE)
576 #elif defined(__APPLE__)
577 int mib [3];
578 size_t len;
579 mib [0] = CTL_HW;
580 mib [1] = HW_CACHELINE;
581 len = sizeof (cachelinesize);
582 if (sysctl (mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
583 perror ("sysctl");
584 cachelinesize = 128;
585 } else {
586 cachelineinc = cachelinesize;
588 #elif defined(__linux__)
589 AuxVec vec [MAX_AUX_ENTRIES];
590 int i, vec_entries = 0;
591 /* sadly this will work only with 2.6 kernels... */
592 FILE* f = fopen ("/proc/self/auxv", "rb");
593 if (f) {
594 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
595 fclose (f);
596 #ifdef USE_ENVIRON_HACK
597 } else {
598 AuxVec *evec = linux_find_auxv (&vec_entries);
599 if (vec_entries)
600 memcpy (&vec, evec, sizeof (AuxVec) * MIN (vec_entries, MAX_AUX_ENTRIES));
601 #endif
603 for (i = 0; i < vec_entries; i++) {
604 int type = vec [i].type;
605 if (type == 19) { /* AT_DCACHEBSIZE */
606 cachelinesize = vec [i].value;
607 continue;
608 } else if (type == 16) { /* AT_HWCAP */
609 if (vec [i].value & 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
610 cpu_hw_caps |= PPC_ICACHE_SNOOP;
611 if (vec [i].value & ISA_2X)
612 cpu_hw_caps |= PPC_ISA_2X;
613 if (vec [i].value & ISA_64)
614 cpu_hw_caps |= PPC_ISA_64;
615 if (vec [i].value & ISA_MOVE_FPR_GPR)
616 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
617 continue;
618 } else if (type == 15) { /* AT_PLATFORM */
619 const char *arch = (char*)vec [i].value;
620 if (strcmp (arch, "ppc970") == 0 ||
621 (strncmp (arch, "power", 5) == 0 && arch [5] >= '4' && arch [5] <= '7'))
622 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
623 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
624 continue;
627 #elif defined(G_COMPILER_CODEWARRIOR)
628 cachelinesize = 32;
629 cachelineinc = 32;
630 #else
631 //#error Need a way to get cache line size
632 #endif
633 if (!cachelinesize)
634 cachelinesize = 32;
635 if (!cachelineinc)
636 cachelineinc = cachelinesize;
638 if (mono_cpu_count () > 1)
639 cpu_hw_caps |= PPC_SMP_CAPABLE;
640 InitializeCriticalSection (&mini_arch_mutex);
642 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
643 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
644 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
646 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
650 * Cleanup architecture specific code.
652 void
653 mono_arch_cleanup (void)
655 DeleteCriticalSection (&mini_arch_mutex);
659 * This function returns the optimizations supported on this cpu.
661 guint32
662 mono_arch_cpu_optimizations (guint32 *exclude_mask)
664 guint32 opts = 0;
666 /* no ppc-specific optimizations yet */
667 *exclude_mask = 0;
668 return opts;
672 * This function test for all SIMD functions supported.
674 * Returns a bitmask corresponding to all supported versions.
677 guint32
678 mono_arch_cpu_enumerate_simd_versions (void)
680 /* SIMD is currently unimplemented */
681 return 0;
684 #ifdef __mono_ppc64__
685 #define CASE_PPC32(c)
686 #define CASE_PPC64(c) case c:
687 #else
688 #define CASE_PPC32(c) case c:
689 #define CASE_PPC64(c)
690 #endif
692 static gboolean
693 is_regsize_var (MonoType *t) {
694 if (t->byref)
695 return TRUE;
696 t = mini_type_get_underlying_type (NULL, t);
697 switch (t->type) {
698 case MONO_TYPE_I4:
699 case MONO_TYPE_U4:
700 CASE_PPC64 (MONO_TYPE_I8)
701 CASE_PPC64 (MONO_TYPE_U8)
702 case MONO_TYPE_I:
703 case MONO_TYPE_U:
704 case MONO_TYPE_PTR:
705 case MONO_TYPE_FNPTR:
706 return TRUE;
707 case MONO_TYPE_OBJECT:
708 case MONO_TYPE_STRING:
709 case MONO_TYPE_CLASS:
710 case MONO_TYPE_SZARRAY:
711 case MONO_TYPE_ARRAY:
712 return TRUE;
713 case MONO_TYPE_GENERICINST:
714 if (!mono_type_generic_inst_is_valuetype (t))
715 return TRUE;
716 return FALSE;
717 case MONO_TYPE_VALUETYPE:
718 return FALSE;
720 return FALSE;
723 #ifndef DISABLE_JIT
724 GList *
725 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
727 GList *vars = NULL;
728 int i;
730 for (i = 0; i < cfg->num_varinfo; i++) {
731 MonoInst *ins = cfg->varinfo [i];
732 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
734 /* unused vars */
735 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
736 continue;
738 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
739 continue;
741 /* we can only allocate 32 bit values */
742 if (is_regsize_var (ins->inst_vtype)) {
743 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
744 g_assert (i == vmv->idx);
745 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
749 return vars;
751 #endif /* ifndef DISABLE_JIT */
753 GList *
754 mono_arch_get_global_int_regs (MonoCompile *cfg)
756 GList *regs = NULL;
757 int i, top = 32;
758 if (cfg->frame_reg != ppc_sp)
759 top = 31;
760 /* ppc_r13 is used by the system on PPC EABI */
761 for (i = 14; i < top; ++i) {
763 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
764 * since the trampolines can clobber r11.
766 if (!(cfg->compile_aot && i == 29))
767 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
770 return regs;
774 * mono_arch_regalloc_cost:
776 * Return the cost, in number of memory references, of the action of
777 * allocating the variable VMV into a register during global register
778 * allocation.
780 guint32
781 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
783 /* FIXME: */
784 return 2;
787 void
788 mono_arch_flush_icache (guint8 *code, gint size)
790 #ifdef MONO_CROSS_COMPILE
791 #else
792 register guint8 *p;
793 guint8 *endp, *start;
795 p = start = code;
796 endp = p + size;
797 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
798 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
799 #if defined(G_COMPILER_CODEWARRIOR)
800 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
801 for (p = start; p < endp; p += cachelineinc) {
802 asm { dcbf 0, p };
804 } else {
805 for (p = start; p < endp; p += cachelineinc) {
806 asm { dcbst 0, p };
809 asm { sync };
810 p = code;
811 for (p = start; p < endp; p += cachelineinc) {
812 asm {
813 icbi 0, p
814 sync
817 asm {
818 sync
819 isync
821 #else
822 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
823 * The sync is required to insure that the store queue is completely empty.
824 * While the icbi performs no cache operations, icbi/isync is required to
825 * kill local prefetch.
827 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
828 asm ("sync");
829 asm ("icbi 0,%0;" : : "r"(code) : "memory");
830 asm ("isync");
831 return;
833 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
834 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
835 for (p = start; p < endp; p += cachelineinc) {
836 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
838 } else {
839 for (p = start; p < endp; p += cachelineinc) {
840 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
843 asm ("sync");
844 p = code;
845 for (p = start; p < endp; p += cachelineinc) {
846 /* for ISA2.0+ implementations we should not need any extra sync between the
847 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
848 * So I am not sure which chip had this problem but its not an issue on
849 * of the ISA V2 chips.
851 if (cpu_hw_caps & PPC_ISA_2X)
852 asm ("icbi 0,%0;" : : "r"(p) : "memory");
853 else
854 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
856 if (!(cpu_hw_caps & PPC_ISA_2X))
857 asm ("sync");
858 asm ("isync");
859 #endif
860 #endif
863 void
864 mono_arch_flush_register_windows (void)
868 #ifdef __APPLE__
869 #define ALWAYS_ON_STACK(s) s
870 #define FP_ALSO_IN_REG(s) s
871 #else
872 #ifdef __mono_ppc64__
873 #define ALWAYS_ON_STACK(s) s
874 #define FP_ALSO_IN_REG(s) s
875 #else
876 #define ALWAYS_ON_STACK(s)
877 #define FP_ALSO_IN_REG(s)
878 #endif
879 #define ALIGN_DOUBLES
880 #endif
882 enum {
883 RegTypeGeneral,
884 RegTypeBase,
885 RegTypeFP,
886 RegTypeStructByVal,
887 RegTypeStructByAddr
890 typedef struct {
891 gint32 offset;
892 guint32 vtsize; /* in param area */
893 guint8 reg;
894 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
895 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
896 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
897 guint8 bytes : 4; /* size in bytes - only valid for
898 RegTypeStructByVal if the struct fits
899 in one word, otherwise it's 0*/
900 } ArgInfo;
902 typedef struct {
903 int nargs;
904 guint32 stack_usage;
905 guint32 struct_ret;
906 ArgInfo ret;
907 ArgInfo sig_cookie;
908 gboolean vtype_retaddr;
909 int vret_arg_index;
910 ArgInfo args [1];
911 } CallInfo;
913 #define DEBUG(a)
915 static void inline
916 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
918 #ifdef __mono_ppc64__
919 g_assert (simple);
920 #endif
922 if (simple) {
923 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
924 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
925 ainfo->reg = ppc_sp; /* in the caller */
926 ainfo->regtype = RegTypeBase;
927 *stack_size += sizeof (gpointer);
928 } else {
929 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
930 ainfo->reg = *gr;
932 } else {
933 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
934 #ifdef ALIGN_DOUBLES
935 //*stack_size += (*stack_size % 8);
936 #endif
937 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
938 ainfo->reg = ppc_sp; /* in the caller */
939 ainfo->regtype = RegTypeBase;
940 *stack_size += 8;
941 } else {
942 #ifdef ALIGN_DOUBLES
943 if (!((*gr) & 1))
944 (*gr) ++;
945 #endif
946 ALWAYS_ON_STACK (*stack_size += 8);
947 ainfo->reg = *gr;
949 (*gr) ++;
951 (*gr) ++;
954 #if defined(__APPLE__) || defined(__mono_ppc64__)
955 static gboolean
956 has_only_a_r48_field (MonoClass *klass)
958 gpointer iter;
959 MonoClassField *f;
960 gboolean have_field = FALSE;
961 iter = NULL;
962 while ((f = mono_class_get_fields (klass, &iter))) {
963 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
964 if (have_field)
965 return FALSE;
966 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
967 have_field = TRUE;
968 else
969 return FALSE;
972 return have_field;
974 #endif
976 static CallInfo*
977 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
979 guint i, fr, gr, pstart;
980 int n = sig->hasthis + sig->param_count;
981 MonoType *simpletype;
982 guint32 stack_size = 0;
983 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
984 gboolean is_pinvoke = sig->pinvoke;
986 fr = PPC_FIRST_FPARG_REG;
987 gr = PPC_FIRST_ARG_REG;
989 /* FIXME: handle returning a struct */
990 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
991 cinfo->vtype_retaddr = TRUE;
994 pstart = 0;
995 n = 0;
997 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
998 * the first argument, allowing 'this' to be always passed in the first arg reg.
999 * Also do this if the first argument is a reference type, since virtual calls
1000 * are sometimes made using calli without sig->hasthis set, like in the delegate
1001 * invoke wrappers.
1003 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1004 if (sig->hasthis) {
1005 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1006 n ++;
1007 } else {
1008 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1009 pstart = 1;
1010 n ++;
1012 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1013 cinfo->struct_ret = cinfo->ret.reg;
1014 cinfo->vret_arg_index = 1;
1015 } else {
1016 /* this */
1017 if (sig->hasthis) {
1018 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1019 n ++;
1022 if (cinfo->vtype_retaddr) {
1023 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1024 cinfo->struct_ret = cinfo->ret.reg;
1028 DEBUG(printf("params: %d\n", sig->param_count));
1029 for (i = pstart; i < sig->param_count; ++i) {
1030 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1031 /* Prevent implicit arguments and sig_cookie from
1032 being passed in registers */
1033 gr = PPC_LAST_ARG_REG + 1;
1034 /* FIXME: don't we have to set fr, too? */
1035 /* Emit the signature cookie just before the implicit arguments */
1036 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1038 DEBUG(printf("param %d: ", i));
1039 if (sig->params [i]->byref) {
1040 DEBUG(printf("byref\n"));
1041 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1042 n++;
1043 continue;
1045 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1046 switch (simpletype->type) {
1047 case MONO_TYPE_BOOLEAN:
1048 case MONO_TYPE_I1:
1049 case MONO_TYPE_U1:
1050 cinfo->args [n].size = 1;
1051 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1052 n++;
1053 break;
1054 case MONO_TYPE_CHAR:
1055 case MONO_TYPE_I2:
1056 case MONO_TYPE_U2:
1057 cinfo->args [n].size = 2;
1058 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1059 n++;
1060 break;
1061 case MONO_TYPE_I4:
1062 case MONO_TYPE_U4:
1063 cinfo->args [n].size = 4;
1064 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1065 n++;
1066 break;
1067 case MONO_TYPE_I:
1068 case MONO_TYPE_U:
1069 case MONO_TYPE_PTR:
1070 case MONO_TYPE_FNPTR:
1071 case MONO_TYPE_CLASS:
1072 case MONO_TYPE_OBJECT:
1073 case MONO_TYPE_STRING:
1074 case MONO_TYPE_SZARRAY:
1075 case MONO_TYPE_ARRAY:
1076 cinfo->args [n].size = sizeof (gpointer);
1077 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1078 n++;
1079 break;
1080 case MONO_TYPE_GENERICINST:
1081 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1082 cinfo->args [n].size = sizeof (gpointer);
1083 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1084 n++;
1085 break;
1087 /* Fall through */
1088 case MONO_TYPE_VALUETYPE:
1089 case MONO_TYPE_TYPEDBYREF: {
1090 gint size;
1091 MonoClass *klass;
1093 klass = mono_class_from_mono_type (sig->params [i]);
1094 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1095 size = sizeof (MonoTypedRef);
1096 else if (is_pinvoke)
1097 size = mono_class_native_size (klass, NULL);
1098 else
1099 size = mono_class_value_size (klass, NULL);
1101 #if defined(__APPLE__) || defined(__mono_ppc64__)
1102 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1103 cinfo->args [n].size = size;
1105 /* It was 7, now it is 8 in LinuxPPC */
1106 if (fr <= PPC_LAST_FPARG_REG) {
1107 cinfo->args [n].regtype = RegTypeFP;
1108 cinfo->args [n].reg = fr;
1109 fr ++;
1110 FP_ALSO_IN_REG (gr ++);
1111 if (size == 8)
1112 FP_ALSO_IN_REG (gr ++);
1113 ALWAYS_ON_STACK (stack_size += size);
1114 } else {
1115 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1116 cinfo->args [n].regtype = RegTypeBase;
1117 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1118 stack_size += 8;
1120 n++;
1121 break;
1123 #endif
1124 DEBUG(printf ("load %d bytes struct\n",
1125 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1127 #if PPC_PASS_STRUCTS_BY_VALUE
1129 int align_size = size;
1130 int nregs = 0;
1131 int rest = PPC_LAST_ARG_REG - gr + 1;
1132 int n_in_regs;
1134 align_size += (sizeof (gpointer) - 1);
1135 align_size &= ~(sizeof (gpointer) - 1);
1136 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1137 n_in_regs = MIN (rest, nregs);
1138 if (n_in_regs < 0)
1139 n_in_regs = 0;
1140 #ifdef __APPLE__
1141 /* FIXME: check this */
1142 if (size >= 3 && size % 4 != 0)
1143 n_in_regs = 0;
1144 #endif
1145 cinfo->args [n].regtype = RegTypeStructByVal;
1146 cinfo->args [n].vtregs = n_in_regs;
1147 cinfo->args [n].size = n_in_regs;
1148 cinfo->args [n].vtsize = nregs - n_in_regs;
1149 cinfo->args [n].reg = gr;
1151 #ifdef __mono_ppc64__
1152 if (nregs == 1 && is_pinvoke)
1153 cinfo->args [n].bytes = size;
1154 else
1155 #endif
1156 cinfo->args [n].bytes = 0;
1157 gr += n_in_regs;
1158 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1159 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1160 stack_size += nregs * sizeof (gpointer);
1162 #else
1163 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1164 cinfo->args [n].regtype = RegTypeStructByAddr;
1165 cinfo->args [n].vtsize = size;
1166 #endif
1167 n++;
1168 break;
1170 case MONO_TYPE_U8:
1171 case MONO_TYPE_I8:
1172 cinfo->args [n].size = 8;
1173 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1174 n++;
1175 break;
1176 case MONO_TYPE_R4:
1177 cinfo->args [n].size = 4;
1179 /* It was 7, now it is 8 in LinuxPPC */
1180 if (fr <= PPC_LAST_FPARG_REG) {
1181 cinfo->args [n].regtype = RegTypeFP;
1182 cinfo->args [n].reg = fr;
1183 fr ++;
1184 FP_ALSO_IN_REG (gr ++);
1185 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1186 } else {
1187 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1188 cinfo->args [n].regtype = RegTypeBase;
1189 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1190 stack_size += SIZEOF_REGISTER;
1192 n++;
1193 break;
1194 case MONO_TYPE_R8:
1195 cinfo->args [n].size = 8;
1196 /* It was 7, now it is 8 in LinuxPPC */
1197 if (fr <= PPC_LAST_FPARG_REG) {
1198 cinfo->args [n].regtype = RegTypeFP;
1199 cinfo->args [n].reg = fr;
1200 fr ++;
1201 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1202 ALWAYS_ON_STACK (stack_size += 8);
1203 } else {
1204 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1205 cinfo->args [n].regtype = RegTypeBase;
1206 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1207 stack_size += 8;
1209 n++;
1210 break;
1211 default:
1212 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1215 cinfo->nargs = n;
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 gboolean
1281 mono_ppc_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1283 CallInfo *c1, *c2;
1284 gboolean res;
1285 int i;
1287 c1 = get_call_info (NULL, caller_sig);
1288 c2 = get_call_info (NULL, callee_sig);
1289 res = c1->stack_usage >= c2->stack_usage;
1290 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1291 /* An address on the callee's stack is passed as the first argument */
1292 res = FALSE;
1293 for (i = 0; i < c2->nargs; ++i) {
1294 if (c2->args [i].regtype == RegTypeStructByAddr)
1295 /* An address on the callee's stack is passed as the argument */
1296 res = FALSE;
1300 if (!mono_debug_count ())
1301 res = FALSE;
1304 g_free (c1);
1305 g_free (c2);
1307 return res;
1311 * Set var information according to the calling convention. ppc version.
1312 * The locals var stuff should most likely be split in another method.
1314 void
1315 mono_arch_allocate_vars (MonoCompile *m)
1317 MonoMethodSignature *sig;
1318 MonoMethodHeader *header;
1319 MonoInst *inst;
1320 int i, offset, size, align, curinst;
1321 int frame_reg = ppc_sp;
1322 gint32 *offsets;
1323 guint32 locals_stack_size, locals_stack_align;
1325 m->flags |= MONO_CFG_HAS_SPILLUP;
1327 /* allow room for the vararg method args: void* and long/double */
1328 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1329 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1330 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1331 * call convs needs to be handled this way.
1333 if (m->flags & MONO_CFG_HAS_VARARGS)
1334 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1335 /* gtk-sharp and other broken code will dllimport vararg functions even with
1336 * non-varargs signatures. Since there is little hope people will get this right
1337 * we assume they won't.
1339 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1340 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1342 header = m->header;
1345 * We use the frame register also for any method that has
1346 * exception clauses. This way, when the handlers are called,
1347 * the code will reference local variables using the frame reg instead of
1348 * the stack pointer: if we had to restore the stack pointer, we'd
1349 * corrupt the method frames that are already on the stack (since
1350 * filters get called before stack unwinding happens) when the filter
1351 * code would call any method (this also applies to finally etc.).
1353 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1354 frame_reg = ppc_r31;
1355 m->frame_reg = frame_reg;
1356 if (frame_reg != ppc_sp) {
1357 m->used_int_regs |= 1 << frame_reg;
1360 sig = mono_method_signature (m->method);
1362 offset = 0;
1363 curinst = 0;
1364 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1365 m->ret->opcode = OP_REGVAR;
1366 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1367 } else {
1368 /* FIXME: handle long values? */
1369 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1370 case MONO_TYPE_VOID:
1371 break;
1372 case MONO_TYPE_R4:
1373 case MONO_TYPE_R8:
1374 m->ret->opcode = OP_REGVAR;
1375 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1376 break;
1377 default:
1378 m->ret->opcode = OP_REGVAR;
1379 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1380 break;
1383 /* local vars are at a positive offset from the stack pointer */
1385 * also note that if the function uses alloca, we use ppc_r31
1386 * to point at the local variables.
1388 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1389 /* align the offset to 16 bytes: not sure this is needed here */
1390 //offset += 16 - 1;
1391 //offset &= ~(16 - 1);
1393 /* add parameter area size for called functions */
1394 offset += m->param_area;
1395 offset += 16 - 1;
1396 offset &= ~(16 - 1);
1398 /* allow room to save the return value */
1399 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1400 offset += 8;
1402 /* the MonoLMF structure is stored just below the stack pointer */
1404 #if 0
1405 /* this stuff should not be needed on ppc and the new jit,
1406 * because a call on ppc to the handlers doesn't change the
1407 * stack pointer and the jist doesn't manipulate the stack pointer
1408 * for operations involving valuetypes.
1410 /* reserve space to store the esp */
1411 offset += sizeof (gpointer);
1413 /* this is a global constant */
1414 mono_exc_esp_offset = offset;
1415 #endif
1417 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1418 offset += sizeof(gpointer) - 1;
1419 offset &= ~(sizeof(gpointer) - 1);
1421 m->vret_addr->opcode = OP_REGOFFSET;
1422 m->vret_addr->inst_basereg = frame_reg;
1423 m->vret_addr->inst_offset = offset;
1425 if (G_UNLIKELY (m->verbose_level > 1)) {
1426 printf ("vret_addr =");
1427 mono_print_ins (m->vret_addr);
1430 offset += sizeof(gpointer);
1433 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1434 if (locals_stack_align) {
1435 offset += (locals_stack_align - 1);
1436 offset &= ~(locals_stack_align - 1);
1438 for (i = m->locals_start; i < m->num_varinfo; i++) {
1439 if (offsets [i] != -1) {
1440 MonoInst *inst = m->varinfo [i];
1441 inst->opcode = OP_REGOFFSET;
1442 inst->inst_basereg = frame_reg;
1443 inst->inst_offset = offset + offsets [i];
1445 g_print ("allocating local %d (%s) to %d\n",
1446 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1450 offset += locals_stack_size;
1452 curinst = 0;
1453 if (sig->hasthis) {
1454 inst = m->args [curinst];
1455 if (inst->opcode != OP_REGVAR) {
1456 inst->opcode = OP_REGOFFSET;
1457 inst->inst_basereg = frame_reg;
1458 offset += sizeof (gpointer) - 1;
1459 offset &= ~(sizeof (gpointer) - 1);
1460 inst->inst_offset = offset;
1461 offset += sizeof (gpointer);
1463 curinst++;
1466 for (i = 0; i < sig->param_count; ++i) {
1467 inst = m->args [curinst];
1468 if (inst->opcode != OP_REGVAR) {
1469 inst->opcode = OP_REGOFFSET;
1470 inst->inst_basereg = frame_reg;
1471 if (sig->pinvoke) {
1472 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1473 inst->backend.is_pinvoke = 1;
1474 } else {
1475 size = mono_type_size (sig->params [i], &align);
1477 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1478 size = align = sizeof (gpointer);
1480 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1481 * they are saved using std in the prolog.
1483 align = sizeof (gpointer);
1484 offset += align - 1;
1485 offset &= ~(align - 1);
1486 inst->inst_offset = offset;
1487 offset += size;
1489 curinst++;
1492 /* some storage for fp conversions */
1493 offset += 8 - 1;
1494 offset &= ~(8 - 1);
1495 m->arch.fp_conv_var_offset = offset;
1496 offset += 8;
1498 /* align the offset to 16 bytes */
1499 offset += 16 - 1;
1500 offset &= ~(16 - 1);
1502 /* change sign? */
1503 m->stack_offset = offset;
1505 if (sig->call_convention == MONO_CALL_VARARG) {
1506 CallInfo *cinfo = get_call_info (m->generic_sharing_context, m->method->signature);
1508 m->sig_cookie = cinfo->sig_cookie.offset;
1510 g_free(cinfo);
1514 void
1515 mono_arch_create_vars (MonoCompile *cfg)
1517 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1519 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1520 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1524 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1525 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1528 static void
1529 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1531 int sig_reg = mono_alloc_ireg (cfg);
1533 /* FIXME: Add support for signature tokens to AOT */
1534 cfg->disable_aot = TRUE;
1536 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1537 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1538 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1541 void
1542 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1544 MonoInst *in, *ins;
1545 MonoMethodSignature *sig;
1546 int i, n;
1547 CallInfo *cinfo;
1549 sig = call->signature;
1550 n = sig->param_count + sig->hasthis;
1552 cinfo = get_call_info (cfg->generic_sharing_context, sig);
1554 for (i = 0; i < n; ++i) {
1555 ArgInfo *ainfo = cinfo->args + i;
1556 MonoType *t;
1558 if (i >= sig->hasthis)
1559 t = sig->params [i - sig->hasthis];
1560 else
1561 t = &mono_defaults.int_class->byval_arg;
1562 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1564 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1565 emit_sig_cookie (cfg, call, cinfo);
1567 in = call->args [i];
1569 if (ainfo->regtype == RegTypeGeneral) {
1570 #ifndef __mono_ppc64__
1571 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1572 MONO_INST_NEW (cfg, ins, OP_MOVE);
1573 ins->dreg = mono_alloc_ireg (cfg);
1574 ins->sreg1 = in->dreg + 1;
1575 MONO_ADD_INS (cfg->cbb, ins);
1576 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1578 MONO_INST_NEW (cfg, ins, OP_MOVE);
1579 ins->dreg = mono_alloc_ireg (cfg);
1580 ins->sreg1 = in->dreg + 2;
1581 MONO_ADD_INS (cfg->cbb, ins);
1582 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1583 } else
1584 #endif
1586 MONO_INST_NEW (cfg, ins, OP_MOVE);
1587 ins->dreg = mono_alloc_ireg (cfg);
1588 ins->sreg1 = in->dreg;
1589 MONO_ADD_INS (cfg->cbb, ins);
1591 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1593 } else if (ainfo->regtype == RegTypeStructByAddr) {
1594 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1595 ins->opcode = OP_OUTARG_VT;
1596 ins->sreg1 = in->dreg;
1597 ins->klass = in->klass;
1598 ins->inst_p0 = call;
1599 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1600 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1601 MONO_ADD_INS (cfg->cbb, ins);
1602 } else if (ainfo->regtype == RegTypeStructByVal) {
1603 /* this is further handled in mono_arch_emit_outarg_vt () */
1604 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1605 ins->opcode = OP_OUTARG_VT;
1606 ins->sreg1 = in->dreg;
1607 ins->klass = in->klass;
1608 ins->inst_p0 = call;
1609 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1610 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1611 MONO_ADD_INS (cfg->cbb, ins);
1612 } else if (ainfo->regtype == RegTypeBase) {
1613 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1614 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1615 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1616 if (t->type == MONO_TYPE_R8)
1617 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1618 else
1619 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1620 } else {
1621 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1623 } else if (ainfo->regtype == RegTypeFP) {
1624 if (t->type == MONO_TYPE_VALUETYPE) {
1625 /* this is further handled in mono_arch_emit_outarg_vt () */
1626 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1627 ins->opcode = OP_OUTARG_VT;
1628 ins->sreg1 = in->dreg;
1629 ins->klass = in->klass;
1630 ins->inst_p0 = call;
1631 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1632 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1633 MONO_ADD_INS (cfg->cbb, ins);
1635 cfg->flags |= MONO_CFG_HAS_FPOUT;
1636 } else {
1637 int dreg = mono_alloc_freg (cfg);
1639 if (ainfo->size == 4) {
1640 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1641 } else {
1642 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1643 ins->dreg = dreg;
1644 ins->sreg1 = in->dreg;
1645 MONO_ADD_INS (cfg->cbb, ins);
1648 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1649 cfg->flags |= MONO_CFG_HAS_FPOUT;
1651 } else {
1652 g_assert_not_reached ();
1656 /* Emit the signature cookie in the case that there is no
1657 additional argument */
1658 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1659 emit_sig_cookie (cfg, call, cinfo);
1661 if (cinfo->struct_ret) {
1662 MonoInst *vtarg;
1664 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1665 vtarg->sreg1 = call->vret_var->dreg;
1666 vtarg->dreg = mono_alloc_preg (cfg);
1667 MONO_ADD_INS (cfg->cbb, vtarg);
1669 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1672 call->stack_usage = cinfo->stack_usage;
1673 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1674 cfg->flags |= MONO_CFG_HAS_CALLS;
1676 g_free (cinfo);
1679 #ifndef DISABLE_JIT
1681 void
1682 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1684 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1685 ArgInfo *ainfo = ins->inst_p1;
1686 int ovf_size = ainfo->vtsize;
1687 int doffset = ainfo->offset;
1688 int i, soffset, dreg;
1690 if (ainfo->regtype == RegTypeStructByVal) {
1691 #ifdef __APPLE__
1692 guint32 size = 0;
1693 #endif
1694 soffset = 0;
1695 #ifdef __APPLE__
1697 * Darwin pinvokes needs some special handling for 1
1698 * and 2 byte arguments
1700 g_assert (ins->klass);
1701 if (call->signature->pinvoke)
1702 size = mono_class_native_size (ins->klass, NULL);
1703 if (size == 2 || size == 1) {
1704 int tmpr = mono_alloc_ireg (cfg);
1705 if (size == 1)
1706 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1707 else
1708 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1709 dreg = mono_alloc_ireg (cfg);
1710 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1711 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1712 } else
1713 #endif
1714 for (i = 0; i < ainfo->vtregs; ++i) {
1715 int antipadding = 0;
1716 if (ainfo->bytes) {
1717 g_assert (i == 0);
1718 antipadding = sizeof (gpointer) - ainfo->bytes;
1720 dreg = mono_alloc_ireg (cfg);
1721 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1722 if (antipadding)
1723 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1724 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1725 soffset += sizeof (gpointer);
1727 if (ovf_size != 0)
1728 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1729 } else if (ainfo->regtype == RegTypeFP) {
1730 int tmpr = mono_alloc_freg (cfg);
1731 if (ainfo->size == 4)
1732 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1733 else
1734 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1735 dreg = mono_alloc_freg (cfg);
1736 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1737 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1738 } else {
1739 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1740 MonoInst *load;
1741 guint32 size;
1743 /* FIXME: alignment? */
1744 if (call->signature->pinvoke) {
1745 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1746 vtcopy->backend.is_pinvoke = 1;
1747 } else {
1748 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1750 if (size > 0)
1751 g_assert (ovf_size > 0);
1753 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1754 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1756 if (ainfo->offset)
1757 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1758 else
1759 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1763 void
1764 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1766 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1767 mono_method_signature (method)->ret);
1769 if (!ret->byref) {
1770 #ifndef __mono_ppc64__
1771 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1772 MonoInst *ins;
1774 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1775 ins->sreg1 = val->dreg + 1;
1776 ins->sreg2 = val->dreg + 2;
1777 MONO_ADD_INS (cfg->cbb, ins);
1778 return;
1780 #endif
1781 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1782 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1783 return;
1786 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1789 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1790 gboolean
1791 mono_arch_is_inst_imm (gint64 imm)
1793 return TRUE;
1796 #endif /* DISABLE_JIT */
1799 * Allow tracing to work with this interface (with an optional argument)
1802 void*
1803 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1805 guchar *code = p;
1807 ppc_load_ptr (code, ppc_r3, cfg->method);
1808 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1809 ppc_load_func (code, ppc_r0, func);
1810 ppc_mtlr (code, ppc_r0);
1811 ppc_blrl (code);
1812 return code;
1815 enum {
1816 SAVE_NONE,
1817 SAVE_STRUCT,
1818 SAVE_ONE,
1819 SAVE_TWO,
1820 SAVE_FP
1823 void*
1824 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1826 guchar *code = p;
1827 int save_mode = SAVE_NONE;
1828 int offset;
1829 MonoMethod *method = cfg->method;
1830 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1831 mono_method_signature (method)->ret)->type;
1832 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1833 save_offset += 15;
1834 save_offset &= ~15;
1836 offset = code - cfg->native_code;
1837 /* we need about 16 instructions */
1838 if (offset > (cfg->code_size - 16 * 4)) {
1839 cfg->code_size *= 2;
1840 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1841 code = cfg->native_code + offset;
1844 switch (rtype) {
1845 case MONO_TYPE_VOID:
1846 /* special case string .ctor icall */
1847 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1848 save_mode = SAVE_ONE;
1849 else
1850 save_mode = SAVE_NONE;
1851 break;
1852 #ifndef __mono_ppc64__
1853 case MONO_TYPE_I8:
1854 case MONO_TYPE_U8:
1855 save_mode = SAVE_TWO;
1856 break;
1857 #endif
1858 case MONO_TYPE_R4:
1859 case MONO_TYPE_R8:
1860 save_mode = SAVE_FP;
1861 break;
1862 case MONO_TYPE_VALUETYPE:
1863 save_mode = SAVE_STRUCT;
1864 break;
1865 default:
1866 save_mode = SAVE_ONE;
1867 break;
1870 switch (save_mode) {
1871 case SAVE_TWO:
1872 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1873 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1874 if (enable_arguments) {
1875 ppc_mr (code, ppc_r5, ppc_r4);
1876 ppc_mr (code, ppc_r4, ppc_r3);
1878 break;
1879 case SAVE_ONE:
1880 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1881 if (enable_arguments) {
1882 ppc_mr (code, ppc_r4, ppc_r3);
1884 break;
1885 case SAVE_FP:
1886 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1887 if (enable_arguments) {
1888 /* FIXME: what reg? */
1889 ppc_fmr (code, ppc_f3, ppc_f1);
1890 /* FIXME: use 8 byte load on PPC64 */
1891 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1892 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1894 break;
1895 case SAVE_STRUCT:
1896 if (enable_arguments) {
1897 /* FIXME: get the actual address */
1898 ppc_mr (code, ppc_r4, ppc_r3);
1900 break;
1901 case SAVE_NONE:
1902 default:
1903 break;
1906 ppc_load_ptr (code, ppc_r3, cfg->method);
1907 ppc_load_func (code, ppc_r0, func);
1908 ppc_mtlr (code, ppc_r0);
1909 ppc_blrl (code);
1911 switch (save_mode) {
1912 case SAVE_TWO:
1913 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1914 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1915 break;
1916 case SAVE_ONE:
1917 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1918 break;
1919 case SAVE_FP:
1920 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1921 break;
1922 case SAVE_NONE:
1923 default:
1924 break;
1927 return code;
1930 * Conditional branches have a small offset, so if it is likely overflowed,
1931 * we do a branch to the end of the method (uncond branches have much larger
1932 * offsets) where we perform the conditional and jump back unconditionally.
1933 * It's slightly slower, since we add two uncond branches, but it's very simple
1934 * with the current patch implementation and such large methods are likely not
1935 * going to be perf critical anyway.
1937 typedef struct {
1938 union {
1939 MonoBasicBlock *bb;
1940 const char *exception;
1941 } data;
1942 guint32 ip_offset;
1943 guint16 b0_cond;
1944 guint16 b1_cond;
1945 } MonoOvfJump;
1947 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1948 if (0 && ins->inst_true_bb->native_offset) { \
1949 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1950 } else { \
1951 int br_disp = ins->inst_true_bb->max_offset - offset; \
1952 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1953 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1954 ovfj->data.bb = ins->inst_true_bb; \
1955 ovfj->ip_offset = 0; \
1956 ovfj->b0_cond = (b0); \
1957 ovfj->b1_cond = (b1); \
1958 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1959 ppc_b (code, 0); \
1960 } else { \
1961 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1962 ppc_bc (code, (b0), (b1), 0); \
1966 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1968 /* emit an exception if condition is fail
1970 * We assign the extra code used to throw the implicit exceptions
1971 * to cfg->bb_exit as far as the big branch handling is concerned
1973 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1974 do { \
1975 int br_disp = cfg->bb_exit->max_offset - offset; \
1976 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1977 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1978 ovfj->data.exception = (exc_name); \
1979 ovfj->ip_offset = code - cfg->native_code; \
1980 ovfj->b0_cond = (b0); \
1981 ovfj->b1_cond = (b1); \
1982 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1983 ppc_bl (code, 0); \
1984 cfg->bb_exit->max_offset += 24; \
1985 } else { \
1986 mono_add_patch_info (cfg, code - cfg->native_code, \
1987 MONO_PATCH_INFO_EXC, exc_name); \
1988 ppc_bcl (code, (b0), (b1), 0); \
1990 } while (0);
1992 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1994 void
1995 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1999 static int
2000 normalize_opcode (int opcode)
2002 switch (opcode) {
2003 #ifndef __mono_ilp32__
2004 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2005 return OP_LOAD_MEMBASE;
2006 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2007 return OP_LOAD_MEMINDEX;
2008 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2009 return OP_STORE_MEMBASE_REG;
2010 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2011 return OP_STORE_MEMBASE_IMM;
2012 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2013 return OP_STORE_MEMINDEX;
2014 #endif
2015 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2016 return OP_SHR_IMM;
2017 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2018 return OP_SHR_UN_IMM;
2019 default:
2020 return opcode;
2024 void
2025 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2027 MonoInst *ins, *n, *last_ins = NULL;
2029 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2030 switch (normalize_opcode (ins->opcode)) {
2031 case OP_MUL_IMM:
2032 /* remove unnecessary multiplication with 1 */
2033 if (ins->inst_imm == 1) {
2034 if (ins->dreg != ins->sreg1) {
2035 ins->opcode = OP_MOVE;
2036 } else {
2037 MONO_DELETE_INS (bb, ins);
2038 continue;
2040 } else {
2041 int power2 = mono_is_power_of_two (ins->inst_imm);
2042 if (power2 > 0) {
2043 ins->opcode = OP_SHL_IMM;
2044 ins->inst_imm = power2;
2047 break;
2048 case OP_LOAD_MEMBASE:
2050 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2051 * OP_LOAD_MEMBASE offset(basereg), reg
2053 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2054 ins->inst_basereg == last_ins->inst_destbasereg &&
2055 ins->inst_offset == last_ins->inst_offset) {
2056 if (ins->dreg == last_ins->sreg1) {
2057 MONO_DELETE_INS (bb, ins);
2058 continue;
2059 } else {
2060 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2061 ins->opcode = OP_MOVE;
2062 ins->sreg1 = last_ins->sreg1;
2066 * Note: reg1 must be different from the basereg in the second load
2067 * OP_LOAD_MEMBASE offset(basereg), reg1
2068 * OP_LOAD_MEMBASE offset(basereg), reg2
2069 * -->
2070 * OP_LOAD_MEMBASE offset(basereg), reg1
2071 * OP_MOVE reg1, reg2
2073 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2074 ins->inst_basereg != last_ins->dreg &&
2075 ins->inst_basereg == last_ins->inst_basereg &&
2076 ins->inst_offset == last_ins->inst_offset) {
2078 if (ins->dreg == last_ins->dreg) {
2079 MONO_DELETE_INS (bb, ins);
2080 continue;
2081 } else {
2082 ins->opcode = OP_MOVE;
2083 ins->sreg1 = last_ins->dreg;
2086 //g_assert_not_reached ();
2088 #if 0
2090 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2091 * OP_LOAD_MEMBASE offset(basereg), reg
2092 * -->
2093 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2094 * OP_ICONST reg, imm
2096 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2097 ins->inst_basereg == last_ins->inst_destbasereg &&
2098 ins->inst_offset == last_ins->inst_offset) {
2099 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2100 ins->opcode = OP_ICONST;
2101 ins->inst_c0 = last_ins->inst_imm;
2102 g_assert_not_reached (); // check this rule
2103 #endif
2105 break;
2106 case OP_LOADU1_MEMBASE:
2107 case OP_LOADI1_MEMBASE:
2108 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2109 ins->inst_basereg == last_ins->inst_destbasereg &&
2110 ins->inst_offset == last_ins->inst_offset) {
2111 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2112 ins->sreg1 = last_ins->sreg1;
2114 break;
2115 case OP_LOADU2_MEMBASE:
2116 case OP_LOADI2_MEMBASE:
2117 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2118 ins->inst_basereg == last_ins->inst_destbasereg &&
2119 ins->inst_offset == last_ins->inst_offset) {
2120 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2121 ins->sreg1 = last_ins->sreg1;
2123 break;
2124 #ifdef __mono_ppc64__
2125 case OP_LOADU4_MEMBASE:
2126 case OP_LOADI4_MEMBASE:
2127 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2128 ins->inst_basereg == last_ins->inst_destbasereg &&
2129 ins->inst_offset == last_ins->inst_offset) {
2130 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2131 ins->sreg1 = last_ins->sreg1;
2133 break;
2134 #endif
2135 case OP_MOVE:
2136 ins->opcode = OP_MOVE;
2138 * OP_MOVE reg, reg
2140 if (ins->dreg == ins->sreg1) {
2141 MONO_DELETE_INS (bb, ins);
2142 continue;
2145 * OP_MOVE sreg, dreg
2146 * OP_MOVE dreg, sreg
2148 if (last_ins && last_ins->opcode == OP_MOVE &&
2149 ins->sreg1 == last_ins->dreg &&
2150 ins->dreg == last_ins->sreg1) {
2151 MONO_DELETE_INS (bb, ins);
2152 continue;
2154 break;
2156 last_ins = ins;
2157 ins = ins->next;
2159 bb->last_ins = last_ins;
2162 void
2163 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2165 switch (ins->opcode) {
2166 case OP_ICONV_TO_R_UN: {
2167 #if G_BYTE_ORDER == G_BIG_ENDIAN
2168 static const guint64 adjust_val = 0x4330000000000000ULL;
2169 #else
2170 static const guint64 adjust_val = 0x0000000000003043ULL;
2171 #endif
2172 int msw_reg = mono_alloc_ireg (cfg);
2173 int adj_reg = mono_alloc_freg (cfg);
2174 int tmp_reg = mono_alloc_freg (cfg);
2175 int basereg = ppc_sp;
2176 int offset = -8;
2177 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2178 if (!ppc_is_imm16 (offset + 4)) {
2179 basereg = mono_alloc_ireg (cfg);
2180 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2182 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2183 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2184 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2185 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2186 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2187 ins->opcode = OP_NOP;
2188 break;
2190 #ifndef __mono_ppc64__
2191 case OP_ICONV_TO_R4:
2192 case OP_ICONV_TO_R8: {
2193 /* If we have a PPC_FEATURE_64 machine we can avoid
2194 this and use the fcfid instruction. Otherwise
2195 on an old 32-bit chip and we have to do this the
2196 hard way. */
2197 if (!(cpu_hw_caps & PPC_ISA_64)) {
2198 /* FIXME: change precision for CEE_CONV_R4 */
2199 static const guint64 adjust_val = 0x4330000080000000ULL;
2200 int msw_reg = mono_alloc_ireg (cfg);
2201 int xored = mono_alloc_ireg (cfg);
2202 int adj_reg = mono_alloc_freg (cfg);
2203 int tmp_reg = mono_alloc_freg (cfg);
2204 int basereg = ppc_sp;
2205 int offset = -8;
2206 if (!ppc_is_imm16 (offset + 4)) {
2207 basereg = mono_alloc_ireg (cfg);
2208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2210 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2211 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2212 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2213 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2214 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2215 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2216 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2217 if (ins->opcode == OP_ICONV_TO_R4)
2218 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2219 ins->opcode = OP_NOP;
2221 break;
2223 #endif
2224 case OP_CKFINITE: {
2225 int msw_reg = mono_alloc_ireg (cfg);
2226 int basereg = ppc_sp;
2227 int offset = -8;
2228 if (!ppc_is_imm16 (offset + 4)) {
2229 basereg = mono_alloc_ireg (cfg);
2230 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2232 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2233 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2234 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2235 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2236 ins->opcode = OP_NOP;
2237 break;
2239 #ifdef __mono_ppc64__
2240 case OP_IADD_OVF:
2241 case OP_IADD_OVF_UN:
2242 case OP_ISUB_OVF: {
2243 int shifted1_reg = mono_alloc_ireg (cfg);
2244 int shifted2_reg = mono_alloc_ireg (cfg);
2245 int result_shifted_reg = mono_alloc_ireg (cfg);
2247 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2248 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2249 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2250 if (ins->opcode == OP_IADD_OVF_UN)
2251 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2252 else
2253 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2254 ins->opcode = OP_NOP;
2256 #endif
2260 void
2261 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2263 switch (ins->opcode) {
2264 case OP_LADD_OVF:
2265 /* ADC sets the condition code */
2266 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2267 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2268 NULLIFY_INS (ins);
2269 break;
2270 case OP_LADD_OVF_UN:
2271 /* ADC sets the condition code */
2272 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2273 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2274 NULLIFY_INS (ins);
2275 break;
2276 case OP_LSUB_OVF:
2277 /* SBB sets the condition code */
2278 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2279 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2280 NULLIFY_INS (ins);
2281 break;
2282 case OP_LSUB_OVF_UN:
2283 /* SBB sets the condition code */
2284 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2285 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2286 NULLIFY_INS (ins);
2287 break;
2288 case OP_LNEG:
2289 /* From gcc generated code */
2290 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2291 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2292 NULLIFY_INS (ins);
2293 break;
2294 default:
2295 break;
2300 * the branch_b0_table should maintain the order of these
2301 * opcodes.
2302 case CEE_BEQ:
2303 case CEE_BGE:
2304 case CEE_BGT:
2305 case CEE_BLE:
2306 case CEE_BLT:
2307 case CEE_BNE_UN:
2308 case CEE_BGE_UN:
2309 case CEE_BGT_UN:
2310 case CEE_BLE_UN:
2311 case CEE_BLT_UN:
2313 static const guchar
2314 branch_b0_table [] = {
2315 PPC_BR_TRUE,
2316 PPC_BR_FALSE,
2317 PPC_BR_TRUE,
2318 PPC_BR_FALSE,
2319 PPC_BR_TRUE,
2321 PPC_BR_FALSE,
2322 PPC_BR_FALSE,
2323 PPC_BR_TRUE,
2324 PPC_BR_FALSE,
2325 PPC_BR_TRUE
2328 static const guchar
2329 branch_b1_table [] = {
2330 PPC_BR_EQ,
2331 PPC_BR_LT,
2332 PPC_BR_GT,
2333 PPC_BR_GT,
2334 PPC_BR_LT,
2336 PPC_BR_EQ,
2337 PPC_BR_LT,
2338 PPC_BR_GT,
2339 PPC_BR_GT,
2340 PPC_BR_LT
2343 #define NEW_INS(cfg,dest,op) do { \
2344 MONO_INST_NEW((cfg), (dest), (op)); \
2345 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2346 } while (0)
2348 static int
2349 map_to_reg_reg_op (int op)
2351 switch (op) {
2352 case OP_ADD_IMM:
2353 return OP_IADD;
2354 case OP_SUB_IMM:
2355 return OP_ISUB;
2356 case OP_AND_IMM:
2357 return OP_IAND;
2358 case OP_COMPARE_IMM:
2359 return OP_COMPARE;
2360 case OP_ICOMPARE_IMM:
2361 return OP_ICOMPARE;
2362 case OP_LCOMPARE_IMM:
2363 return OP_LCOMPARE;
2364 case OP_ADDCC_IMM:
2365 return OP_IADDCC;
2366 case OP_ADC_IMM:
2367 return OP_IADC;
2368 case OP_SUBCC_IMM:
2369 return OP_ISUBCC;
2370 case OP_SBB_IMM:
2371 return OP_ISBB;
2372 case OP_OR_IMM:
2373 return OP_IOR;
2374 case OP_XOR_IMM:
2375 return OP_IXOR;
2376 case OP_MUL_IMM:
2377 return OP_IMUL;
2378 case OP_LOAD_MEMBASE:
2379 return OP_LOAD_MEMINDEX;
2380 case OP_LOADI4_MEMBASE:
2381 return OP_LOADI4_MEMINDEX;
2382 case OP_LOADU4_MEMBASE:
2383 return OP_LOADU4_MEMINDEX;
2384 case OP_LOADI8_MEMBASE:
2385 return OP_LOADI8_MEMINDEX;
2386 case OP_LOADU1_MEMBASE:
2387 return OP_LOADU1_MEMINDEX;
2388 case OP_LOADI2_MEMBASE:
2389 return OP_LOADI2_MEMINDEX;
2390 case OP_LOADU2_MEMBASE:
2391 return OP_LOADU2_MEMINDEX;
2392 case OP_LOADI1_MEMBASE:
2393 return OP_LOADI1_MEMINDEX;
2394 case OP_LOADR4_MEMBASE:
2395 return OP_LOADR4_MEMINDEX;
2396 case OP_LOADR8_MEMBASE:
2397 return OP_LOADR8_MEMINDEX;
2398 case OP_STOREI1_MEMBASE_REG:
2399 return OP_STOREI1_MEMINDEX;
2400 case OP_STOREI2_MEMBASE_REG:
2401 return OP_STOREI2_MEMINDEX;
2402 case OP_STOREI4_MEMBASE_REG:
2403 return OP_STOREI4_MEMINDEX;
2404 case OP_STOREI8_MEMBASE_REG:
2405 return OP_STOREI8_MEMINDEX;
2406 case OP_STORE_MEMBASE_REG:
2407 return OP_STORE_MEMINDEX;
2408 case OP_STORER4_MEMBASE_REG:
2409 return OP_STORER4_MEMINDEX;
2410 case OP_STORER8_MEMBASE_REG:
2411 return OP_STORER8_MEMINDEX;
2412 case OP_STORE_MEMBASE_IMM:
2413 return OP_STORE_MEMBASE_REG;
2414 case OP_STOREI1_MEMBASE_IMM:
2415 return OP_STOREI1_MEMBASE_REG;
2416 case OP_STOREI2_MEMBASE_IMM:
2417 return OP_STOREI2_MEMBASE_REG;
2418 case OP_STOREI4_MEMBASE_IMM:
2419 return OP_STOREI4_MEMBASE_REG;
2420 case OP_STOREI8_MEMBASE_IMM:
2421 return OP_STOREI8_MEMBASE_REG;
2423 return mono_op_imm_to_op (op);
2426 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2428 #define compare_opcode_is_unsigned(opcode) \
2429 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2430 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2431 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2432 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2433 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2434 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2435 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2436 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2439 * Remove from the instruction list the instructions that can't be
2440 * represented with very simple instructions with no register
2441 * requirements.
2443 void
2444 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2446 MonoInst *ins, *next, *temp, *last_ins = NULL;
2447 int imm;
2449 MONO_BB_FOR_EACH_INS (bb, ins) {
2450 loop_start:
2451 switch (ins->opcode) {
2452 case OP_IDIV_UN_IMM:
2453 case OP_IDIV_IMM:
2454 case OP_IREM_IMM:
2455 case OP_IREM_UN_IMM:
2456 NEW_INS (cfg, temp, OP_ICONST);
2457 temp->inst_c0 = ins->inst_imm;
2458 temp->dreg = mono_alloc_ireg (cfg);
2459 ins->sreg2 = temp->dreg;
2460 if (ins->opcode == OP_IDIV_IMM)
2461 ins->opcode = OP_IDIV;
2462 else if (ins->opcode == OP_IREM_IMM)
2463 ins->opcode = OP_IREM;
2464 else if (ins->opcode == OP_IDIV_UN_IMM)
2465 ins->opcode = OP_IDIV_UN;
2466 else if (ins->opcode == OP_IREM_UN_IMM)
2467 ins->opcode = OP_IREM_UN;
2468 last_ins = temp;
2469 /* handle rem separately */
2470 goto loop_start;
2471 case OP_IREM:
2472 case OP_IREM_UN:
2473 CASE_PPC64 (OP_LREM)
2474 CASE_PPC64 (OP_LREM_UN) {
2475 MonoInst *mul;
2476 /* we change a rem dest, src1, src2 to
2477 * div temp1, src1, src2
2478 * mul temp2, temp1, src2
2479 * sub dest, src1, temp2
2481 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2482 NEW_INS (cfg, mul, OP_IMUL);
2483 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2484 ins->opcode = OP_ISUB;
2485 } else {
2486 NEW_INS (cfg, mul, OP_LMUL);
2487 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2488 ins->opcode = OP_LSUB;
2490 temp->sreg1 = ins->sreg1;
2491 temp->sreg2 = ins->sreg2;
2492 temp->dreg = mono_alloc_ireg (cfg);
2493 mul->sreg1 = temp->dreg;
2494 mul->sreg2 = ins->sreg2;
2495 mul->dreg = mono_alloc_ireg (cfg);
2496 ins->sreg2 = mul->dreg;
2497 break;
2499 case OP_IADD_IMM:
2500 CASE_PPC64 (OP_LADD_IMM)
2501 case OP_ADD_IMM:
2502 case OP_ADDCC_IMM:
2503 if (!ppc_is_imm16 (ins->inst_imm)) {
2504 NEW_INS (cfg, temp, OP_ICONST);
2505 temp->inst_c0 = ins->inst_imm;
2506 temp->dreg = mono_alloc_ireg (cfg);
2507 ins->sreg2 = temp->dreg;
2508 ins->opcode = map_to_reg_reg_op (ins->opcode);
2510 break;
2511 case OP_ISUB_IMM:
2512 CASE_PPC64 (OP_LSUB_IMM)
2513 case OP_SUB_IMM:
2514 if (!ppc_is_imm16 (-ins->inst_imm)) {
2515 NEW_INS (cfg, temp, OP_ICONST);
2516 temp->inst_c0 = ins->inst_imm;
2517 temp->dreg = mono_alloc_ireg (cfg);
2518 ins->sreg2 = temp->dreg;
2519 ins->opcode = map_to_reg_reg_op (ins->opcode);
2521 break;
2522 case OP_IAND_IMM:
2523 case OP_IOR_IMM:
2524 case OP_IXOR_IMM:
2525 case OP_LAND_IMM:
2526 case OP_LOR_IMM:
2527 case OP_LXOR_IMM:
2528 case OP_AND_IMM:
2529 case OP_OR_IMM:
2530 case OP_XOR_IMM: {
2531 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2532 #ifdef __mono_ppc64__
2533 if (ins->inst_imm & 0xffffffff00000000ULL)
2534 is_imm = TRUE;
2535 #endif
2536 if (is_imm) {
2537 NEW_INS (cfg, temp, OP_ICONST);
2538 temp->inst_c0 = ins->inst_imm;
2539 temp->dreg = mono_alloc_ireg (cfg);
2540 ins->sreg2 = temp->dreg;
2541 ins->opcode = map_to_reg_reg_op (ins->opcode);
2543 break;
2545 case OP_ISBB_IMM:
2546 case OP_IADC_IMM:
2547 case OP_SBB_IMM:
2548 case OP_SUBCC_IMM:
2549 case OP_ADC_IMM:
2550 NEW_INS (cfg, temp, OP_ICONST);
2551 temp->inst_c0 = ins->inst_imm;
2552 temp->dreg = mono_alloc_ireg (cfg);
2553 ins->sreg2 = temp->dreg;
2554 ins->opcode = map_to_reg_reg_op (ins->opcode);
2555 break;
2556 case OP_COMPARE_IMM:
2557 case OP_ICOMPARE_IMM:
2558 CASE_PPC64 (OP_LCOMPARE_IMM)
2559 next = ins->next;
2560 /* Branch opts can eliminate the branch */
2561 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2562 ins->opcode = OP_NOP;
2563 break;
2565 g_assert(next);
2566 if (compare_opcode_is_unsigned (next->opcode)) {
2567 if (!ppc_is_uimm16 (ins->inst_imm)) {
2568 NEW_INS (cfg, temp, OP_ICONST);
2569 temp->inst_c0 = ins->inst_imm;
2570 temp->dreg = mono_alloc_ireg (cfg);
2571 ins->sreg2 = temp->dreg;
2572 ins->opcode = map_to_reg_reg_op (ins->opcode);
2574 } else {
2575 if (!ppc_is_imm16 (ins->inst_imm)) {
2576 NEW_INS (cfg, temp, OP_ICONST);
2577 temp->inst_c0 = ins->inst_imm;
2578 temp->dreg = mono_alloc_ireg (cfg);
2579 ins->sreg2 = temp->dreg;
2580 ins->opcode = map_to_reg_reg_op (ins->opcode);
2583 break;
2584 case OP_IMUL_IMM:
2585 case OP_MUL_IMM:
2586 if (ins->inst_imm == 1) {
2587 ins->opcode = OP_MOVE;
2588 break;
2590 if (ins->inst_imm == 0) {
2591 ins->opcode = OP_ICONST;
2592 ins->inst_c0 = 0;
2593 break;
2595 imm = mono_is_power_of_two (ins->inst_imm);
2596 if (imm > 0) {
2597 ins->opcode = OP_SHL_IMM;
2598 ins->inst_imm = imm;
2599 break;
2601 if (!ppc_is_imm16 (ins->inst_imm)) {
2602 NEW_INS (cfg, temp, OP_ICONST);
2603 temp->inst_c0 = ins->inst_imm;
2604 temp->dreg = mono_alloc_ireg (cfg);
2605 ins->sreg2 = temp->dreg;
2606 ins->opcode = map_to_reg_reg_op (ins->opcode);
2608 break;
2609 case OP_LOCALLOC_IMM:
2610 NEW_INS (cfg, temp, OP_ICONST);
2611 temp->inst_c0 = ins->inst_imm;
2612 temp->dreg = mono_alloc_ireg (cfg);
2613 ins->sreg1 = temp->dreg;
2614 ins->opcode = OP_LOCALLOC;
2615 break;
2616 case OP_LOAD_MEMBASE:
2617 case OP_LOADI4_MEMBASE:
2618 CASE_PPC64 (OP_LOADI8_MEMBASE)
2619 case OP_LOADU4_MEMBASE:
2620 case OP_LOADI2_MEMBASE:
2621 case OP_LOADU2_MEMBASE:
2622 case OP_LOADI1_MEMBASE:
2623 case OP_LOADU1_MEMBASE:
2624 case OP_LOADR4_MEMBASE:
2625 case OP_LOADR8_MEMBASE:
2626 case OP_STORE_MEMBASE_REG:
2627 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2628 case OP_STOREI4_MEMBASE_REG:
2629 case OP_STOREI2_MEMBASE_REG:
2630 case OP_STOREI1_MEMBASE_REG:
2631 case OP_STORER4_MEMBASE_REG:
2632 case OP_STORER8_MEMBASE_REG:
2633 /* we can do two things: load the immed in a register
2634 * and use an indexed load, or see if the immed can be
2635 * represented as an ad_imm + a load with a smaller offset
2636 * that fits. We just do the first for now, optimize later.
2638 if (ppc_is_imm16 (ins->inst_offset))
2639 break;
2640 NEW_INS (cfg, temp, OP_ICONST);
2641 temp->inst_c0 = ins->inst_offset;
2642 temp->dreg = mono_alloc_ireg (cfg);
2643 ins->sreg2 = temp->dreg;
2644 ins->opcode = map_to_reg_reg_op (ins->opcode);
2645 break;
2646 case OP_STORE_MEMBASE_IMM:
2647 case OP_STOREI1_MEMBASE_IMM:
2648 case OP_STOREI2_MEMBASE_IMM:
2649 case OP_STOREI4_MEMBASE_IMM:
2650 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2651 NEW_INS (cfg, temp, OP_ICONST);
2652 temp->inst_c0 = ins->inst_imm;
2653 temp->dreg = mono_alloc_ireg (cfg);
2654 ins->sreg1 = temp->dreg;
2655 ins->opcode = map_to_reg_reg_op (ins->opcode);
2656 last_ins = temp;
2657 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2658 case OP_R8CONST:
2659 case OP_R4CONST:
2660 if (cfg->compile_aot) {
2661 /* Keep these in the aot case */
2662 break;
2664 NEW_INS (cfg, temp, OP_ICONST);
2665 temp->inst_c0 = (gulong)ins->inst_p0;
2666 temp->dreg = mono_alloc_ireg (cfg);
2667 ins->inst_basereg = temp->dreg;
2668 ins->inst_offset = 0;
2669 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2670 last_ins = temp;
2671 /* make it handle the possibly big ins->inst_offset
2672 * later optimize to use lis + load_membase
2674 goto loop_start;
2676 last_ins = ins;
2678 bb->last_ins = last_ins;
2679 bb->max_vreg = cfg->next_vreg;
2682 static guchar*
2683 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2685 long offset = cfg->arch.fp_conv_var_offset;
2686 long sub_offset;
2687 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2688 #ifdef __mono_ppc64__
2689 if (size == 8) {
2690 ppc_fctidz (code, ppc_f0, sreg);
2691 sub_offset = 0;
2692 } else
2693 #endif
2695 ppc_fctiwz (code, ppc_f0, sreg);
2696 sub_offset = 4;
2698 if (ppc_is_imm16 (offset + sub_offset)) {
2699 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2700 if (size == 8)
2701 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2702 else
2703 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2704 } else {
2705 ppc_load (code, dreg, offset);
2706 ppc_add (code, dreg, dreg, cfg->frame_reg);
2707 ppc_stfd (code, ppc_f0, 0, dreg);
2708 if (size == 8)
2709 ppc_ldr (code, dreg, sub_offset, dreg);
2710 else
2711 ppc_lwz (code, dreg, sub_offset, dreg);
2713 if (!is_signed) {
2714 if (size == 1)
2715 ppc_andid (code, dreg, dreg, 0xff);
2716 else if (size == 2)
2717 ppc_andid (code, dreg, dreg, 0xffff);
2718 #ifdef __mono_ppc64__
2719 else if (size == 4)
2720 ppc_clrldi (code, dreg, dreg, 32);
2721 #endif
2722 } else {
2723 if (size == 1)
2724 ppc_extsb (code, dreg, dreg);
2725 else if (size == 2)
2726 ppc_extsh (code, dreg, dreg);
2727 #ifdef __mono_ppc64__
2728 else if (size == 4)
2729 ppc_extsw (code, dreg, dreg);
2730 #endif
2732 return code;
2735 typedef struct {
2736 guchar *code;
2737 const guchar *target;
2738 int absolute;
2739 int found;
2740 } PatchData;
2742 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2744 static int
2745 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2746 #ifdef __mono_ppc64__
2747 g_assert_not_reached ();
2748 #else
2749 PatchData *pdata = (PatchData*)user_data;
2750 guchar *code = data;
2751 guint32 *thunks = data;
2752 guint32 *endthunks = (guint32*)(code + bsize);
2753 guint32 load [2];
2754 guchar *templ;
2755 int count = 0;
2756 int difflow, diffhigh;
2758 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2759 difflow = (char*)pdata->code - (char*)thunks;
2760 diffhigh = (char*)pdata->code - (char*)endthunks;
2761 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2762 return 0;
2764 templ = (guchar*)load;
2765 ppc_load_sequence (templ, ppc_r0, pdata->target);
2767 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2768 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2769 while (thunks < endthunks) {
2770 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2771 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2772 ppc_patch (pdata->code, (guchar*)thunks);
2773 pdata->found = 1;
2775 static int num_thunks = 0;
2776 num_thunks++;
2777 if ((num_thunks % 20) == 0)
2778 g_print ("num_thunks lookup: %d\n", num_thunks);
2780 return 1;
2781 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2782 /* found a free slot instead: emit thunk */
2783 code = (guchar*)thunks;
2784 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2785 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2786 ppc_mtctr (code, ppc_r0);
2787 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2788 mono_arch_flush_icache ((guchar*)thunks, 16);
2790 ppc_patch (pdata->code, (guchar*)thunks);
2791 pdata->found = 1;
2793 static int num_thunks = 0;
2794 num_thunks++;
2795 if ((num_thunks % 20) == 0)
2796 g_print ("num_thunks: %d\n", num_thunks);
2798 return 1;
2800 /* skip 16 bytes, the size of the thunk */
2801 thunks += 4;
2802 count++;
2804 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2806 #endif
2807 return 0;
2810 static void
2811 handle_thunk (int absolute, guchar *code, const guchar *target) {
2812 MonoDomain *domain = mono_domain_get ();
2813 PatchData pdata;
2815 pdata.code = code;
2816 pdata.target = target;
2817 pdata.absolute = absolute;
2818 pdata.found = 0;
2820 mono_domain_lock (domain);
2821 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2823 if (!pdata.found) {
2824 /* this uses the first available slot */
2825 pdata.found = 2;
2826 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2828 mono_domain_unlock (domain);
2830 if (pdata.found != 1)
2831 g_print ("thunk failed for %p from %p\n", target, code);
2832 g_assert (pdata.found == 1);
2835 static void
2836 patch_ins (guint8 *code, guint32 ins)
2838 *(guint32*)code = GUINT32_TO_BE (ins);
2839 mono_arch_flush_icache (code, 4);
2842 void
2843 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2845 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2846 guint32 prim = ins >> 26;
2847 guint32 ovf;
2849 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2850 if (prim == 18) {
2851 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2852 gint diff = target - code;
2853 g_assert (!is_fd);
2854 if (diff >= 0){
2855 if (diff <= 33554431){
2856 ins = (18 << 26) | (diff) | (ins & 1);
2857 patch_ins (code, ins);
2858 return;
2860 } else {
2861 /* diff between 0 and -33554432 */
2862 if (diff >= -33554432){
2863 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2864 patch_ins (code, ins);
2865 return;
2869 if ((glong)target >= 0){
2870 if ((glong)target <= 33554431){
2871 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2872 patch_ins (code, ins);
2873 return;
2875 } else {
2876 if ((glong)target >= -33554432){
2877 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2878 patch_ins (code, ins);
2879 return;
2883 handle_thunk (TRUE, code, target);
2884 return;
2886 g_assert_not_reached ();
2890 if (prim == 16) {
2891 g_assert (!is_fd);
2892 // absolute address
2893 if (ins & 2) {
2894 guint32 li = (gulong)target;
2895 ins = (ins & 0xffff0000) | (ins & 3);
2896 ovf = li & 0xffff0000;
2897 if (ovf != 0 && ovf != 0xffff0000)
2898 g_assert_not_reached ();
2899 li &= 0xffff;
2900 ins |= li;
2901 // FIXME: assert the top bits of li are 0
2902 } else {
2903 gint diff = target - code;
2904 ins = (ins & 0xffff0000) | (ins & 3);
2905 ovf = diff & 0xffff0000;
2906 if (ovf != 0 && ovf != 0xffff0000)
2907 g_assert_not_reached ();
2908 diff &= 0xffff;
2909 ins |= diff;
2911 patch_ins (code, ins);
2912 return;
2915 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2916 #ifdef __mono_ppc64__
2917 guint32 *seq = (guint32*)code;
2918 guint32 *branch_ins;
2920 /* the trampoline code will try to patch the blrl, blr, bcctr */
2921 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2922 branch_ins = seq;
2923 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2924 code -= 32;
2925 else
2926 code -= 24;
2927 } else {
2928 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2929 branch_ins = seq + 8;
2930 else
2931 branch_ins = seq + 6;
2934 seq = (guint32*)code;
2935 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2936 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2938 if (ppc_is_load_op (seq [5])) {
2939 g_assert (ppc_is_load_op (seq [6]));
2941 if (!is_fd) {
2942 guint8 *buf = (guint8*)&seq [5];
2943 ppc_mr (buf, ppc_r0, ppc_r11);
2944 ppc_nop (buf);
2946 } else {
2947 if (is_fd)
2948 target = mono_get_addr_from_ftnptr ((gpointer)target);
2951 /* FIXME: make this thread safe */
2952 /* FIXME: we're assuming we're using r11 here */
2953 ppc_load_ptr_sequence (code, ppc_r11, target);
2954 mono_arch_flush_icache ((guint8*)seq, 28);
2955 #else
2956 guint32 *seq;
2957 /* the trampoline code will try to patch the blrl, blr, bcctr */
2958 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2959 code -= 12;
2961 /* this is the lis/ori/mtlr/blrl sequence */
2962 seq = (guint32*)code;
2963 g_assert ((seq [0] >> 26) == 15);
2964 g_assert ((seq [1] >> 26) == 24);
2965 g_assert ((seq [2] >> 26) == 31);
2966 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2967 /* FIXME: make this thread safe */
2968 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2969 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2970 mono_arch_flush_icache (code - 8, 8);
2971 #endif
2972 } else {
2973 g_assert_not_reached ();
2975 // g_print ("patched with 0x%08x\n", ins);
2978 void
2979 ppc_patch (guchar *code, const guchar *target)
2981 ppc_patch_full (code, target, FALSE);
2984 void
2985 mono_ppc_patch (guchar *code, const guchar *target)
2987 ppc_patch (code, target);
2990 static guint8*
2991 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2993 switch (ins->opcode) {
2994 case OP_FCALL:
2995 case OP_FCALL_REG:
2996 case OP_FCALL_MEMBASE:
2997 if (ins->dreg != ppc_f1)
2998 ppc_fmr (code, ins->dreg, ppc_f1);
2999 break;
3002 return code;
3005 static int
3006 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3008 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3011 static guint8*
3012 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3014 long size = cfg->param_area;
3016 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3017 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3019 if (!size)
3020 return code;
3022 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3023 if (ppc_is_imm16 (-size)) {
3024 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3025 } else {
3026 ppc_load (code, ppc_r11, -size);
3027 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3030 return code;
3033 static guint8*
3034 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3036 long size = cfg->param_area;
3038 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3039 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3041 if (!size)
3042 return code;
3044 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3045 if (ppc_is_imm16 (size)) {
3046 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3047 } else {
3048 ppc_load (code, ppc_r11, size);
3049 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3052 return code;
3055 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3057 #ifndef DISABLE_JIT
3058 void
3059 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3061 MonoInst *ins, *next;
3062 MonoCallInst *call;
3063 guint offset;
3064 guint8 *code = cfg->native_code + cfg->code_len;
3065 MonoInst *last_ins = NULL;
3066 guint last_offset = 0;
3067 int max_len, cpos;
3068 int L;
3070 /* we don't align basic blocks of loops on ppc */
3072 if (cfg->verbose_level > 2)
3073 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3075 cpos = bb->max_offset;
3077 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3078 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3079 //g_assert (!mono_compile_aot);
3080 //cpos += 6;
3081 //if (bb->cil_code)
3082 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3083 /* this is not thread save, but good enough */
3084 /* fixme: howto handle overflows? */
3085 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3088 MONO_BB_FOR_EACH_INS (bb, ins) {
3089 offset = code - cfg->native_code;
3091 max_len = ins_native_length (cfg, ins);
3093 if (offset > (cfg->code_size - max_len - 16)) {
3094 cfg->code_size *= 2;
3095 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3096 code = cfg->native_code + offset;
3098 // if (ins->cil_code)
3099 // g_print ("cil code\n");
3100 mono_debug_record_line_number (cfg, ins, offset);
3102 switch (normalize_opcode (ins->opcode)) {
3103 case OP_RELAXED_NOP:
3104 case OP_NOP:
3105 case OP_DUMMY_USE:
3106 case OP_DUMMY_STORE:
3107 case OP_NOT_REACHED:
3108 case OP_NOT_NULL:
3109 break;
3110 case OP_SEQ_POINT: {
3111 int i;
3113 if (cfg->compile_aot)
3114 NOT_IMPLEMENTED;
3117 * Read from the single stepping trigger page. This will cause a
3118 * SIGSEGV when single stepping is enabled.
3119 * We do this _before_ the breakpoint, so single stepping after
3120 * a breakpoint is hit will step to the next IL offset.
3122 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3123 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3124 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3127 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3130 * A placeholder for a possible breakpoint inserted by
3131 * mono_arch_set_breakpoint ().
3133 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3134 ppc_nop (code);
3135 break;
3137 case OP_TLS_GET:
3138 emit_tls_access (code, ins->dreg, ins->inst_offset);
3139 break;
3140 case OP_BIGMUL:
3141 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3142 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3143 ppc_mr (code, ppc_r4, ppc_r0);
3144 break;
3145 case OP_BIGMUL_UN:
3146 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3147 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3148 ppc_mr (code, ppc_r4, ppc_r0);
3149 break;
3150 case OP_MEMORY_BARRIER:
3151 ppc_sync (code);
3152 break;
3153 case OP_STOREI1_MEMBASE_REG:
3154 if (ppc_is_imm16 (ins->inst_offset)) {
3155 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3156 } else {
3157 if (ppc_is_imm32 (ins->inst_offset)) {
3158 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3159 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3160 } else {
3161 ppc_load (code, ppc_r0, ins->inst_offset);
3162 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3165 break;
3166 case OP_STOREI2_MEMBASE_REG:
3167 if (ppc_is_imm16 (ins->inst_offset)) {
3168 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3169 } else {
3170 if (ppc_is_imm32 (ins->inst_offset)) {
3171 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3172 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3173 } else {
3174 ppc_load (code, ppc_r0, ins->inst_offset);
3175 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3178 break;
3179 case OP_STORE_MEMBASE_REG:
3180 if (ppc_is_imm16 (ins->inst_offset)) {
3181 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3182 } else {
3183 if (ppc_is_imm32 (ins->inst_offset)) {
3184 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3185 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3186 } else {
3187 ppc_load (code, ppc_r0, ins->inst_offset);
3188 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3191 break;
3192 #ifdef __mono_ilp32__
3193 case OP_STOREI8_MEMBASE_REG:
3194 if (ppc_is_imm16 (ins->inst_offset)) {
3195 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3196 } else {
3197 ppc_load (code, ppc_r0, ins->inst_offset);
3198 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3200 break;
3201 #endif
3202 case OP_STOREI1_MEMINDEX:
3203 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3204 break;
3205 case OP_STOREI2_MEMINDEX:
3206 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3207 break;
3208 case OP_STORE_MEMINDEX:
3209 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3210 break;
3211 case OP_LOADU4_MEM:
3212 g_assert_not_reached ();
3213 break;
3214 case OP_LOAD_MEMBASE:
3215 if (ppc_is_imm16 (ins->inst_offset)) {
3216 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3217 } else {
3218 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3219 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3220 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3221 } else {
3222 ppc_load (code, ppc_r0, ins->inst_offset);
3223 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3226 break;
3227 case OP_LOADI4_MEMBASE:
3228 #ifdef __mono_ppc64__
3229 if (ppc_is_imm16 (ins->inst_offset)) {
3230 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3231 } else {
3232 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3233 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3234 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3235 } else {
3236 ppc_load (code, ppc_r0, ins->inst_offset);
3237 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3240 break;
3241 #endif
3242 case OP_LOADU4_MEMBASE:
3243 if (ppc_is_imm16 (ins->inst_offset)) {
3244 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3245 } else {
3246 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3247 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3248 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3249 } else {
3250 ppc_load (code, ppc_r0, ins->inst_offset);
3251 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3254 break;
3255 case OP_LOADI1_MEMBASE:
3256 case OP_LOADU1_MEMBASE:
3257 if (ppc_is_imm16 (ins->inst_offset)) {
3258 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3259 } else {
3260 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3261 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3262 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3263 } else {
3264 ppc_load (code, ppc_r0, ins->inst_offset);
3265 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3268 if (ins->opcode == OP_LOADI1_MEMBASE)
3269 ppc_extsb (code, ins->dreg, ins->dreg);
3270 break;
3271 case OP_LOADU2_MEMBASE:
3272 if (ppc_is_imm16 (ins->inst_offset)) {
3273 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3274 } else {
3275 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3276 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3277 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3278 } else {
3279 ppc_load (code, ppc_r0, ins->inst_offset);
3280 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3283 break;
3284 case OP_LOADI2_MEMBASE:
3285 if (ppc_is_imm16 (ins->inst_offset)) {
3286 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3287 } else {
3288 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3289 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3290 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3291 } else {
3292 ppc_load (code, ppc_r0, ins->inst_offset);
3293 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3296 break;
3297 #ifdef __mono_ilp32__
3298 case OP_LOADI8_MEMBASE:
3299 if (ppc_is_imm16 (ins->inst_offset)) {
3300 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3301 } else {
3302 ppc_load (code, ppc_r0, ins->inst_offset);
3303 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3305 break;
3306 #endif
3307 case OP_LOAD_MEMINDEX:
3308 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3309 break;
3310 case OP_LOADI4_MEMINDEX:
3311 #ifdef __mono_ppc64__
3312 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3313 break;
3314 #endif
3315 case OP_LOADU4_MEMINDEX:
3316 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3317 break;
3318 case OP_LOADU2_MEMINDEX:
3319 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3320 break;
3321 case OP_LOADI2_MEMINDEX:
3322 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3323 break;
3324 case OP_LOADU1_MEMINDEX:
3325 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3326 break;
3327 case OP_LOADI1_MEMINDEX:
3328 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3329 ppc_extsb (code, ins->dreg, ins->dreg);
3330 break;
3331 case OP_ICONV_TO_I1:
3332 CASE_PPC64 (OP_LCONV_TO_I1)
3333 ppc_extsb (code, ins->dreg, ins->sreg1);
3334 break;
3335 case OP_ICONV_TO_I2:
3336 CASE_PPC64 (OP_LCONV_TO_I2)
3337 ppc_extsh (code, ins->dreg, ins->sreg1);
3338 break;
3339 case OP_ICONV_TO_U1:
3340 CASE_PPC64 (OP_LCONV_TO_U1)
3341 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3342 break;
3343 case OP_ICONV_TO_U2:
3344 CASE_PPC64 (OP_LCONV_TO_U2)
3345 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3346 break;
3347 case OP_COMPARE:
3348 case OP_ICOMPARE:
3349 CASE_PPC64 (OP_LCOMPARE)
3350 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3351 next = ins->next;
3352 if (next && compare_opcode_is_unsigned (next->opcode))
3353 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3354 else
3355 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3356 break;
3357 case OP_COMPARE_IMM:
3358 case OP_ICOMPARE_IMM:
3359 CASE_PPC64 (OP_LCOMPARE_IMM)
3360 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3361 next = ins->next;
3362 if (next && compare_opcode_is_unsigned (next->opcode)) {
3363 if (ppc_is_uimm16 (ins->inst_imm)) {
3364 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3365 } else {
3366 g_assert_not_reached ();
3368 } else {
3369 if (ppc_is_imm16 (ins->inst_imm)) {
3370 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3371 } else {
3372 g_assert_not_reached ();
3375 break;
3376 case OP_BREAK:
3378 * gdb does not like encountering a trap in the debugged code. So
3379 * instead of emitting a trap, we emit a call a C function and place a
3380 * breakpoint there.
3382 //ppc_break (code);
3383 ppc_mr (code, ppc_r3, ins->sreg1);
3384 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3385 (gpointer)"mono_break");
3386 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3387 ppc_load_func (code, ppc_r0, 0);
3388 ppc_mtlr (code, ppc_r0);
3389 ppc_blrl (code);
3390 } else {
3391 ppc_bl (code, 0);
3393 break;
3394 case OP_ADDCC:
3395 case OP_IADDCC:
3396 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3397 break;
3398 case OP_IADD:
3399 CASE_PPC64 (OP_LADD)
3400 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3401 break;
3402 case OP_ADC:
3403 case OP_IADC:
3404 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3405 break;
3406 case OP_ADDCC_IMM:
3407 if (ppc_is_imm16 (ins->inst_imm)) {
3408 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3409 } else {
3410 g_assert_not_reached ();
3412 break;
3413 case OP_ADD_IMM:
3414 case OP_IADD_IMM:
3415 CASE_PPC64 (OP_LADD_IMM)
3416 if (ppc_is_imm16 (ins->inst_imm)) {
3417 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3418 } else {
3419 g_assert_not_reached ();
3421 break;
3422 case OP_IADD_OVF:
3423 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3425 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3426 ppc_mfspr (code, ppc_r0, ppc_xer);
3427 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3428 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3429 break;
3430 case OP_IADD_OVF_UN:
3431 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3433 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3434 ppc_mfspr (code, ppc_r0, ppc_xer);
3435 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3436 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3437 break;
3438 case OP_ISUB_OVF:
3439 CASE_PPC64 (OP_LSUB_OVF)
3440 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3442 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3443 ppc_mfspr (code, ppc_r0, ppc_xer);
3444 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3445 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3446 break;
3447 case OP_ISUB_OVF_UN:
3448 CASE_PPC64 (OP_LSUB_OVF_UN)
3449 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3451 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3452 ppc_mfspr (code, ppc_r0, ppc_xer);
3453 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3454 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3455 break;
3456 case OP_ADD_OVF_CARRY:
3457 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3459 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3460 ppc_mfspr (code, ppc_r0, ppc_xer);
3461 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3462 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3463 break;
3464 case OP_ADD_OVF_UN_CARRY:
3465 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3467 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3468 ppc_mfspr (code, ppc_r0, ppc_xer);
3469 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3470 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3471 break;
3472 case OP_SUB_OVF_CARRY:
3473 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3475 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3476 ppc_mfspr (code, ppc_r0, ppc_xer);
3477 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3478 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3479 break;
3480 case OP_SUB_OVF_UN_CARRY:
3481 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3483 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3484 ppc_mfspr (code, ppc_r0, ppc_xer);
3485 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3486 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3487 break;
3488 case OP_SUBCC:
3489 case OP_ISUBCC:
3490 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3491 break;
3492 case OP_ISUB:
3493 CASE_PPC64 (OP_LSUB)
3494 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3495 break;
3496 case OP_SBB:
3497 case OP_ISBB:
3498 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3499 break;
3500 case OP_SUB_IMM:
3501 case OP_ISUB_IMM:
3502 CASE_PPC64 (OP_LSUB_IMM)
3503 // we add the negated value
3504 if (ppc_is_imm16 (-ins->inst_imm))
3505 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3506 else {
3507 g_assert_not_reached ();
3509 break;
3510 case OP_PPC_SUBFIC:
3511 g_assert (ppc_is_imm16 (ins->inst_imm));
3512 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3513 break;
3514 case OP_PPC_SUBFZE:
3515 ppc_subfze (code, ins->dreg, ins->sreg1);
3516 break;
3517 case OP_IAND:
3518 CASE_PPC64 (OP_LAND)
3519 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3520 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3521 break;
3522 case OP_AND_IMM:
3523 case OP_IAND_IMM:
3524 CASE_PPC64 (OP_LAND_IMM)
3525 if (!(ins->inst_imm & 0xffff0000)) {
3526 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3527 } else if (!(ins->inst_imm & 0xffff)) {
3528 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3529 } else {
3530 g_assert_not_reached ();
3532 break;
3533 case OP_IDIV:
3534 CASE_PPC64 (OP_LDIV) {
3535 guint8 *divisor_is_m1;
3536 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3538 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3539 divisor_is_m1 = code;
3540 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3541 ppc_lis (code, ppc_r0, 0x8000);
3542 #ifdef __mono_ppc64__
3543 if (ins->opcode == OP_LDIV)
3544 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3545 #endif
3546 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3547 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3548 ppc_patch (divisor_is_m1, code);
3549 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3551 if (ins->opcode == OP_IDIV)
3552 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3553 #ifdef __mono_ppc64__
3554 else
3555 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3556 #endif
3557 ppc_mfspr (code, ppc_r0, ppc_xer);
3558 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3559 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3560 break;
3562 case OP_IDIV_UN:
3563 CASE_PPC64 (OP_LDIV_UN)
3564 if (ins->opcode == OP_IDIV_UN)
3565 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3566 #ifdef __mono_ppc64__
3567 else
3568 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3569 #endif
3570 ppc_mfspr (code, ppc_r0, ppc_xer);
3571 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3572 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3573 break;
3574 case OP_DIV_IMM:
3575 case OP_IREM:
3576 case OP_IREM_UN:
3577 case OP_REM_IMM:
3578 g_assert_not_reached ();
3579 case OP_IOR:
3580 CASE_PPC64 (OP_LOR)
3581 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3582 break;
3583 case OP_OR_IMM:
3584 case OP_IOR_IMM:
3585 CASE_PPC64 (OP_LOR_IMM)
3586 if (!(ins->inst_imm & 0xffff0000)) {
3587 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3588 } else if (!(ins->inst_imm & 0xffff)) {
3589 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3590 } else {
3591 g_assert_not_reached ();
3593 break;
3594 case OP_IXOR:
3595 CASE_PPC64 (OP_LXOR)
3596 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3597 break;
3598 case OP_IXOR_IMM:
3599 case OP_XOR_IMM:
3600 CASE_PPC64 (OP_LXOR_IMM)
3601 if (!(ins->inst_imm & 0xffff0000)) {
3602 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3603 } else if (!(ins->inst_imm & 0xffff)) {
3604 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3605 } else {
3606 g_assert_not_reached ();
3608 break;
3609 case OP_ISHL:
3610 CASE_PPC64 (OP_LSHL)
3611 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3612 break;
3613 case OP_SHL_IMM:
3614 case OP_ISHL_IMM:
3615 CASE_PPC64 (OP_LSHL_IMM)
3616 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3617 break;
3618 case OP_ISHR:
3619 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3620 break;
3621 case OP_SHR_IMM:
3622 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3623 break;
3624 case OP_SHR_UN_IMM:
3625 if (MASK_SHIFT_IMM (ins->inst_imm))
3626 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3627 else
3628 ppc_mr (code, ins->dreg, ins->sreg1);
3629 break;
3630 case OP_ISHR_UN:
3631 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3632 break;
3633 case OP_INOT:
3634 CASE_PPC64 (OP_LNOT)
3635 ppc_not (code, ins->dreg, ins->sreg1);
3636 break;
3637 case OP_INEG:
3638 CASE_PPC64 (OP_LNEG)
3639 ppc_neg (code, ins->dreg, ins->sreg1);
3640 break;
3641 case OP_IMUL:
3642 CASE_PPC64 (OP_LMUL)
3643 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3644 break;
3645 case OP_IMUL_IMM:
3646 case OP_MUL_IMM:
3647 CASE_PPC64 (OP_LMUL_IMM)
3648 if (ppc_is_imm16 (ins->inst_imm)) {
3649 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3650 } else {
3651 g_assert_not_reached ();
3653 break;
3654 case OP_IMUL_OVF:
3655 CASE_PPC64 (OP_LMUL_OVF)
3656 /* we annot use mcrxr, since it's not implemented on some processors
3657 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3659 if (ins->opcode == OP_IMUL_OVF)
3660 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3661 #ifdef __mono_ppc64__
3662 else
3663 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3664 #endif
3665 ppc_mfspr (code, ppc_r0, ppc_xer);
3666 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3667 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3668 break;
3669 case OP_IMUL_OVF_UN:
3670 CASE_PPC64 (OP_LMUL_OVF_UN)
3671 /* we first multiply to get the high word and compare to 0
3672 * to set the flags, then the result is discarded and then
3673 * we multiply to get the lower * bits result
3675 if (ins->opcode == OP_IMUL_OVF_UN)
3676 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3677 #ifdef __mono_ppc64__
3678 else
3679 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3680 #endif
3681 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3682 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3683 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3684 break;
3685 case OP_ICONST:
3686 ppc_load (code, ins->dreg, ins->inst_c0);
3687 break;
3688 case OP_I8CONST: {
3689 ppc_load (code, ins->dreg, ins->inst_l);
3690 break;
3692 case OP_LOAD_GOTADDR:
3693 /* The PLT implementation depends on this */
3694 g_assert (ins->dreg == ppc_r30);
3696 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3697 break;
3698 case OP_GOT_ENTRY:
3699 // FIXME: Fix max instruction length
3700 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3701 /* arch_emit_got_access () patches this */
3702 ppc_load32 (code, ppc_r0, 0);
3703 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3704 break;
3705 case OP_AOTCONST:
3706 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3707 ppc_load_sequence (code, ins->dreg, 0);
3708 break;
3709 CASE_PPC32 (OP_ICONV_TO_I4)
3710 CASE_PPC32 (OP_ICONV_TO_U4)
3711 case OP_MOVE:
3712 ppc_mr (code, ins->dreg, ins->sreg1);
3713 break;
3714 case OP_SETLRET: {
3715 int saved = ins->sreg1;
3716 if (ins->sreg1 == ppc_r3) {
3717 ppc_mr (code, ppc_r0, ins->sreg1);
3718 saved = ppc_r0;
3720 if (ins->sreg2 != ppc_r3)
3721 ppc_mr (code, ppc_r3, ins->sreg2);
3722 if (saved != ppc_r4)
3723 ppc_mr (code, ppc_r4, saved);
3724 break;
3726 case OP_FMOVE:
3727 ppc_fmr (code, ins->dreg, ins->sreg1);
3728 break;
3729 case OP_FCONV_TO_R4:
3730 ppc_frsp (code, ins->dreg, ins->sreg1);
3731 break;
3732 case OP_TAILCALL: {
3733 int i, pos;
3734 MonoCallInst *call = (MonoCallInst*)ins;
3737 * Keep in sync with mono_arch_emit_epilog
3739 g_assert (!cfg->method->save_lmf);
3741 * Note: we can use ppc_r11 here because it is dead anyway:
3742 * we're leaving the method.
3744 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3745 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3746 if (ppc_is_imm16 (ret_offset)) {
3747 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3748 } else {
3749 ppc_load (code, ppc_r11, ret_offset);
3750 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3752 ppc_mtlr (code, ppc_r0);
3755 if (ppc_is_imm16 (cfg->stack_usage)) {
3756 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3757 } else {
3758 /* cfg->stack_usage is an int, so we can use
3759 * an addis/addi sequence here even in 64-bit. */
3760 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3761 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3763 if (!cfg->method->save_lmf) {
3764 pos = 0;
3765 for (i = 31; i >= 13; --i) {
3766 if (cfg->used_int_regs & (1 << i)) {
3767 pos += sizeof (gpointer);
3768 ppc_ldptr (code, i, -pos, ppc_r11);
3771 } else {
3772 /* FIXME restore from MonoLMF: though this can't happen yet */
3775 /* Copy arguments on the stack to our argument area */
3776 if (call->stack_usage) {
3777 code = emit_memcpy (code, call->stack_usage, ppc_r11, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3778 /* r11 was clobbered */
3779 g_assert (cfg->frame_reg == ppc_sp);
3780 if (ppc_is_imm16 (cfg->stack_usage)) {
3781 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3782 } else {
3783 /* cfg->stack_usage is an int, so we can use
3784 * an addis/addi sequence here even in 64-bit. */
3785 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3786 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3790 ppc_mr (code, ppc_sp, ppc_r11);
3791 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3792 if (cfg->compile_aot) {
3793 /* arch_emit_got_access () patches this */
3794 ppc_load32 (code, ppc_r0, 0);
3795 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3796 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3797 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3798 #else
3799 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3800 #endif
3801 ppc_mtctr (code, ppc_r0);
3802 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3803 } else {
3804 ppc_b (code, 0);
3806 break;
3808 case OP_CHECK_THIS:
3809 /* ensure ins->sreg1 is not NULL */
3810 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3811 break;
3812 case OP_ARGLIST: {
3813 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3814 if (ppc_is_imm16 (cookie_offset)) {
3815 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3816 } else {
3817 ppc_load (code, ppc_r0, cookie_offset);
3818 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3820 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3821 break;
3823 case OP_FCALL:
3824 case OP_LCALL:
3825 case OP_VCALL:
3826 case OP_VCALL2:
3827 case OP_VOIDCALL:
3828 case OP_CALL:
3829 call = (MonoCallInst*)ins;
3830 if (ins->flags & MONO_INST_HAS_METHOD)
3831 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3832 else
3833 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3834 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3835 ppc_load_func (code, ppc_r0, 0);
3836 ppc_mtlr (code, ppc_r0);
3837 ppc_blrl (code);
3838 } else {
3839 ppc_bl (code, 0);
3841 /* FIXME: this should be handled somewhere else in the new jit */
3842 code = emit_move_return_value (cfg, ins, code);
3843 break;
3844 case OP_FCALL_REG:
3845 case OP_LCALL_REG:
3846 case OP_VCALL_REG:
3847 case OP_VCALL2_REG:
3848 case OP_VOIDCALL_REG:
3849 case OP_CALL_REG:
3850 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3851 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3852 /* FIXME: if we know that this is a method, we
3853 can omit this load */
3854 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3855 ppc_mtlr (code, ppc_r0);
3856 #else
3857 ppc_mtlr (code, ins->sreg1);
3858 #endif
3859 ppc_blrl (code);
3860 /* FIXME: this should be handled somewhere else in the new jit */
3861 code = emit_move_return_value (cfg, ins, code);
3862 break;
3863 case OP_FCALL_MEMBASE:
3864 case OP_LCALL_MEMBASE:
3865 case OP_VCALL_MEMBASE:
3866 case OP_VCALL2_MEMBASE:
3867 case OP_VOIDCALL_MEMBASE:
3868 case OP_CALL_MEMBASE:
3869 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
3870 /* The trampolines clobber this */
3871 ppc_mr (code, ppc_r29, ins->sreg1);
3872 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3873 } else {
3874 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3876 ppc_mtlr (code, ppc_r0);
3877 ppc_blrl (code);
3878 /* FIXME: this should be handled somewhere else in the new jit */
3879 code = emit_move_return_value (cfg, ins, code);
3880 break;
3881 case OP_LOCALLOC: {
3882 guint8 * zero_loop_jump, * zero_loop_start;
3883 /* keep alignment */
3884 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3885 int area_offset = alloca_waste;
3886 area_offset &= ~31;
3887 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3888 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3889 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3890 /* use ctr to store the number of words to 0 if needed */
3891 if (ins->flags & MONO_INST_INIT) {
3892 /* we zero 4 bytes at a time:
3893 * we add 7 instead of 3 so that we set the counter to
3894 * at least 1, otherwise the bdnz instruction will make
3895 * it negative and iterate billions of times.
3897 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3898 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3899 ppc_mtctr (code, ppc_r0);
3901 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3902 ppc_neg (code, ppc_r11, ppc_r11);
3903 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3905 /* FIXME: make this loop work in 8 byte
3906 increments on PPC64 */
3907 if (ins->flags & MONO_INST_INIT) {
3908 /* adjust the dest reg by -4 so we can use stwu */
3909 /* we actually adjust -8 because we let the loop
3910 * run at least once
3912 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3913 ppc_li (code, ppc_r11, 0);
3914 zero_loop_start = code;
3915 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3916 zero_loop_jump = code;
3917 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3918 ppc_patch (zero_loop_jump, zero_loop_start);
3920 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3921 break;
3923 case OP_THROW: {
3924 //ppc_break (code);
3925 ppc_mr (code, ppc_r3, ins->sreg1);
3926 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3927 (gpointer)"mono_arch_throw_exception");
3928 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3929 ppc_load_func (code, ppc_r0, 0);
3930 ppc_mtlr (code, ppc_r0);
3931 ppc_blrl (code);
3932 } else {
3933 ppc_bl (code, 0);
3935 break;
3937 case OP_RETHROW: {
3938 //ppc_break (code);
3939 ppc_mr (code, ppc_r3, ins->sreg1);
3940 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3941 (gpointer)"mono_arch_rethrow_exception");
3942 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3943 ppc_load_func (code, ppc_r0, 0);
3944 ppc_mtlr (code, ppc_r0);
3945 ppc_blrl (code);
3946 } else {
3947 ppc_bl (code, 0);
3949 break;
3951 case OP_START_HANDLER: {
3952 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3953 g_assert (spvar->inst_basereg != ppc_sp);
3954 code = emit_reserve_param_area (cfg, code);
3955 ppc_mflr (code, ppc_r0);
3956 if (ppc_is_imm16 (spvar->inst_offset)) {
3957 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3958 } else {
3959 ppc_load (code, ppc_r11, spvar->inst_offset);
3960 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3962 break;
3964 case OP_ENDFILTER: {
3965 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3966 g_assert (spvar->inst_basereg != ppc_sp);
3967 code = emit_unreserve_param_area (cfg, code);
3968 if (ins->sreg1 != ppc_r3)
3969 ppc_mr (code, ppc_r3, ins->sreg1);
3970 if (ppc_is_imm16 (spvar->inst_offset)) {
3971 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3972 } else {
3973 ppc_load (code, ppc_r11, spvar->inst_offset);
3974 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3976 ppc_mtlr (code, ppc_r0);
3977 ppc_blr (code);
3978 break;
3980 case OP_ENDFINALLY: {
3981 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3982 g_assert (spvar->inst_basereg != ppc_sp);
3983 code = emit_unreserve_param_area (cfg, code);
3984 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3985 ppc_mtlr (code, ppc_r0);
3986 ppc_blr (code);
3987 break;
3989 case OP_CALL_HANDLER:
3990 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3991 ppc_bl (code, 0);
3992 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3993 break;
3994 case OP_LABEL:
3995 ins->inst_c0 = code - cfg->native_code;
3996 break;
3997 case OP_BR:
3998 /*if (ins->inst_target_bb->native_offset) {
3999 ppc_b (code, 0);
4000 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4001 } else*/ {
4002 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4003 ppc_b (code, 0);
4005 break;
4006 case OP_BR_REG:
4007 ppc_mtctr (code, ins->sreg1);
4008 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4009 break;
4010 case OP_CEQ:
4011 case OP_ICEQ:
4012 CASE_PPC64 (OP_LCEQ)
4013 ppc_li (code, ins->dreg, 0);
4014 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4015 ppc_li (code, ins->dreg, 1);
4016 break;
4017 case OP_CLT:
4018 case OP_CLT_UN:
4019 case OP_ICLT:
4020 case OP_ICLT_UN:
4021 CASE_PPC64 (OP_LCLT)
4022 CASE_PPC64 (OP_LCLT_UN)
4023 ppc_li (code, ins->dreg, 1);
4024 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4025 ppc_li (code, ins->dreg, 0);
4026 break;
4027 case OP_CGT:
4028 case OP_CGT_UN:
4029 case OP_ICGT:
4030 case OP_ICGT_UN:
4031 CASE_PPC64 (OP_LCGT)
4032 CASE_PPC64 (OP_LCGT_UN)
4033 ppc_li (code, ins->dreg, 1);
4034 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4035 ppc_li (code, ins->dreg, 0);
4036 break;
4037 case OP_COND_EXC_EQ:
4038 case OP_COND_EXC_NE_UN:
4039 case OP_COND_EXC_LT:
4040 case OP_COND_EXC_LT_UN:
4041 case OP_COND_EXC_GT:
4042 case OP_COND_EXC_GT_UN:
4043 case OP_COND_EXC_GE:
4044 case OP_COND_EXC_GE_UN:
4045 case OP_COND_EXC_LE:
4046 case OP_COND_EXC_LE_UN:
4047 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4048 break;
4049 case OP_COND_EXC_IEQ:
4050 case OP_COND_EXC_INE_UN:
4051 case OP_COND_EXC_ILT:
4052 case OP_COND_EXC_ILT_UN:
4053 case OP_COND_EXC_IGT:
4054 case OP_COND_EXC_IGT_UN:
4055 case OP_COND_EXC_IGE:
4056 case OP_COND_EXC_IGE_UN:
4057 case OP_COND_EXC_ILE:
4058 case OP_COND_EXC_ILE_UN:
4059 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4060 break;
4061 case OP_IBEQ:
4062 case OP_IBNE_UN:
4063 case OP_IBLT:
4064 case OP_IBLT_UN:
4065 case OP_IBGT:
4066 case OP_IBGT_UN:
4067 case OP_IBGE:
4068 case OP_IBGE_UN:
4069 case OP_IBLE:
4070 case OP_IBLE_UN:
4071 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4072 break;
4074 /* floating point opcodes */
4075 case OP_R8CONST:
4076 g_assert (cfg->compile_aot);
4078 /* FIXME: Optimize this */
4079 ppc_bl (code, 1);
4080 ppc_mflr (code, ppc_r11);
4081 ppc_b (code, 3);
4082 *(double*)code = *(double*)ins->inst_p0;
4083 code += 8;
4084 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4085 break;
4086 case OP_R4CONST:
4087 g_assert_not_reached ();
4088 break;
4089 case OP_STORER8_MEMBASE_REG:
4090 if (ppc_is_imm16 (ins->inst_offset)) {
4091 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4092 } else {
4093 if (ppc_is_imm32 (ins->inst_offset)) {
4094 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4095 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4096 } else {
4097 ppc_load (code, ppc_r0, ins->inst_offset);
4098 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4101 break;
4102 case OP_LOADR8_MEMBASE:
4103 if (ppc_is_imm16 (ins->inst_offset)) {
4104 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4105 } else {
4106 if (ppc_is_imm32 (ins->inst_offset)) {
4107 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4108 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4109 } else {
4110 ppc_load (code, ppc_r0, ins->inst_offset);
4111 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4114 break;
4115 case OP_STORER4_MEMBASE_REG:
4116 ppc_frsp (code, ins->sreg1, ins->sreg1);
4117 if (ppc_is_imm16 (ins->inst_offset)) {
4118 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4119 } else {
4120 if (ppc_is_imm32 (ins->inst_offset)) {
4121 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4122 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4123 } else {
4124 ppc_load (code, ppc_r0, ins->inst_offset);
4125 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4128 break;
4129 case OP_LOADR4_MEMBASE:
4130 if (ppc_is_imm16 (ins->inst_offset)) {
4131 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4132 } else {
4133 if (ppc_is_imm32 (ins->inst_offset)) {
4134 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4135 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4136 } else {
4137 ppc_load (code, ppc_r0, ins->inst_offset);
4138 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4141 break;
4142 case OP_LOADR4_MEMINDEX:
4143 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4144 break;
4145 case OP_LOADR8_MEMINDEX:
4146 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4147 break;
4148 case OP_STORER4_MEMINDEX:
4149 ppc_frsp (code, ins->sreg1, ins->sreg1);
4150 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4151 break;
4152 case OP_STORER8_MEMINDEX:
4153 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4154 break;
4155 case CEE_CONV_R_UN:
4156 case CEE_CONV_R4: /* FIXME: change precision */
4157 case CEE_CONV_R8:
4158 g_assert_not_reached ();
4159 case OP_FCONV_TO_I1:
4160 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4161 break;
4162 case OP_FCONV_TO_U1:
4163 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4164 break;
4165 case OP_FCONV_TO_I2:
4166 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4167 break;
4168 case OP_FCONV_TO_U2:
4169 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4170 break;
4171 case OP_FCONV_TO_I4:
4172 case OP_FCONV_TO_I:
4173 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4174 break;
4175 case OP_FCONV_TO_U4:
4176 case OP_FCONV_TO_U:
4177 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4178 break;
4179 case OP_LCONV_TO_R_UN:
4180 g_assert_not_reached ();
4181 /* Implemented as helper calls */
4182 break;
4183 case OP_LCONV_TO_OVF_I4_2:
4184 case OP_LCONV_TO_OVF_I: {
4185 #ifdef __mono_ppc64__
4186 NOT_IMPLEMENTED;
4187 #else
4188 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4189 // Check if its negative
4190 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4191 negative_branch = code;
4192 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4193 // Its positive msword == 0
4194 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4195 msword_positive_branch = code;
4196 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4198 ovf_ex_target = code;
4199 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4200 // Negative
4201 ppc_patch (negative_branch, code);
4202 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4203 msword_negative_branch = code;
4204 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4205 ppc_patch (msword_negative_branch, ovf_ex_target);
4207 ppc_patch (msword_positive_branch, code);
4208 if (ins->dreg != ins->sreg1)
4209 ppc_mr (code, ins->dreg, ins->sreg1);
4210 break;
4211 #endif
4213 case OP_SQRT:
4214 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4215 break;
4216 case OP_FADD:
4217 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4218 break;
4219 case OP_FSUB:
4220 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4221 break;
4222 case OP_FMUL:
4223 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4224 break;
4225 case OP_FDIV:
4226 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4227 break;
4228 case OP_FNEG:
4229 ppc_fneg (code, ins->dreg, ins->sreg1);
4230 break;
4231 case OP_FREM:
4232 /* emulated */
4233 g_assert_not_reached ();
4234 break;
4235 case OP_FCOMPARE:
4236 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4237 break;
4238 case OP_FCEQ:
4239 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4240 ppc_li (code, ins->dreg, 0);
4241 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4242 ppc_li (code, ins->dreg, 1);
4243 break;
4244 case OP_FCLT:
4245 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4246 ppc_li (code, ins->dreg, 1);
4247 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4248 ppc_li (code, ins->dreg, 0);
4249 break;
4250 case OP_FCLT_UN:
4251 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4252 ppc_li (code, ins->dreg, 1);
4253 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4254 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4255 ppc_li (code, ins->dreg, 0);
4256 break;
4257 case OP_FCGT:
4258 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4259 ppc_li (code, ins->dreg, 1);
4260 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4261 ppc_li (code, ins->dreg, 0);
4262 break;
4263 case OP_FCGT_UN:
4264 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4265 ppc_li (code, ins->dreg, 1);
4266 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4267 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4268 ppc_li (code, ins->dreg, 0);
4269 break;
4270 case OP_FBEQ:
4271 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4272 break;
4273 case OP_FBNE_UN:
4274 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4275 break;
4276 case OP_FBLT:
4277 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4278 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4279 break;
4280 case OP_FBLT_UN:
4281 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4282 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4283 break;
4284 case OP_FBGT:
4285 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4286 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4287 break;
4288 case OP_FBGT_UN:
4289 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4290 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4291 break;
4292 case OP_FBGE:
4293 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4294 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4295 break;
4296 case OP_FBGE_UN:
4297 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4298 break;
4299 case OP_FBLE:
4300 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4301 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4302 break;
4303 case OP_FBLE_UN:
4304 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4305 break;
4306 case OP_CKFINITE:
4307 g_assert_not_reached ();
4308 case OP_CHECK_FINITE: {
4309 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4310 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4311 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4312 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4313 break;
4314 case OP_JUMP_TABLE:
4315 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4316 #ifdef __mono_ppc64__
4317 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4318 #else
4319 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4320 #endif
4321 break;
4324 #ifdef __mono_ppc64__
4325 case OP_ICONV_TO_I4:
4326 case OP_SEXT_I4:
4327 ppc_extsw (code, ins->dreg, ins->sreg1);
4328 break;
4329 case OP_ICONV_TO_U4:
4330 case OP_ZEXT_I4:
4331 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4332 break;
4333 case OP_ICONV_TO_R4:
4334 case OP_ICONV_TO_R8:
4335 case OP_LCONV_TO_R4:
4336 case OP_LCONV_TO_R8: {
4337 int tmp;
4338 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4339 ppc_extsw (code, ppc_r0, ins->sreg1);
4340 tmp = ppc_r0;
4341 } else {
4342 tmp = ins->sreg1;
4344 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4345 ppc_mffgpr (code, ins->dreg, tmp);
4346 } else {
4347 ppc_str (code, tmp, -8, ppc_r1);
4348 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4350 ppc_fcfid (code, ins->dreg, ins->dreg);
4351 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4352 ppc_frsp (code, ins->dreg, ins->dreg);
4353 break;
4355 case OP_LSHR:
4356 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4357 break;
4358 case OP_LSHR_UN:
4359 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4360 break;
4361 case OP_COND_EXC_C:
4362 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4364 ppc_mfspr (code, ppc_r0, ppc_xer);
4365 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4366 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4367 break;
4368 case OP_COND_EXC_OV:
4369 ppc_mfspr (code, ppc_r0, ppc_xer);
4370 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4371 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4372 break;
4373 case OP_LBEQ:
4374 case OP_LBNE_UN:
4375 case OP_LBLT:
4376 case OP_LBLT_UN:
4377 case OP_LBGT:
4378 case OP_LBGT_UN:
4379 case OP_LBGE:
4380 case OP_LBGE_UN:
4381 case OP_LBLE:
4382 case OP_LBLE_UN:
4383 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4384 break;
4385 case OP_FCONV_TO_I8:
4386 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4387 break;
4388 case OP_FCONV_TO_U8:
4389 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4390 break;
4391 case OP_STOREI4_MEMBASE_REG:
4392 if (ppc_is_imm16 (ins->inst_offset)) {
4393 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4394 } else {
4395 ppc_load (code, ppc_r0, ins->inst_offset);
4396 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4398 break;
4399 case OP_STOREI4_MEMINDEX:
4400 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4401 break;
4402 case OP_ISHR_IMM:
4403 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4404 break;
4405 case OP_ISHR_UN_IMM:
4406 if (ins->inst_imm & 0x1f)
4407 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4408 else
4409 ppc_mr (code, ins->dreg, ins->sreg1);
4410 break;
4411 case OP_ATOMIC_ADD_NEW_I4:
4412 case OP_ATOMIC_ADD_NEW_I8: {
4413 guint8 *loop = code, *branch;
4414 g_assert (ins->inst_offset == 0);
4415 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4416 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4417 else
4418 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4419 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4420 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4421 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4422 else
4423 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4424 branch = code;
4425 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4426 ppc_patch (branch, loop);
4427 ppc_mr (code, ins->dreg, ppc_r0);
4428 break;
4430 #else
4431 case OP_ICONV_TO_R4:
4432 case OP_ICONV_TO_R8: {
4433 if (cpu_hw_caps & PPC_ISA_64) {
4434 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4435 ppc_stw (code, ppc_r0, -8, ppc_r1);
4436 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4437 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4438 ppc_fcfid (code, ins->dreg, ins->dreg);
4439 if (ins->opcode == OP_ICONV_TO_R4)
4440 ppc_frsp (code, ins->dreg, ins->dreg);
4442 break;
4444 #endif
4445 case OP_ATOMIC_CAS_I4:
4446 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4447 int location = ins->sreg1;
4448 int value = ins->sreg2;
4449 int comparand = ins->sreg3;
4450 guint8 *start, *not_equal, *lost_reservation;
4452 start = code;
4453 if (ins->opcode == OP_ATOMIC_CAS_I4)
4454 ppc_lwarx (code, ppc_r0, 0, location);
4455 #ifdef __mono_ppc64__
4456 else
4457 ppc_ldarx (code, ppc_r0, 0, location);
4458 #endif
4459 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4461 not_equal = code;
4462 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4463 if (ins->opcode == OP_ATOMIC_CAS_I4)
4464 ppc_stwcxd (code, value, 0, location);
4465 #ifdef __mono_ppc64__
4466 else
4467 ppc_stdcxd (code, value, 0, location);
4468 #endif
4470 lost_reservation = code;
4471 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4472 ppc_patch (lost_reservation, start);
4474 ppc_patch (not_equal, code);
4475 ppc_mr (code, ins->dreg, ppc_r0);
4476 break;
4479 default:
4480 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4481 g_assert_not_reached ();
4484 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4485 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4486 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4487 g_assert_not_reached ();
4490 cpos += max_len;
4492 last_ins = ins;
4493 last_offset = offset;
4496 cfg->code_len = code - cfg->native_code;
4498 #endif /* !DISABLE_JIT */
4500 void
4501 mono_arch_register_lowlevel_calls (void)
4503 /* The signature doesn't matter */
4504 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4507 #ifdef __mono_ppc64__
4508 #define patch_load_sequence(ip,val) do {\
4509 guint16 *__load = (guint16*)(ip); \
4510 g_assert (sizeof (val) == sizeof (gsize)); \
4511 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4512 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4513 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4514 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4515 } while (0)
4516 #else
4517 #define patch_load_sequence(ip,val) do {\
4518 guint16 *__lis_ori = (guint16*)(ip); \
4519 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4520 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4521 } while (0)
4522 #endif
4524 #ifndef DISABLE_JIT
4525 void
4526 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4528 MonoJumpInfo *patch_info;
4529 gboolean compile_aot = !run_cctors;
4531 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4532 unsigned char *ip = patch_info->ip.i + code;
4533 unsigned char *target;
4534 gboolean is_fd = FALSE;
4536 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4538 if (compile_aot) {
4539 switch (patch_info->type) {
4540 case MONO_PATCH_INFO_BB:
4541 case MONO_PATCH_INFO_LABEL:
4542 break;
4543 default:
4544 /* No need to patch these */
4545 continue;
4549 switch (patch_info->type) {
4550 case MONO_PATCH_INFO_IP:
4551 patch_load_sequence (ip, ip);
4552 continue;
4553 case MONO_PATCH_INFO_METHOD_REL:
4554 g_assert_not_reached ();
4555 *((gpointer *)(ip)) = code + patch_info->data.offset;
4556 continue;
4557 case MONO_PATCH_INFO_SWITCH: {
4558 gpointer *table = (gpointer *)patch_info->data.table->table;
4559 int i;
4561 patch_load_sequence (ip, table);
4563 for (i = 0; i < patch_info->data.table->table_size; i++) {
4564 table [i] = (glong)patch_info->data.table->table [i] + code;
4566 /* we put into the table the absolute address, no need for ppc_patch in this case */
4567 continue;
4569 case MONO_PATCH_INFO_METHODCONST:
4570 case MONO_PATCH_INFO_CLASS:
4571 case MONO_PATCH_INFO_IMAGE:
4572 case MONO_PATCH_INFO_FIELD:
4573 case MONO_PATCH_INFO_VTABLE:
4574 case MONO_PATCH_INFO_IID:
4575 case MONO_PATCH_INFO_SFLDA:
4576 case MONO_PATCH_INFO_LDSTR:
4577 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4578 case MONO_PATCH_INFO_LDTOKEN:
4579 /* from OP_AOTCONST : lis + ori */
4580 patch_load_sequence (ip, target);
4581 continue;
4582 case MONO_PATCH_INFO_R4:
4583 case MONO_PATCH_INFO_R8:
4584 g_assert_not_reached ();
4585 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4586 continue;
4587 case MONO_PATCH_INFO_EXC_NAME:
4588 g_assert_not_reached ();
4589 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4590 continue;
4591 case MONO_PATCH_INFO_NONE:
4592 case MONO_PATCH_INFO_BB_OVF:
4593 case MONO_PATCH_INFO_EXC_OVF:
4594 /* everything is dealt with at epilog output time */
4595 continue;
4596 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4597 case MONO_PATCH_INFO_INTERNAL_METHOD:
4598 case MONO_PATCH_INFO_ABS:
4599 case MONO_PATCH_INFO_CLASS_INIT:
4600 case MONO_PATCH_INFO_RGCTX_FETCH:
4601 is_fd = TRUE;
4602 break;
4603 #endif
4604 default:
4605 break;
4607 ppc_patch_full (ip, target, is_fd);
4612 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4613 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4614 * the instruction offset immediate for all the registers.
4616 static guint8*
4617 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4619 int i;
4620 if (!save_lmf) {
4621 for (i = 13; i <= 31; i++) {
4622 if (used_int_regs & (1 << i)) {
4623 ppc_str (code, i, pos, base_reg);
4624 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4625 pos += sizeof (mgreg_t);
4628 } else {
4629 /* pos is the start of the MonoLMF structure */
4630 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4631 for (i = 13; i <= 31; i++) {
4632 ppc_str (code, i, offset, base_reg);
4633 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4634 offset += sizeof (mgreg_t);
4636 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4637 for (i = 14; i < 32; i++) {
4638 ppc_stfd (code, i, offset, base_reg);
4639 offset += sizeof (gdouble);
4642 return code;
4646 * Stack frame layout:
4648 * ------------------- sp
4649 * MonoLMF structure or saved registers
4650 * -------------------
4651 * spilled regs
4652 * -------------------
4653 * locals
4654 * -------------------
4655 * optional 8 bytes for tracing
4656 * -------------------
4657 * param area size is cfg->param_area
4658 * -------------------
4659 * linkage area size is PPC_STACK_PARAM_OFFSET
4660 * ------------------- sp
4661 * red zone
4663 guint8 *
4664 mono_arch_emit_prolog (MonoCompile *cfg)
4666 MonoMethod *method = cfg->method;
4667 MonoBasicBlock *bb;
4668 MonoMethodSignature *sig;
4669 MonoInst *inst;
4670 long alloc_size, pos, max_offset, cfa_offset;
4671 int i;
4672 guint8 *code;
4673 CallInfo *cinfo;
4674 int tracing = 0;
4675 int lmf_offset = 0;
4676 int tailcall_struct_index;
4678 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4679 tracing = 1;
4681 sig = mono_method_signature (method);
4682 cfg->code_size = 512 + sig->param_count * 32;
4683 code = cfg->native_code = g_malloc (cfg->code_size);
4685 cfa_offset = 0;
4687 /* We currently emit unwind info for aot, but don't use it */
4688 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4690 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4691 ppc_mflr (code, ppc_r0);
4692 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4693 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4696 alloc_size = cfg->stack_offset;
4697 pos = 0;
4699 if (!method->save_lmf) {
4700 for (i = 31; i >= 13; --i) {
4701 if (cfg->used_int_regs & (1 << i)) {
4702 pos += sizeof (mgreg_t);
4705 } else {
4706 pos += sizeof (MonoLMF);
4707 lmf_offset = pos;
4709 alloc_size += pos;
4710 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4711 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4712 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4713 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4716 cfg->stack_usage = alloc_size;
4717 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4718 if (alloc_size) {
4719 if (ppc_is_imm16 (-alloc_size)) {
4720 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4721 cfa_offset = alloc_size;
4722 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4723 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4724 } else {
4725 if (pos)
4726 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4727 ppc_load (code, ppc_r0, -alloc_size);
4728 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4729 cfa_offset = alloc_size;
4730 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4731 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4734 if (cfg->frame_reg != ppc_sp) {
4735 ppc_mr (code, cfg->frame_reg, ppc_sp);
4736 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4739 /* store runtime generic context */
4740 if (cfg->rgctx_var) {
4741 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4742 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4744 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4747 /* compute max_offset in order to use short forward jumps
4748 * we always do it on ppc because the immediate displacement
4749 * for jumps is too small
4751 max_offset = 0;
4752 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4753 MonoInst *ins;
4754 bb->max_offset = max_offset;
4756 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4757 max_offset += 6;
4759 MONO_BB_FOR_EACH_INS (bb, ins)
4760 max_offset += ins_native_length (cfg, ins);
4763 /* load arguments allocated to register from the stack */
4764 pos = 0;
4766 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4768 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4769 ArgInfo *ainfo = &cinfo->ret;
4771 inst = cfg->vret_addr;
4772 g_assert (inst);
4774 if (ppc_is_imm16 (inst->inst_offset)) {
4775 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4776 } else {
4777 ppc_load (code, ppc_r11, inst->inst_offset);
4778 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4782 tailcall_struct_index = 0;
4783 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4784 ArgInfo *ainfo = cinfo->args + i;
4785 inst = cfg->args [pos];
4787 if (cfg->verbose_level > 2)
4788 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4789 if (inst->opcode == OP_REGVAR) {
4790 if (ainfo->regtype == RegTypeGeneral)
4791 ppc_mr (code, inst->dreg, ainfo->reg);
4792 else if (ainfo->regtype == RegTypeFP)
4793 ppc_fmr (code, inst->dreg, ainfo->reg);
4794 else if (ainfo->regtype == RegTypeBase) {
4795 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4796 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4797 } else
4798 g_assert_not_reached ();
4800 if (cfg->verbose_level > 2)
4801 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4802 } else {
4803 /* the argument should be put on the stack: FIXME handle size != word */
4804 if (ainfo->regtype == RegTypeGeneral) {
4805 switch (ainfo->size) {
4806 case 1:
4807 if (ppc_is_imm16 (inst->inst_offset)) {
4808 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4809 } else {
4810 if (ppc_is_imm32 (inst->inst_offset)) {
4811 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4812 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4813 } else {
4814 ppc_load (code, ppc_r11, inst->inst_offset);
4815 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4818 break;
4819 case 2:
4820 if (ppc_is_imm16 (inst->inst_offset)) {
4821 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4822 } else {
4823 if (ppc_is_imm32 (inst->inst_offset)) {
4824 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4825 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4826 } else {
4827 ppc_load (code, ppc_r11, inst->inst_offset);
4828 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4831 break;
4832 #ifdef __mono_ppc64__
4833 case 4:
4834 if (ppc_is_imm16 (inst->inst_offset)) {
4835 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4836 } else {
4837 if (ppc_is_imm32 (inst->inst_offset)) {
4838 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4839 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4840 } else {
4841 ppc_load (code, ppc_r11, inst->inst_offset);
4842 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4845 break;
4846 case 8:
4847 if (ppc_is_imm16 (inst->inst_offset)) {
4848 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4849 } else {
4850 ppc_load (code, ppc_r11, inst->inst_offset);
4851 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4853 break;
4854 #else
4855 case 8:
4856 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4857 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4858 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4859 } else {
4860 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4861 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4862 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4863 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4865 break;
4866 #endif
4867 default:
4868 if (ppc_is_imm16 (inst->inst_offset)) {
4869 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4870 } else {
4871 if (ppc_is_imm32 (inst->inst_offset)) {
4872 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4873 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4874 } else {
4875 ppc_load (code, ppc_r11, inst->inst_offset);
4876 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4879 break;
4881 } else if (ainfo->regtype == RegTypeBase) {
4882 g_assert (ppc_is_imm16 (ainfo->offset));
4883 /* load the previous stack pointer in r11 */
4884 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4885 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4886 switch (ainfo->size) {
4887 case 1:
4888 if (ppc_is_imm16 (inst->inst_offset)) {
4889 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4890 } else {
4891 if (ppc_is_imm32 (inst->inst_offset)) {
4892 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4893 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4894 } else {
4895 ppc_load (code, ppc_r11, inst->inst_offset);
4896 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4899 break;
4900 case 2:
4901 if (ppc_is_imm16 (inst->inst_offset)) {
4902 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4903 } else {
4904 if (ppc_is_imm32 (inst->inst_offset)) {
4905 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4906 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4907 } else {
4908 ppc_load (code, ppc_r11, inst->inst_offset);
4909 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4912 break;
4913 #ifdef __mono_ppc64__
4914 case 4:
4915 if (ppc_is_imm16 (inst->inst_offset)) {
4916 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4917 } else {
4918 if (ppc_is_imm32 (inst->inst_offset)) {
4919 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4920 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4921 } else {
4922 ppc_load (code, ppc_r11, inst->inst_offset);
4923 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4926 break;
4927 case 8:
4928 if (ppc_is_imm16 (inst->inst_offset)) {
4929 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4930 } else {
4931 ppc_load (code, ppc_r11, inst->inst_offset);
4932 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4934 break;
4935 #else
4936 case 8:
4937 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4938 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4939 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4940 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4941 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4942 } else {
4943 /* use r12 to load the 2nd half of the long before we clobber r11. */
4944 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4945 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4946 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4947 ppc_stw (code, ppc_r0, 0, ppc_r11);
4948 ppc_stw (code, ppc_r12, 4, ppc_r11);
4950 break;
4951 #endif
4952 default:
4953 if (ppc_is_imm16 (inst->inst_offset)) {
4954 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4955 } else {
4956 if (ppc_is_imm32 (inst->inst_offset)) {
4957 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4958 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4959 } else {
4960 ppc_load (code, ppc_r11, inst->inst_offset);
4961 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4964 break;
4966 } else if (ainfo->regtype == RegTypeFP) {
4967 g_assert (ppc_is_imm16 (inst->inst_offset));
4968 if (ainfo->size == 8)
4969 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4970 else if (ainfo->size == 4)
4971 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4972 else
4973 g_assert_not_reached ();
4974 } else if (ainfo->regtype == RegTypeStructByVal) {
4975 int doffset = inst->inst_offset;
4976 int soffset = 0;
4977 int cur_reg;
4978 int size = 0;
4979 g_assert (ppc_is_imm16 (inst->inst_offset));
4980 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
4981 /* FIXME: what if there is no class? */
4982 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4983 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4984 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
4985 #if __APPLE__
4987 * Darwin handles 1 and 2 byte
4988 * structs specially by
4989 * loading h/b into the arg
4990 * register. Only done for
4991 * pinvokes.
4993 if (size == 2)
4994 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4995 else if (size == 1)
4996 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4997 else
4998 #endif
5000 #ifdef __mono_ppc64__
5001 if (ainfo->bytes) {
5002 g_assert (cur_reg == 0);
5003 ppc_sldi (code, ppc_r0, ainfo->reg,
5004 (sizeof (gpointer) - ainfo->bytes) * 8);
5005 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5006 } else
5007 #endif
5009 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5010 inst->inst_basereg);
5013 soffset += sizeof (gpointer);
5014 doffset += sizeof (gpointer);
5016 if (ainfo->vtsize) {
5017 /* FIXME: we need to do the shifting here, too */
5018 if (ainfo->bytes)
5019 NOT_IMPLEMENTED;
5020 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5021 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5022 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5023 code = emit_memcpy (code, size - soffset,
5024 inst->inst_basereg, doffset,
5025 ppc_r11, ainfo->offset + soffset);
5026 } else {
5027 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5028 inst->inst_basereg, doffset,
5029 ppc_r11, ainfo->offset + soffset);
5032 } else if (ainfo->regtype == RegTypeStructByAddr) {
5033 /* if it was originally a RegTypeBase */
5034 if (ainfo->offset) {
5035 /* load the previous stack pointer in r11 */
5036 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5037 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5038 } else {
5039 ppc_mr (code, ppc_r11, ainfo->reg);
5042 if (cfg->tailcall_valuetype_addrs) {
5043 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5045 g_assert (ppc_is_imm16 (addr->inst_offset));
5046 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5048 tailcall_struct_index++;
5051 g_assert (ppc_is_imm16 (inst->inst_offset));
5052 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5053 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5054 } else
5055 g_assert_not_reached ();
5057 pos++;
5060 if (method->save_lmf) {
5061 if (lmf_pthread_key != -1) {
5062 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5063 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5064 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5065 } else {
5066 if (cfg->compile_aot) {
5067 /* Compute the got address which is needed by the PLT entry */
5068 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5070 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5071 (gpointer)"mono_get_lmf_addr");
5072 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5073 ppc_load_func (code, ppc_r0, 0);
5074 ppc_mtlr (code, ppc_r0);
5075 ppc_blrl (code);
5076 } else {
5077 ppc_bl (code, 0);
5080 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5081 /* lmf_offset is the offset from the previous stack pointer,
5082 * alloc_size is the total stack space allocated, so the offset
5083 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5084 * The pointer to the struct is put in ppc_r11 (new_lmf).
5085 * The callee-saved registers are already in the MonoLMF structure
5087 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5088 /* ppc_r3 is the result from mono_get_lmf_addr () */
5089 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5090 /* new_lmf->previous_lmf = *lmf_addr */
5091 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5092 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5093 /* *(lmf_addr) = r11 */
5094 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5095 /* save method info */
5096 if (cfg->compile_aot)
5097 // FIXME:
5098 ppc_load (code, ppc_r0, 0);
5099 else
5100 ppc_load_ptr (code, ppc_r0, method);
5101 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5102 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5103 /* save the current IP */
5104 if (cfg->compile_aot) {
5105 ppc_bl (code, 1);
5106 ppc_mflr (code, ppc_r0);
5107 } else {
5108 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5109 #ifdef __mono_ppc64__
5110 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5111 #else
5112 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5113 #endif
5115 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5118 if (tracing)
5119 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5121 cfg->code_len = code - cfg->native_code;
5122 g_assert (cfg->code_len <= cfg->code_size);
5123 g_free (cinfo);
5125 return code;
5128 void
5129 mono_arch_emit_epilog (MonoCompile *cfg)
5131 MonoMethod *method = cfg->method;
5132 int pos, i;
5133 int max_epilog_size = 16 + 20*4;
5134 guint8 *code;
5136 if (cfg->method->save_lmf)
5137 max_epilog_size += 128;
5139 if (mono_jit_trace_calls != NULL)
5140 max_epilog_size += 50;
5142 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5143 max_epilog_size += 50;
5145 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5146 cfg->code_size *= 2;
5147 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5148 cfg->stat_code_reallocs++;
5152 * Keep in sync with OP_JMP
5154 code = cfg->native_code + cfg->code_len;
5156 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5157 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5159 pos = 0;
5161 if (method->save_lmf) {
5162 int lmf_offset;
5163 pos += sizeof (MonoLMF);
5164 lmf_offset = pos;
5165 /* save the frame reg in r8 */
5166 ppc_mr (code, ppc_r8, cfg->frame_reg);
5167 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5168 /* r5 = previous_lmf */
5169 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5170 /* r6 = lmf_addr */
5171 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5172 /* *(lmf_addr) = previous_lmf */
5173 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5174 /* FIXME: speedup: there is no actual need to restore the registers if
5175 * we didn't actually change them (idea from Zoltan).
5177 /* restore iregs */
5178 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5179 /* restore fregs */
5180 /*for (i = 14; i < 32; i++) {
5181 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5183 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5184 /* use the saved copy of the frame reg in r8 */
5185 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5186 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5187 ppc_mtlr (code, ppc_r0);
5189 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5190 } else {
5191 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5192 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5193 if (ppc_is_imm16 (return_offset)) {
5194 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5195 } else {
5196 ppc_load (code, ppc_r11, return_offset);
5197 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5199 ppc_mtlr (code, ppc_r0);
5201 if (ppc_is_imm16 (cfg->stack_usage)) {
5202 int offset = cfg->stack_usage;
5203 for (i = 13; i <= 31; i++) {
5204 if (cfg->used_int_regs & (1 << i))
5205 offset -= sizeof (mgreg_t);
5207 if (cfg->frame_reg != ppc_sp)
5208 ppc_mr (code, ppc_r11, cfg->frame_reg);
5209 /* note r31 (possibly the frame register) is restored last */
5210 for (i = 13; i <= 31; i++) {
5211 if (cfg->used_int_regs & (1 << i)) {
5212 ppc_ldr (code, i, offset, cfg->frame_reg);
5213 offset += sizeof (mgreg_t);
5216 if (cfg->frame_reg != ppc_sp)
5217 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5218 else
5219 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5220 } else {
5221 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5222 if (cfg->used_int_regs) {
5223 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5224 for (i = 31; i >= 13; --i) {
5225 if (cfg->used_int_regs & (1 << i)) {
5226 pos += sizeof (mgreg_t);
5227 ppc_ldr (code, i, -pos, ppc_r11);
5230 ppc_mr (code, ppc_sp, ppc_r11);
5231 } else {
5232 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5237 ppc_blr (code);
5239 cfg->code_len = code - cfg->native_code;
5241 g_assert (cfg->code_len < cfg->code_size);
5244 #endif /* ifndef DISABLE_JIT */
5246 /* remove once throw_exception_by_name is eliminated */
5247 static int
5248 exception_id_by_name (const char *name)
5250 if (strcmp (name, "IndexOutOfRangeException") == 0)
5251 return MONO_EXC_INDEX_OUT_OF_RANGE;
5252 if (strcmp (name, "OverflowException") == 0)
5253 return MONO_EXC_OVERFLOW;
5254 if (strcmp (name, "ArithmeticException") == 0)
5255 return MONO_EXC_ARITHMETIC;
5256 if (strcmp (name, "DivideByZeroException") == 0)
5257 return MONO_EXC_DIVIDE_BY_ZERO;
5258 if (strcmp (name, "InvalidCastException") == 0)
5259 return MONO_EXC_INVALID_CAST;
5260 if (strcmp (name, "NullReferenceException") == 0)
5261 return MONO_EXC_NULL_REF;
5262 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5263 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5264 if (strcmp (name, "ArgumentException") == 0)
5265 return MONO_EXC_ARGUMENT;
5266 g_error ("Unknown intrinsic exception %s\n", name);
5267 return 0;
5270 #ifndef DISABLE_JIT
5271 void
5272 mono_arch_emit_exceptions (MonoCompile *cfg)
5274 MonoJumpInfo *patch_info;
5275 int i;
5276 guint8 *code;
5277 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5278 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5279 int max_epilog_size = 50;
5281 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5282 exc_throw_pos [i] = NULL;
5283 exc_throw_found [i] = 0;
5286 /* count the number of exception infos */
5289 * make sure we have enough space for exceptions
5291 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5292 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5293 i = exception_id_by_name (patch_info->data.target);
5294 if (!exc_throw_found [i]) {
5295 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5296 exc_throw_found [i] = TRUE;
5298 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5299 max_epilog_size += 12;
5300 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5301 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5302 i = exception_id_by_name (ovfj->data.exception);
5303 if (!exc_throw_found [i]) {
5304 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5305 exc_throw_found [i] = TRUE;
5307 max_epilog_size += 8;
5311 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5312 cfg->code_size *= 2;
5313 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5314 cfg->stat_code_reallocs++;
5317 code = cfg->native_code + cfg->code_len;
5319 /* add code to raise exceptions */
5320 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5321 switch (patch_info->type) {
5322 case MONO_PATCH_INFO_BB_OVF: {
5323 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5324 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5325 /* patch the initial jump */
5326 ppc_patch (ip, code);
5327 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5328 ppc_b (code, 0);
5329 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5330 /* jump back to the true target */
5331 ppc_b (code, 0);
5332 ip = ovfj->data.bb->native_offset + cfg->native_code;
5333 ppc_patch (code - 4, ip);
5334 patch_info->type = MONO_PATCH_INFO_NONE;
5335 break;
5337 case MONO_PATCH_INFO_EXC_OVF: {
5338 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5339 MonoJumpInfo *newji;
5340 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5341 unsigned char *bcl = code;
5342 /* patch the initial jump: we arrived here with a call */
5343 ppc_patch (ip, code);
5344 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5345 ppc_b (code, 0);
5346 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5347 /* patch the conditional jump to the right handler */
5348 /* make it processed next */
5349 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5350 newji->type = MONO_PATCH_INFO_EXC;
5351 newji->ip.i = bcl - cfg->native_code;
5352 newji->data.target = ovfj->data.exception;
5353 newji->next = patch_info->next;
5354 patch_info->next = newji;
5355 patch_info->type = MONO_PATCH_INFO_NONE;
5356 break;
5358 case MONO_PATCH_INFO_EXC: {
5359 MonoClass *exc_class;
5361 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5362 i = exception_id_by_name (patch_info->data.target);
5363 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5364 ppc_patch (ip, exc_throw_pos [i]);
5365 patch_info->type = MONO_PATCH_INFO_NONE;
5366 break;
5367 } else {
5368 exc_throw_pos [i] = code;
5371 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5372 g_assert (exc_class);
5374 ppc_patch (ip, code);
5375 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5376 ppc_load (code, ppc_r3, exc_class->type_token);
5377 /* we got here from a conditional call, so the calling ip is set in lr */
5378 ppc_mflr (code, ppc_r4);
5379 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5380 patch_info->data.name = "mono_arch_throw_corlib_exception";
5381 patch_info->ip.i = code - cfg->native_code;
5382 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5383 ppc_load_func (code, ppc_r0, 0);
5384 ppc_mtctr (code, ppc_r0);
5385 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5386 } else {
5387 ppc_bl (code, 0);
5389 break;
5391 default:
5392 /* do nothing */
5393 break;
5397 cfg->code_len = code - cfg->native_code;
5399 g_assert (cfg->code_len <= cfg->code_size);
5401 #endif
5403 #if DEAD_CODE
5404 static int
5405 try_offset_access (void *value, guint32 idx)
5407 register void* me __asm__ ("r2");
5408 void ***p = (void***)((char*)me + 284);
5409 int idx1 = idx / 32;
5410 int idx2 = idx % 32;
5411 if (!p [idx1])
5412 return 0;
5413 if (value != p[idx1][idx2])
5414 return 0;
5415 return 1;
5417 #endif
5419 static void
5420 setup_tls_access (void)
5422 guint32 ptk;
5424 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5425 size_t conf_size = 0;
5426 char confbuf[128];
5427 #else
5428 /* FIXME for darwin */
5429 guint32 *ins, *code;
5430 guint32 cmplwi_1023, li_0x48, blr_ins;
5431 #endif
5433 #ifdef TARGET_PS3
5434 tls_mode = TLS_MODE_FAILED;
5435 #endif
5437 if (tls_mode == TLS_MODE_FAILED)
5438 return;
5439 if (g_getenv ("MONO_NO_TLS")) {
5440 tls_mode = TLS_MODE_FAILED;
5441 return;
5444 if (tls_mode == TLS_MODE_DETECT) {
5445 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5446 tls_mode = TLS_MODE_DARWIN_G4;
5447 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5448 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5449 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5450 tls_mode = TLS_MODE_NPTL;
5451 #elif !defined(TARGET_PS3)
5452 ins = (guint32*)pthread_getspecific;
5453 /* uncond branch to the real method */
5454 if ((*ins >> 26) == 18) {
5455 gint32 val;
5456 val = (*ins & ~3) << 6;
5457 val >>= 6;
5458 if (*ins & 2) {
5459 /* absolute */
5460 ins = (guint32*)(long)val;
5461 } else {
5462 ins = (guint32*) ((char*)ins + val);
5465 code = &cmplwi_1023;
5466 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5467 code = &li_0x48;
5468 ppc_li (code, ppc_r4, 0x48);
5469 code = &blr_ins;
5470 ppc_blr (code);
5471 if (*ins == cmplwi_1023) {
5472 int found_lwz_284 = 0;
5473 for (ptk = 0; ptk < 20; ++ptk) {
5474 ++ins;
5475 if (!*ins || *ins == blr_ins)
5476 break;
5477 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5478 found_lwz_284 = 1;
5479 break;
5482 if (!found_lwz_284) {
5483 tls_mode = TLS_MODE_FAILED;
5484 return;
5486 tls_mode = TLS_MODE_LTHREADS;
5487 } else if (*ins == li_0x48) {
5488 ++ins;
5489 /* uncond branch to the real method */
5490 if ((*ins >> 26) == 18) {
5491 gint32 val;
5492 val = (*ins & ~3) << 6;
5493 val >>= 6;
5494 if (*ins & 2) {
5495 /* absolute */
5496 ins = (guint32*)(long)val;
5497 } else {
5498 ins = (guint32*) ((char*)ins + val);
5500 code = (guint32*)&val;
5501 ppc_li (code, ppc_r0, 0x7FF2);
5502 if (ins [1] == val) {
5503 /* Darwin on G4, implement */
5504 tls_mode = TLS_MODE_FAILED;
5505 return;
5506 } else {
5507 code = (guint32*)&val;
5508 ppc_mfspr (code, ppc_r3, 104);
5509 if (ins [1] != val) {
5510 tls_mode = TLS_MODE_FAILED;
5511 return;
5513 tls_mode = TLS_MODE_DARWIN_G5;
5515 } else {
5516 tls_mode = TLS_MODE_FAILED;
5517 return;
5519 } else {
5520 tls_mode = TLS_MODE_FAILED;
5521 return;
5523 #endif
5525 #ifndef TARGET_PS3
5526 if (tls_mode == TLS_MODE_DETECT)
5527 tls_mode = TLS_MODE_FAILED;
5528 if (tls_mode == TLS_MODE_FAILED)
5529 return;
5530 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5531 monodomain_key = mono_domain_get_tls_offset();
5533 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5534 mono_domain_get_tls_offset returning -1) then use keyed access. */
5535 if (monodomain_key == -1) {
5536 ptk = mono_domain_get_tls_key ();
5537 if (ptk < 1024)
5538 monodomain_key = ptk;
5541 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5542 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5545 #if 0
5546 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5547 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5548 if (lmf_pthread_key == -1) {
5549 ptk = mono_jit_tls_id;
5550 if (ptk < 1024) {
5551 /*g_print ("MonoLMF at: %d\n", ptk);*/
5552 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5553 init_tls_failed = 1;
5554 return;
5556 lmf_pthread_key = ptk;
5559 #endif
5561 #endif
5564 void
5565 mono_arch_finish_init (void)
5567 setup_tls_access ();
5570 void
5571 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5575 #ifdef MONO_ARCH_HAVE_IMT
5577 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5578 #define BR_SIZE 4
5579 #define LOADSTORE_SIZE 4
5580 #define JUMP_IMM_SIZE 12
5581 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5582 #define ENABLE_WRONG_METHOD_CHECK 0
5585 * LOCKING: called with the domain lock held
5587 gpointer
5588 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5589 gpointer fail_tramp)
5591 int i;
5592 int size = 0;
5593 guint8 *code, *start;
5595 for (i = 0; i < count; ++i) {
5596 MonoIMTCheckItem *item = imt_entries [i];
5597 if (item->is_equals) {
5598 if (item->check_target_idx) {
5599 if (!item->compare_done)
5600 item->chunk_size += CMP_SIZE;
5601 if (item->has_target_code)
5602 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5603 else
5604 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5605 } else {
5606 if (fail_tramp) {
5607 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5608 if (!item->has_target_code)
5609 item->chunk_size += LOADSTORE_SIZE;
5610 } else {
5611 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5612 #if ENABLE_WRONG_METHOD_CHECK
5613 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5614 #endif
5617 } else {
5618 item->chunk_size += CMP_SIZE + BR_SIZE;
5619 imt_entries [item->check_target_idx]->compare_done = TRUE;
5621 size += item->chunk_size;
5623 /* the initial load of the vtable address */
5624 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5625 if (fail_tramp) {
5626 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5627 } else {
5628 code = mono_domain_code_reserve (domain, size);
5630 start = code;
5633 * We need to save and restore r11 because it might be
5634 * used by the caller as the vtable register, so
5635 * clobbering it will trip up the magic trampoline.
5637 * FIXME: Get rid of this by making sure that r11 is
5638 * not used as the vtable register in interface calls.
5640 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5641 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5643 for (i = 0; i < count; ++i) {
5644 MonoIMTCheckItem *item = imt_entries [i];
5645 item->code_target = code;
5646 if (item->is_equals) {
5647 if (item->check_target_idx) {
5648 if (!item->compare_done) {
5649 ppc_load (code, ppc_r0, (gsize)item->key);
5650 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5652 item->jmp_code = code;
5653 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5654 if (item->has_target_code) {
5655 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5656 } else {
5657 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5658 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5660 ppc_mtctr (code, ppc_r0);
5661 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5662 } else {
5663 if (fail_tramp) {
5664 ppc_load (code, ppc_r0, (gulong)item->key);
5665 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5666 item->jmp_code = code;
5667 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5668 if (item->has_target_code) {
5669 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5670 } else {
5671 g_assert (vtable);
5672 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5673 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5675 ppc_mtctr (code, ppc_r0);
5676 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5677 ppc_patch (item->jmp_code, code);
5678 ppc_load_ptr (code, ppc_r0, fail_tramp);
5679 ppc_mtctr (code, ppc_r0);
5680 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5681 item->jmp_code = NULL;
5682 } else {
5683 /* enable the commented code to assert on wrong method */
5684 #if ENABLE_WRONG_METHOD_CHECK
5685 ppc_load (code, ppc_r0, (guint32)item->key);
5686 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5687 item->jmp_code = code;
5688 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5689 #endif
5690 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5691 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5692 ppc_mtctr (code, ppc_r0);
5693 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5694 #if ENABLE_WRONG_METHOD_CHECK
5695 ppc_patch (item->jmp_code, code);
5696 ppc_break (code);
5697 item->jmp_code = NULL;
5698 #endif
5701 } else {
5702 ppc_load (code, ppc_r0, (gulong)item->key);
5703 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5704 item->jmp_code = code;
5705 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5708 /* patch the branches to get to the target items */
5709 for (i = 0; i < count; ++i) {
5710 MonoIMTCheckItem *item = imt_entries [i];
5711 if (item->jmp_code) {
5712 if (item->check_target_idx) {
5713 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5718 if (!fail_tramp)
5719 mono_stats.imt_thunks_size += code - start;
5720 g_assert (code - start <= size);
5721 mono_arch_flush_icache (start, size);
5722 return start;
5725 MonoMethod*
5726 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5728 mgreg_t *r = (mgreg_t*)regs;
5730 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5732 #endif
5734 MonoVTable*
5735 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5737 mgreg_t *r = (mgreg_t*)regs;
5739 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5742 GSList*
5743 mono_arch_get_cie_program (void)
5745 GSList *l = NULL;
5747 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5749 return l;
5752 MonoInst*
5753 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5755 /* FIXME: */
5756 return NULL;
5759 gboolean
5760 mono_arch_print_tree (MonoInst *tree, int arity)
5762 return 0;
5765 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5767 MonoInst* ins;
5769 setup_tls_access ();
5770 if (monodomain_key == -1)
5771 return NULL;
5773 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5774 ins->inst_offset = monodomain_key;
5775 return ins;
5778 mgreg_t
5779 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5781 if (reg == ppc_r1)
5782 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5784 g_assert (reg >= ppc_r13);
5786 return ctx->regs [reg - ppc_r13];
5789 guint32
5790 mono_arch_get_patch_offset (guint8 *code)
5792 return 0;
5796 * mono_aot_emit_load_got_addr:
5798 * Emit code to load the got address.
5799 * On PPC, the result is placed into r30.
5801 guint8*
5802 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5804 ppc_bl (code, 1);
5805 ppc_mflr (code, ppc_r30);
5806 if (cfg)
5807 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5808 else
5809 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5810 /* arch_emit_got_address () patches this */
5811 #if defined(TARGET_POWERPC64)
5812 ppc_nop (code);
5813 ppc_nop (code);
5814 ppc_nop (code);
5815 ppc_nop (code);
5816 #else
5817 ppc_load32 (code, ppc_r0, 0);
5818 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5819 #endif
5821 return code;
5825 * mono_ppc_emit_load_aotconst:
5827 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5828 * TARGET from the mscorlib GOT in full-aot code.
5829 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5830 * r11.
5832 guint8*
5833 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5835 /* Load the mscorlib got address */
5836 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5837 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5838 /* arch_emit_got_access () patches this */
5839 ppc_load32 (code, ppc_r0, 0);
5840 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5842 return code;
5845 /* Soft Debug support */
5846 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5849 * BREAKPOINTS
5853 * mono_arch_set_breakpoint:
5855 * See mini-amd64.c for docs.
5857 void
5858 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5860 guint8 *code = ip;
5861 guint8 *orig_code = code;
5863 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5864 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5866 g_assert (code - orig_code == BREAKPOINT_SIZE);
5868 mono_arch_flush_icache (orig_code, code - orig_code);
5872 * mono_arch_clear_breakpoint:
5874 * See mini-amd64.c for docs.
5876 void
5877 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5879 guint8 *code = ip;
5880 int i;
5882 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5883 ppc_nop (code);
5885 mono_arch_flush_icache (ip, code - ip);
5889 * mono_arch_is_breakpoint_event:
5891 * See mini-amd64.c for docs.
5893 gboolean
5894 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5896 siginfo_t* sinfo = (siginfo_t*) info;
5897 /* Sometimes the address is off by 4 */
5898 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5899 return TRUE;
5900 else
5901 return FALSE;
5905 * mono_arch_skip_breakpoint:
5907 * See mini-amd64.c for docs.
5909 void
5910 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5912 /* skip the ldptr */
5913 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5917 * SINGLE STEPPING
5921 * mono_arch_start_single_stepping:
5923 * See mini-amd64.c for docs.
5925 void
5926 mono_arch_start_single_stepping (void)
5928 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5932 * mono_arch_stop_single_stepping:
5934 * See mini-amd64.c for docs.
5936 void
5937 mono_arch_stop_single_stepping (void)
5939 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5943 * mono_arch_is_single_step_event:
5945 * See mini-amd64.c for docs.
5947 gboolean
5948 mono_arch_is_single_step_event (void *info, void *sigctx)
5950 siginfo_t* sinfo = (siginfo_t*) info;
5951 /* Sometimes the address is off by 4 */
5952 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5953 return TRUE;
5954 else
5955 return FALSE;
5959 * mono_arch_skip_single_step:
5961 * See mini-amd64.c for docs.
5963 void
5964 mono_arch_skip_single_step (MonoContext *ctx)
5966 /* skip the ldptr */
5967 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5971 * mono_arch_create_seq_point_info:
5973 * See mini-amd64.c for docs.
5975 gpointer
5976 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5978 NOT_IMPLEMENTED;
5979 return NULL;
5982 #endif