Update spec file to 4.5 profile
[mono-project.git] / mono / mini / mini-ppc.c
blobc59d75038a2f8abb4f971b3d813572132c00e7a9
1 /*
2 * mini-ppc.c: PowerPC backend for the Mono code generator
4 * Authors:
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
12 #include "mini.h"
13 #include <string.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/utils/mono-proclib.h>
18 #include <mono/utils/mono-mmap.h>
20 #include "mini-ppc.h"
21 #ifdef TARGET_POWERPC64
22 #include "cpu-ppc64.h"
23 #else
24 #include "cpu-ppc.h"
25 #endif
26 #include "trace.h"
27 #include "ir-emit.h"
28 #ifdef __APPLE__
29 #include <sys/sysctl.h>
30 #endif
31 #ifdef __linux__
32 #include <unistd.h>
33 #endif
35 #define FORCE_INDIR_CALL 1
37 enum {
38 TLS_MODE_DETECT,
39 TLS_MODE_FAILED,
40 TLS_MODE_LTHREADS,
41 TLS_MODE_NPTL,
42 TLS_MODE_DARWIN_G4,
43 TLS_MODE_DARWIN_G5
46 /* cpu_hw_caps contains the flags defined below */
47 static int cpu_hw_caps = 0;
48 static int cachelinesize = 0;
49 static int cachelineinc = 0;
50 enum {
51 PPC_ICACHE_SNOOP = 1 << 0,
52 PPC_MULTIPLE_LS_UNITS = 1 << 1,
53 PPC_SMP_CAPABLE = 1 << 2,
54 PPC_ISA_2X = 1 << 3,
55 PPC_ISA_64 = 1 << 4,
56 PPC_MOVE_FPR_GPR = 1 << 5,
57 PPC_HW_CAP_END
60 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
65 static CRITICAL_SECTION mini_arch_mutex;
67 int mono_exc_esp_offset = 0;
68 static int tls_mode = TLS_MODE_DETECT;
69 static int lmf_pthread_key = -1;
70 static int monodomain_key = -1;
73 * The code generated for sequence points reads from this location, which is
74 * made read-only when single stepping is enabled.
76 static gpointer ss_trigger_page;
78 /* Enabled breakpoints read from this trigger page */
79 static gpointer bp_trigger_page;
81 static int
82 offsets_from_pthread_key (guint32 key, int *offset2)
84 int idx1 = key / 32;
85 int idx2 = key % 32;
86 *offset2 = idx2 * sizeof (gpointer);
87 return 284 + idx1 * sizeof (gpointer);
90 #define emit_linuxthreads_tls(code,dreg,key) do {\
91 int off1, off2; \
92 off1 = offsets_from_pthread_key ((key), &off2); \
93 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
94 ppc_ldptr ((code), (dreg), off2, (dreg)); \
95 } while (0);
97 #define emit_darwing5_tls(code,dreg,key) do {\
98 int off1 = 0x48 + key * sizeof (gpointer); \
99 ppc_mfspr ((code), (dreg), 104); \
100 ppc_ldptr ((code), (dreg), off1, (dreg)); \
101 } while (0);
103 /* FIXME: ensure the sc call preserves all but r3 */
104 #define emit_darwing4_tls(code,dreg,key) do {\
105 int off1 = 0x48 + key * sizeof (gpointer); \
106 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
107 ppc_li ((code), ppc_r0, 0x7FF2); \
108 ppc_sc ((code)); \
109 ppc_lwz ((code), (dreg), off1, ppc_r3); \
110 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
111 } while (0);
113 #ifdef PPC_THREAD_PTR_REG
114 #define emit_nptl_tls(code,dreg,key) do { \
115 int off1 = key; \
116 int off2 = key >> 15; \
117 if ((off2 == 0) || (off2 == -1)) { \
118 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
119 } else { \
120 int off3 = (off2 + 1) > 1; \
121 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
122 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
124 } while (0);
125 #else
126 #define emit_nptl_tls(code,dreg,key) do { \
127 g_assert_not_reached (); \
128 } while (0)
129 #endif
131 #define emit_tls_access(code,dreg,key) do { \
132 switch (tls_mode) { \
133 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
134 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
135 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
137 default: g_assert_not_reached (); \
139 } while (0)
141 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
142 MonoInst *inst; \
143 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
144 inst->type = STACK_R8; \
145 inst->dreg = (dr); \
146 inst->inst_p0 = (void*)(addr); \
147 mono_bblock_add_inst (cfg->cbb, inst); \
148 } while (0)
150 const char*
151 mono_arch_regname (int reg) {
152 static const char rnames[][4] = {
153 "r0", "sp", "r2", "r3", "r4",
154 "r5", "r6", "r7", "r8", "r9",
155 "r10", "r11", "r12", "r13", "r14",
156 "r15", "r16", "r17", "r18", "r19",
157 "r20", "r21", "r22", "r23", "r24",
158 "r25", "r26", "r27", "r28", "r29",
159 "r30", "r31"
161 if (reg >= 0 && reg < 32)
162 return rnames [reg];
163 return "unknown";
166 const char*
167 mono_arch_fregname (int reg) {
168 static const char rnames[][4] = {
169 "f0", "f1", "f2", "f3", "f4",
170 "f5", "f6", "f7", "f8", "f9",
171 "f10", "f11", "f12", "f13", "f14",
172 "f15", "f16", "f17", "f18", "f19",
173 "f20", "f21", "f22", "f23", "f24",
174 "f25", "f26", "f27", "f28", "f29",
175 "f30", "f31"
177 if (reg >= 0 && reg < 32)
178 return rnames [reg];
179 return "unknown";
182 /* this function overwrites r0, r11, r12 */
183 static guint8*
184 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
186 /* unrolled, use the counter in big */
187 if (size > sizeof (gpointer) * 5) {
188 long shifted = size / SIZEOF_VOID_P;
189 guint8 *copy_loop_start, *copy_loop_jump;
191 ppc_load (code, ppc_r0, shifted);
192 ppc_mtctr (code, ppc_r0);
193 //g_assert (sreg == ppc_r11);
194 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
195 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
196 copy_loop_start = code;
197 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
198 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 copy_loop_jump = code;
200 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
201 ppc_patch (copy_loop_jump, copy_loop_start);
202 size -= shifted * sizeof (gpointer);
203 doffset = soffset = 0;
204 dreg = ppc_r12;
206 #ifdef __mono_ppc64__
207 /* the hardware has multiple load/store units and the move is long
208 enough to use more then one regiester, then use load/load/store/store
209 to execute 2 instructions per cycle. */
210 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
211 while (size >= 16) {
212 ppc_ldptr (code, ppc_r0, soffset, sreg);
213 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
214 ppc_stptr (code, ppc_r0, doffset, dreg);
215 ppc_stptr (code, ppc_r12, doffset+8, dreg);
216 size -= 16;
217 soffset += 16;
218 doffset += 16;
221 while (size >= 8) {
222 ppc_ldr (code, ppc_r0, soffset, sreg);
223 ppc_str (code, ppc_r0, doffset, dreg);
224 size -= 8;
225 soffset += 8;
226 doffset += 8;
228 #else
229 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
230 while (size >= 8) {
231 ppc_lwz (code, ppc_r0, soffset, sreg);
232 ppc_lwz (code, ppc_r12, soffset+4, sreg);
233 ppc_stw (code, ppc_r0, doffset, dreg);
234 ppc_stw (code, ppc_r12, doffset+4, dreg);
235 size -= 8;
236 soffset += 8;
237 doffset += 8;
240 #endif
241 while (size >= 4) {
242 ppc_lwz (code, ppc_r0, soffset, sreg);
243 ppc_stw (code, ppc_r0, doffset, dreg);
244 size -= 4;
245 soffset += 4;
246 doffset += 4;
248 while (size >= 2) {
249 ppc_lhz (code, ppc_r0, soffset, sreg);
250 ppc_sth (code, ppc_r0, doffset, dreg);
251 size -= 2;
252 soffset += 2;
253 doffset += 2;
255 while (size >= 1) {
256 ppc_lbz (code, ppc_r0, soffset, sreg);
257 ppc_stb (code, ppc_r0, doffset, dreg);
258 size -= 1;
259 soffset += 1;
260 doffset += 1;
262 return code;
266 * mono_arch_get_argument_info:
267 * @csig: a method signature
268 * @param_count: the number of parameters to consider
269 * @arg_info: an array to store the result infos
271 * Gathers information on parameters such as size, alignment and
272 * padding. arg_info should be large enought to hold param_count + 1 entries.
274 * Returns the size of the activation frame.
277 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
279 #ifdef __mono_ppc64__
280 NOT_IMPLEMENTED;
281 return -1;
282 #else
283 int k, frame_size = 0;
284 int size, align, pad;
285 int offset = 8;
287 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
288 frame_size += sizeof (gpointer);
289 offset += 4;
292 arg_info [0].offset = offset;
294 if (csig->hasthis) {
295 frame_size += sizeof (gpointer);
296 offset += 4;
299 arg_info [0].size = frame_size;
301 for (k = 0; k < param_count; k++) {
303 if (csig->pinvoke)
304 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
305 else
306 size = mini_type_stack_size (NULL, csig->params [k], &align);
308 /* ignore alignment for now */
309 align = 1;
311 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
312 arg_info [k].pad = pad;
313 frame_size += size;
314 arg_info [k + 1].pad = 0;
315 arg_info [k + 1].size = size;
316 offset += pad;
317 arg_info [k + 1].offset = offset;
318 offset += size;
321 align = MONO_ARCH_FRAME_ALIGNMENT;
322 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
323 arg_info [k].pad = pad;
325 return frame_size;
326 #endif
329 #ifdef __mono_ppc64__
330 static gboolean
331 is_load_sequence (guint32 *seq)
333 return ppc_opcode (seq [0]) == 15 && /* lis */
334 ppc_opcode (seq [1]) == 24 && /* ori */
335 ppc_opcode (seq [2]) == 30 && /* sldi */
336 ppc_opcode (seq [3]) == 25 && /* oris */
337 ppc_opcode (seq [4]) == 24; /* ori */
340 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
341 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
342 #endif
344 /* 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_optimizazions (guint32 *exclude_mask)
664 guint32 opts = 0;
666 /* no ppc-specific optimizations yet */
667 *exclude_mask = 0;
668 return opts;
671 #ifdef __mono_ppc64__
672 #define CASE_PPC32(c)
673 #define CASE_PPC64(c) case c:
674 #else
675 #define CASE_PPC32(c) case c:
676 #define CASE_PPC64(c)
677 #endif
679 static gboolean
680 is_regsize_var (MonoType *t) {
681 if (t->byref)
682 return TRUE;
683 t = mini_type_get_underlying_type (NULL, t);
684 switch (t->type) {
685 case MONO_TYPE_I4:
686 case MONO_TYPE_U4:
687 CASE_PPC64 (MONO_TYPE_I8)
688 CASE_PPC64 (MONO_TYPE_U8)
689 case MONO_TYPE_I:
690 case MONO_TYPE_U:
691 case MONO_TYPE_PTR:
692 case MONO_TYPE_FNPTR:
693 return TRUE;
694 case MONO_TYPE_OBJECT:
695 case MONO_TYPE_STRING:
696 case MONO_TYPE_CLASS:
697 case MONO_TYPE_SZARRAY:
698 case MONO_TYPE_ARRAY:
699 return TRUE;
700 case MONO_TYPE_GENERICINST:
701 if (!mono_type_generic_inst_is_valuetype (t))
702 return TRUE;
703 return FALSE;
704 case MONO_TYPE_VALUETYPE:
705 return FALSE;
707 return FALSE;
710 #ifndef DISABLE_JIT
711 GList *
712 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
714 GList *vars = NULL;
715 int i;
717 for (i = 0; i < cfg->num_varinfo; i++) {
718 MonoInst *ins = cfg->varinfo [i];
719 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
721 /* unused vars */
722 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
723 continue;
725 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
726 continue;
728 /* we can only allocate 32 bit values */
729 if (is_regsize_var (ins->inst_vtype)) {
730 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
731 g_assert (i == vmv->idx);
732 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
736 return vars;
738 #endif /* ifndef DISABLE_JIT */
740 GList *
741 mono_arch_get_global_int_regs (MonoCompile *cfg)
743 GList *regs = NULL;
744 int i, top = 32;
745 if (cfg->frame_reg != ppc_sp)
746 top = 31;
747 /* ppc_r13 is used by the system on PPC EABI */
748 for (i = 14; i < top; ++i) {
750 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
751 * since the trampolines can clobber r11.
753 if (!(cfg->compile_aot && i == 29))
754 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
757 return regs;
761 * mono_arch_regalloc_cost:
763 * Return the cost, in number of memory references, of the action of
764 * allocating the variable VMV into a register during global register
765 * allocation.
767 guint32
768 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
770 /* FIXME: */
771 return 2;
774 void
775 mono_arch_flush_icache (guint8 *code, gint size)
777 #ifdef MONO_CROSS_COMPILE
778 #else
779 register guint8 *p;
780 guint8 *endp, *start;
782 p = start = code;
783 endp = p + size;
784 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
785 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
786 #if defined(G_COMPILER_CODEWARRIOR)
787 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
788 for (p = start; p < endp; p += cachelineinc) {
789 asm { dcbf 0, p };
791 } else {
792 for (p = start; p < endp; p += cachelineinc) {
793 asm { dcbst 0, p };
796 asm { sync };
797 p = code;
798 for (p = start; p < endp; p += cachelineinc) {
799 asm {
800 icbi 0, p
801 sync
804 asm {
805 sync
806 isync
808 #else
809 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
810 * The sync is required to insure that the store queue is completely empty.
811 * While the icbi performs no cache operations, icbi/isync is required to
812 * kill local prefetch.
814 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
815 asm ("sync");
816 asm ("icbi 0,%0;" : : "r"(code) : "memory");
817 asm ("isync");
818 return;
820 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
821 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
822 for (p = start; p < endp; p += cachelineinc) {
823 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
825 } else {
826 for (p = start; p < endp; p += cachelineinc) {
827 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
830 asm ("sync");
831 p = code;
832 for (p = start; p < endp; p += cachelineinc) {
833 /* for ISA2.0+ implementations we should not need any extra sync between the
834 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
835 * So I am not sure which chip had this problem but its not an issue on
836 * of the ISA V2 chips.
838 if (cpu_hw_caps & PPC_ISA_2X)
839 asm ("icbi 0,%0;" : : "r"(p) : "memory");
840 else
841 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
843 if (!(cpu_hw_caps & PPC_ISA_2X))
844 asm ("sync");
845 asm ("isync");
846 #endif
847 #endif
850 void
851 mono_arch_flush_register_windows (void)
855 #ifdef __APPLE__
856 #define ALWAYS_ON_STACK(s) s
857 #define FP_ALSO_IN_REG(s) s
858 #else
859 #ifdef __mono_ppc64__
860 #define ALWAYS_ON_STACK(s) s
861 #define FP_ALSO_IN_REG(s) s
862 #else
863 #define ALWAYS_ON_STACK(s)
864 #define FP_ALSO_IN_REG(s)
865 #endif
866 #define ALIGN_DOUBLES
867 #endif
869 enum {
870 RegTypeGeneral,
871 RegTypeBase,
872 RegTypeFP,
873 RegTypeStructByVal,
874 RegTypeStructByAddr
877 typedef struct {
878 gint32 offset;
879 guint32 vtsize; /* in param area */
880 guint8 reg;
881 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
882 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
883 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
884 guint8 bytes : 4; /* size in bytes - only valid for
885 RegTypeStructByVal if the struct fits
886 in one word, otherwise it's 0*/
887 } ArgInfo;
889 typedef struct {
890 int nargs;
891 guint32 stack_usage;
892 guint32 struct_ret;
893 ArgInfo ret;
894 ArgInfo sig_cookie;
895 gboolean vtype_retaddr;
896 int vret_arg_index;
897 ArgInfo args [1];
898 } CallInfo;
900 #define DEBUG(a)
902 static void inline
903 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
905 #ifdef __mono_ppc64__
906 g_assert (simple);
907 #endif
909 if (simple) {
910 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
911 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
912 ainfo->reg = ppc_sp; /* in the caller */
913 ainfo->regtype = RegTypeBase;
914 *stack_size += sizeof (gpointer);
915 } else {
916 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
917 ainfo->reg = *gr;
919 } else {
920 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
921 #ifdef ALIGN_DOUBLES
922 //*stack_size += (*stack_size % 8);
923 #endif
924 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
925 ainfo->reg = ppc_sp; /* in the caller */
926 ainfo->regtype = RegTypeBase;
927 *stack_size += 8;
928 } else {
929 #ifdef ALIGN_DOUBLES
930 if (!((*gr) & 1))
931 (*gr) ++;
932 #endif
933 ALWAYS_ON_STACK (*stack_size += 8);
934 ainfo->reg = *gr;
936 (*gr) ++;
938 (*gr) ++;
941 #if defined(__APPLE__) || defined(__mono_ppc64__)
942 static gboolean
943 has_only_a_r48_field (MonoClass *klass)
945 gpointer iter;
946 MonoClassField *f;
947 gboolean have_field = FALSE;
948 iter = NULL;
949 while ((f = mono_class_get_fields (klass, &iter))) {
950 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
951 if (have_field)
952 return FALSE;
953 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
954 have_field = TRUE;
955 else
956 return FALSE;
959 return have_field;
961 #endif
963 static CallInfo*
964 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
966 guint i, fr, gr, pstart;
967 int n = sig->hasthis + sig->param_count;
968 MonoType *simpletype;
969 guint32 stack_size = 0;
970 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
971 gboolean is_pinvoke = sig->pinvoke;
973 fr = PPC_FIRST_FPARG_REG;
974 gr = PPC_FIRST_ARG_REG;
976 /* FIXME: handle returning a struct */
977 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
978 cinfo->vtype_retaddr = TRUE;
981 pstart = 0;
982 n = 0;
984 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
985 * the first argument, allowing 'this' to be always passed in the first arg reg.
986 * Also do this if the first argument is a reference type, since virtual calls
987 * are sometimes made using calli without sig->hasthis set, like in the delegate
988 * invoke wrappers.
990 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]))))) {
991 if (sig->hasthis) {
992 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
993 n ++;
994 } else {
995 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
996 pstart = 1;
997 n ++;
999 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1000 cinfo->struct_ret = cinfo->ret.reg;
1001 cinfo->vret_arg_index = 1;
1002 } else {
1003 /* this */
1004 if (sig->hasthis) {
1005 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1006 n ++;
1009 if (cinfo->vtype_retaddr) {
1010 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1011 cinfo->struct_ret = cinfo->ret.reg;
1015 DEBUG(printf("params: %d\n", sig->param_count));
1016 for (i = pstart; i < sig->param_count; ++i) {
1017 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1018 /* Prevent implicit arguments and sig_cookie from
1019 being passed in registers */
1020 gr = PPC_LAST_ARG_REG + 1;
1021 /* FIXME: don't we have to set fr, too? */
1022 /* Emit the signature cookie just before the implicit arguments */
1023 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1025 DEBUG(printf("param %d: ", i));
1026 if (sig->params [i]->byref) {
1027 DEBUG(printf("byref\n"));
1028 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1029 n++;
1030 continue;
1032 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1033 switch (simpletype->type) {
1034 case MONO_TYPE_BOOLEAN:
1035 case MONO_TYPE_I1:
1036 case MONO_TYPE_U1:
1037 cinfo->args [n].size = 1;
1038 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1039 n++;
1040 break;
1041 case MONO_TYPE_CHAR:
1042 case MONO_TYPE_I2:
1043 case MONO_TYPE_U2:
1044 cinfo->args [n].size = 2;
1045 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1046 n++;
1047 break;
1048 case MONO_TYPE_I4:
1049 case MONO_TYPE_U4:
1050 cinfo->args [n].size = 4;
1051 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1052 n++;
1053 break;
1054 case MONO_TYPE_I:
1055 case MONO_TYPE_U:
1056 case MONO_TYPE_PTR:
1057 case MONO_TYPE_FNPTR:
1058 case MONO_TYPE_CLASS:
1059 case MONO_TYPE_OBJECT:
1060 case MONO_TYPE_STRING:
1061 case MONO_TYPE_SZARRAY:
1062 case MONO_TYPE_ARRAY:
1063 cinfo->args [n].size = sizeof (gpointer);
1064 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1065 n++;
1066 break;
1067 case MONO_TYPE_GENERICINST:
1068 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1069 cinfo->args [n].size = sizeof (gpointer);
1070 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1071 n++;
1072 break;
1074 /* Fall through */
1075 case MONO_TYPE_VALUETYPE:
1076 case MONO_TYPE_TYPEDBYREF: {
1077 gint size;
1078 MonoClass *klass;
1080 klass = mono_class_from_mono_type (sig->params [i]);
1081 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1082 size = sizeof (MonoTypedRef);
1083 else if (is_pinvoke)
1084 size = mono_class_native_size (klass, NULL);
1085 else
1086 size = mono_class_value_size (klass, NULL);
1088 #if defined(__APPLE__) || defined(__mono_ppc64__)
1089 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1090 cinfo->args [n].size = size;
1092 /* It was 7, now it is 8 in LinuxPPC */
1093 if (fr <= PPC_LAST_FPARG_REG) {
1094 cinfo->args [n].regtype = RegTypeFP;
1095 cinfo->args [n].reg = fr;
1096 fr ++;
1097 FP_ALSO_IN_REG (gr ++);
1098 if (size == 8)
1099 FP_ALSO_IN_REG (gr ++);
1100 ALWAYS_ON_STACK (stack_size += size);
1101 } else {
1102 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1103 cinfo->args [n].regtype = RegTypeBase;
1104 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1105 stack_size += 8;
1107 n++;
1108 break;
1110 #endif
1111 DEBUG(printf ("load %d bytes struct\n",
1112 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1114 #if PPC_PASS_STRUCTS_BY_VALUE
1116 int align_size = size;
1117 int nregs = 0;
1118 int rest = PPC_LAST_ARG_REG - gr + 1;
1119 int n_in_regs;
1121 align_size += (sizeof (gpointer) - 1);
1122 align_size &= ~(sizeof (gpointer) - 1);
1123 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1124 n_in_regs = MIN (rest, nregs);
1125 if (n_in_regs < 0)
1126 n_in_regs = 0;
1127 #ifdef __APPLE__
1128 /* FIXME: check this */
1129 if (size >= 3 && size % 4 != 0)
1130 n_in_regs = 0;
1131 #endif
1132 cinfo->args [n].regtype = RegTypeStructByVal;
1133 cinfo->args [n].vtregs = n_in_regs;
1134 cinfo->args [n].size = n_in_regs;
1135 cinfo->args [n].vtsize = nregs - n_in_regs;
1136 cinfo->args [n].reg = gr;
1138 #ifdef __mono_ppc64__
1139 if (nregs == 1 && is_pinvoke)
1140 cinfo->args [n].bytes = size;
1141 else
1142 #endif
1143 cinfo->args [n].bytes = 0;
1144 gr += n_in_regs;
1145 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1146 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1147 stack_size += nregs * sizeof (gpointer);
1149 #else
1150 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1151 cinfo->args [n].regtype = RegTypeStructByAddr;
1152 cinfo->args [n].vtsize = size;
1153 #endif
1154 n++;
1155 break;
1157 case MONO_TYPE_U8:
1158 case MONO_TYPE_I8:
1159 cinfo->args [n].size = 8;
1160 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1161 n++;
1162 break;
1163 case MONO_TYPE_R4:
1164 cinfo->args [n].size = 4;
1166 /* It was 7, now it is 8 in LinuxPPC */
1167 if (fr <= PPC_LAST_FPARG_REG) {
1168 cinfo->args [n].regtype = RegTypeFP;
1169 cinfo->args [n].reg = fr;
1170 fr ++;
1171 FP_ALSO_IN_REG (gr ++);
1172 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1173 } else {
1174 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1175 cinfo->args [n].regtype = RegTypeBase;
1176 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1177 stack_size += SIZEOF_REGISTER;
1179 n++;
1180 break;
1181 case MONO_TYPE_R8:
1182 cinfo->args [n].size = 8;
1183 /* It was 7, now it is 8 in LinuxPPC */
1184 if (fr <= PPC_LAST_FPARG_REG) {
1185 cinfo->args [n].regtype = RegTypeFP;
1186 cinfo->args [n].reg = fr;
1187 fr ++;
1188 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1189 ALWAYS_ON_STACK (stack_size += 8);
1190 } else {
1191 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1192 cinfo->args [n].regtype = RegTypeBase;
1193 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1194 stack_size += 8;
1196 n++;
1197 break;
1198 default:
1199 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1202 cinfo->nargs = n;
1204 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1205 /* Prevent implicit arguments and sig_cookie from
1206 being passed in registers */
1207 gr = PPC_LAST_ARG_REG + 1;
1208 /* Emit the signature cookie just before the implicit arguments */
1209 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1213 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1214 switch (simpletype->type) {
1215 case MONO_TYPE_BOOLEAN:
1216 case MONO_TYPE_I1:
1217 case MONO_TYPE_U1:
1218 case MONO_TYPE_I2:
1219 case MONO_TYPE_U2:
1220 case MONO_TYPE_CHAR:
1221 case MONO_TYPE_I4:
1222 case MONO_TYPE_U4:
1223 case MONO_TYPE_I:
1224 case MONO_TYPE_U:
1225 case MONO_TYPE_PTR:
1226 case MONO_TYPE_FNPTR:
1227 case MONO_TYPE_CLASS:
1228 case MONO_TYPE_OBJECT:
1229 case MONO_TYPE_SZARRAY:
1230 case MONO_TYPE_ARRAY:
1231 case MONO_TYPE_STRING:
1232 cinfo->ret.reg = ppc_r3;
1233 break;
1234 case MONO_TYPE_U8:
1235 case MONO_TYPE_I8:
1236 cinfo->ret.reg = ppc_r3;
1237 break;
1238 case MONO_TYPE_R4:
1239 case MONO_TYPE_R8:
1240 cinfo->ret.reg = ppc_f1;
1241 cinfo->ret.regtype = RegTypeFP;
1242 break;
1243 case MONO_TYPE_GENERICINST:
1244 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1245 cinfo->ret.reg = ppc_r3;
1246 break;
1248 break;
1249 case MONO_TYPE_VALUETYPE:
1250 break;
1251 case MONO_TYPE_TYPEDBYREF:
1252 case MONO_TYPE_VOID:
1253 break;
1254 default:
1255 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1259 /* align stack size to 16 */
1260 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1261 stack_size = (stack_size + 15) & ~15;
1263 cinfo->stack_usage = stack_size;
1264 return cinfo;
1267 G_GNUC_UNUSED static void
1268 break_count (void)
1272 G_GNUC_UNUSED static gboolean
1273 debug_count (void)
1275 static int count = 0;
1276 count ++;
1278 if (!getenv ("COUNT"))
1279 return TRUE;
1281 if (count == atoi (getenv ("COUNT"))) {
1282 break_count ();
1285 if (count > atoi (getenv ("COUNT"))) {
1286 return FALSE;
1289 return TRUE;
1292 gboolean
1293 mono_ppc_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1295 CallInfo *c1, *c2;
1296 gboolean res;
1297 int i;
1299 c1 = get_call_info (NULL, caller_sig);
1300 c2 = get_call_info (NULL, callee_sig);
1301 res = c1->stack_usage >= c2->stack_usage;
1302 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1303 /* An address on the callee's stack is passed as the first argument */
1304 res = FALSE;
1305 for (i = 0; i < c2->nargs; ++i) {
1306 if (c2->args [i].regtype == RegTypeStructByAddr)
1307 /* An address on the callee's stack is passed as the argument */
1308 res = FALSE;
1312 if (!debug_count ())
1313 res = FALSE;
1316 g_free (c1);
1317 g_free (c2);
1319 return res;
1323 * Set var information according to the calling convention. ppc version.
1324 * The locals var stuff should most likely be split in another method.
1326 void
1327 mono_arch_allocate_vars (MonoCompile *m)
1329 MonoMethodSignature *sig;
1330 MonoMethodHeader *header;
1331 MonoInst *inst;
1332 int i, offset, size, align, curinst;
1333 int frame_reg = ppc_sp;
1334 gint32 *offsets;
1335 guint32 locals_stack_size, locals_stack_align;
1337 m->flags |= MONO_CFG_HAS_SPILLUP;
1339 /* allow room for the vararg method args: void* and long/double */
1340 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1341 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1342 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1343 * call convs needs to be handled this way.
1345 if (m->flags & MONO_CFG_HAS_VARARGS)
1346 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1347 /* gtk-sharp and other broken code will dllimport vararg functions even with
1348 * non-varargs signatures. Since there is little hope people will get this right
1349 * we assume they won't.
1351 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1352 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1354 header = m->header;
1357 * We use the frame register also for any method that has
1358 * exception clauses. This way, when the handlers are called,
1359 * the code will reference local variables using the frame reg instead of
1360 * the stack pointer: if we had to restore the stack pointer, we'd
1361 * corrupt the method frames that are already on the stack (since
1362 * filters get called before stack unwinding happens) when the filter
1363 * code would call any method (this also applies to finally etc.).
1365 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1366 frame_reg = ppc_r31;
1367 m->frame_reg = frame_reg;
1368 if (frame_reg != ppc_sp) {
1369 m->used_int_regs |= 1 << frame_reg;
1372 sig = mono_method_signature (m->method);
1374 offset = 0;
1375 curinst = 0;
1376 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1377 m->ret->opcode = OP_REGVAR;
1378 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1379 } else {
1380 /* FIXME: handle long values? */
1381 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1382 case MONO_TYPE_VOID:
1383 break;
1384 case MONO_TYPE_R4:
1385 case MONO_TYPE_R8:
1386 m->ret->opcode = OP_REGVAR;
1387 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1388 break;
1389 default:
1390 m->ret->opcode = OP_REGVAR;
1391 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1392 break;
1395 /* local vars are at a positive offset from the stack pointer */
1397 * also note that if the function uses alloca, we use ppc_r31
1398 * to point at the local variables.
1400 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1401 /* align the offset to 16 bytes: not sure this is needed here */
1402 //offset += 16 - 1;
1403 //offset &= ~(16 - 1);
1405 /* add parameter area size for called functions */
1406 offset += m->param_area;
1407 offset += 16 - 1;
1408 offset &= ~(16 - 1);
1410 /* allow room to save the return value */
1411 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1412 offset += 8;
1414 /* the MonoLMF structure is stored just below the stack pointer */
1416 #if 0
1417 /* this stuff should not be needed on ppc and the new jit,
1418 * because a call on ppc to the handlers doesn't change the
1419 * stack pointer and the jist doesn't manipulate the stack pointer
1420 * for operations involving valuetypes.
1422 /* reserve space to store the esp */
1423 offset += sizeof (gpointer);
1425 /* this is a global constant */
1426 mono_exc_esp_offset = offset;
1427 #endif
1429 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1430 offset += sizeof(gpointer) - 1;
1431 offset &= ~(sizeof(gpointer) - 1);
1433 m->vret_addr->opcode = OP_REGOFFSET;
1434 m->vret_addr->inst_basereg = frame_reg;
1435 m->vret_addr->inst_offset = offset;
1437 if (G_UNLIKELY (m->verbose_level > 1)) {
1438 printf ("vret_addr =");
1439 mono_print_ins (m->vret_addr);
1442 offset += sizeof(gpointer);
1445 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1446 if (locals_stack_align) {
1447 offset += (locals_stack_align - 1);
1448 offset &= ~(locals_stack_align - 1);
1450 for (i = m->locals_start; i < m->num_varinfo; i++) {
1451 if (offsets [i] != -1) {
1452 MonoInst *inst = m->varinfo [i];
1453 inst->opcode = OP_REGOFFSET;
1454 inst->inst_basereg = frame_reg;
1455 inst->inst_offset = offset + offsets [i];
1457 g_print ("allocating local %d (%s) to %d\n",
1458 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1462 offset += locals_stack_size;
1464 curinst = 0;
1465 if (sig->hasthis) {
1466 inst = m->args [curinst];
1467 if (inst->opcode != OP_REGVAR) {
1468 inst->opcode = OP_REGOFFSET;
1469 inst->inst_basereg = frame_reg;
1470 offset += sizeof (gpointer) - 1;
1471 offset &= ~(sizeof (gpointer) - 1);
1472 inst->inst_offset = offset;
1473 offset += sizeof (gpointer);
1475 curinst++;
1478 for (i = 0; i < sig->param_count; ++i) {
1479 inst = m->args [curinst];
1480 if (inst->opcode != OP_REGVAR) {
1481 inst->opcode = OP_REGOFFSET;
1482 inst->inst_basereg = frame_reg;
1483 if (sig->pinvoke) {
1484 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1485 inst->backend.is_pinvoke = 1;
1486 } else {
1487 size = mono_type_size (sig->params [i], &align);
1489 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1490 size = align = sizeof (gpointer);
1492 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1493 * they are saved using std in the prolog.
1495 align = sizeof (gpointer);
1496 offset += align - 1;
1497 offset &= ~(align - 1);
1498 inst->inst_offset = offset;
1499 offset += size;
1501 curinst++;
1504 /* some storage for fp conversions */
1505 offset += 8 - 1;
1506 offset &= ~(8 - 1);
1507 m->arch.fp_conv_var_offset = offset;
1508 offset += 8;
1510 /* align the offset to 16 bytes */
1511 offset += 16 - 1;
1512 offset &= ~(16 - 1);
1514 /* change sign? */
1515 m->stack_offset = offset;
1517 if (sig->call_convention == MONO_CALL_VARARG) {
1518 CallInfo *cinfo = get_call_info (m->generic_sharing_context, m->method->signature);
1520 m->sig_cookie = cinfo->sig_cookie.offset;
1522 g_free(cinfo);
1526 void
1527 mono_arch_create_vars (MonoCompile *cfg)
1529 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1531 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1532 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1536 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1537 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1540 static void
1541 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1543 int sig_reg = mono_alloc_ireg (cfg);
1545 /* FIXME: Add support for signature tokens to AOT */
1546 cfg->disable_aot = TRUE;
1548 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1549 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1550 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1553 void
1554 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1556 MonoInst *in, *ins;
1557 MonoMethodSignature *sig;
1558 int i, n;
1559 CallInfo *cinfo;
1561 sig = call->signature;
1562 n = sig->param_count + sig->hasthis;
1564 cinfo = get_call_info (cfg->generic_sharing_context, sig);
1566 for (i = 0; i < n; ++i) {
1567 ArgInfo *ainfo = cinfo->args + i;
1568 MonoType *t;
1570 if (i >= sig->hasthis)
1571 t = sig->params [i - sig->hasthis];
1572 else
1573 t = &mono_defaults.int_class->byval_arg;
1574 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1576 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1577 emit_sig_cookie (cfg, call, cinfo);
1579 in = call->args [i];
1581 if (ainfo->regtype == RegTypeGeneral) {
1582 #ifndef __mono_ppc64__
1583 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1584 MONO_INST_NEW (cfg, ins, OP_MOVE);
1585 ins->dreg = mono_alloc_ireg (cfg);
1586 ins->sreg1 = in->dreg + 1;
1587 MONO_ADD_INS (cfg->cbb, ins);
1588 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1590 MONO_INST_NEW (cfg, ins, OP_MOVE);
1591 ins->dreg = mono_alloc_ireg (cfg);
1592 ins->sreg1 = in->dreg + 2;
1593 MONO_ADD_INS (cfg->cbb, ins);
1594 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1595 } else
1596 #endif
1598 MONO_INST_NEW (cfg, ins, OP_MOVE);
1599 ins->dreg = mono_alloc_ireg (cfg);
1600 ins->sreg1 = in->dreg;
1601 MONO_ADD_INS (cfg->cbb, ins);
1603 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1605 } else if (ainfo->regtype == RegTypeStructByAddr) {
1606 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1607 ins->opcode = OP_OUTARG_VT;
1608 ins->sreg1 = in->dreg;
1609 ins->klass = in->klass;
1610 ins->inst_p0 = call;
1611 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1612 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1613 MONO_ADD_INS (cfg->cbb, ins);
1614 } else if (ainfo->regtype == RegTypeStructByVal) {
1615 /* this is further handled in mono_arch_emit_outarg_vt () */
1616 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1617 ins->opcode = OP_OUTARG_VT;
1618 ins->sreg1 = in->dreg;
1619 ins->klass = in->klass;
1620 ins->inst_p0 = call;
1621 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1622 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1623 MONO_ADD_INS (cfg->cbb, ins);
1624 } else if (ainfo->regtype == RegTypeBase) {
1625 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1626 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1627 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1628 if (t->type == MONO_TYPE_R8)
1629 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1630 else
1631 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1632 } else {
1633 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1635 } else if (ainfo->regtype == RegTypeFP) {
1636 if (t->type == MONO_TYPE_VALUETYPE) {
1637 /* this is further handled in mono_arch_emit_outarg_vt () */
1638 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1639 ins->opcode = OP_OUTARG_VT;
1640 ins->sreg1 = in->dreg;
1641 ins->klass = in->klass;
1642 ins->inst_p0 = call;
1643 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1644 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1645 MONO_ADD_INS (cfg->cbb, ins);
1647 cfg->flags |= MONO_CFG_HAS_FPOUT;
1648 } else {
1649 int dreg = mono_alloc_freg (cfg);
1651 if (ainfo->size == 4) {
1652 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1653 } else {
1654 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1655 ins->dreg = dreg;
1656 ins->sreg1 = in->dreg;
1657 MONO_ADD_INS (cfg->cbb, ins);
1660 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1661 cfg->flags |= MONO_CFG_HAS_FPOUT;
1663 } else {
1664 g_assert_not_reached ();
1668 /* Emit the signature cookie in the case that there is no
1669 additional argument */
1670 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1671 emit_sig_cookie (cfg, call, cinfo);
1673 if (cinfo->struct_ret) {
1674 MonoInst *vtarg;
1676 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1677 vtarg->sreg1 = call->vret_var->dreg;
1678 vtarg->dreg = mono_alloc_preg (cfg);
1679 MONO_ADD_INS (cfg->cbb, vtarg);
1681 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1684 call->stack_usage = cinfo->stack_usage;
1685 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1686 cfg->flags |= MONO_CFG_HAS_CALLS;
1688 g_free (cinfo);
1691 #ifndef DISABLE_JIT
1693 void
1694 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1696 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1697 ArgInfo *ainfo = ins->inst_p1;
1698 int ovf_size = ainfo->vtsize;
1699 int doffset = ainfo->offset;
1700 int i, soffset, dreg;
1702 if (ainfo->regtype == RegTypeStructByVal) {
1703 #ifdef __APPLE__
1704 guint32 size = 0;
1705 #endif
1706 soffset = 0;
1707 #ifdef __APPLE__
1709 * Darwin pinvokes needs some special handling for 1
1710 * and 2 byte arguments
1712 g_assert (ins->klass);
1713 if (call->signature->pinvoke)
1714 size = mono_class_native_size (ins->klass, NULL);
1715 if (size == 2 || size == 1) {
1716 int tmpr = mono_alloc_ireg (cfg);
1717 if (size == 1)
1718 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1719 else
1720 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1721 dreg = mono_alloc_ireg (cfg);
1722 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1723 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1724 } else
1725 #endif
1726 for (i = 0; i < ainfo->vtregs; ++i) {
1727 int antipadding = 0;
1728 if (ainfo->bytes) {
1729 g_assert (i == 0);
1730 antipadding = sizeof (gpointer) - ainfo->bytes;
1732 dreg = mono_alloc_ireg (cfg);
1733 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1734 if (antipadding)
1735 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1736 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1737 soffset += sizeof (gpointer);
1739 if (ovf_size != 0)
1740 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1741 } else if (ainfo->regtype == RegTypeFP) {
1742 int tmpr = mono_alloc_freg (cfg);
1743 if (ainfo->size == 4)
1744 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1745 else
1746 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1747 dreg = mono_alloc_freg (cfg);
1748 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1749 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1750 } else {
1751 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1752 MonoInst *load;
1753 guint32 size;
1755 /* FIXME: alignment? */
1756 if (call->signature->pinvoke) {
1757 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1758 vtcopy->backend.is_pinvoke = 1;
1759 } else {
1760 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1762 if (size > 0)
1763 g_assert (ovf_size > 0);
1765 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1766 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1768 if (ainfo->offset)
1769 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1770 else
1771 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1775 void
1776 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1778 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1779 mono_method_signature (method)->ret);
1781 if (!ret->byref) {
1782 #ifndef __mono_ppc64__
1783 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1784 MonoInst *ins;
1786 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1787 ins->sreg1 = val->dreg + 1;
1788 ins->sreg2 = val->dreg + 2;
1789 MONO_ADD_INS (cfg->cbb, ins);
1790 return;
1792 #endif
1793 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1794 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1795 return;
1798 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1801 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1802 gboolean
1803 mono_arch_is_inst_imm (gint64 imm)
1805 return TRUE;
1808 #endif /* DISABLE_JIT */
1811 * Allow tracing to work with this interface (with an optional argument)
1814 void*
1815 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1817 guchar *code = p;
1819 ppc_load_ptr (code, ppc_r3, cfg->method);
1820 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1821 ppc_load_func (code, ppc_r0, func);
1822 ppc_mtlr (code, ppc_r0);
1823 ppc_blrl (code);
1824 return code;
1827 enum {
1828 SAVE_NONE,
1829 SAVE_STRUCT,
1830 SAVE_ONE,
1831 SAVE_TWO,
1832 SAVE_FP
1835 void*
1836 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1838 guchar *code = p;
1839 int save_mode = SAVE_NONE;
1840 int offset;
1841 MonoMethod *method = cfg->method;
1842 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1843 mono_method_signature (method)->ret)->type;
1844 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1845 save_offset += 15;
1846 save_offset &= ~15;
1848 offset = code - cfg->native_code;
1849 /* we need about 16 instructions */
1850 if (offset > (cfg->code_size - 16 * 4)) {
1851 cfg->code_size *= 2;
1852 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1853 code = cfg->native_code + offset;
1856 switch (rtype) {
1857 case MONO_TYPE_VOID:
1858 /* special case string .ctor icall */
1859 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1860 save_mode = SAVE_ONE;
1861 else
1862 save_mode = SAVE_NONE;
1863 break;
1864 #ifndef __mono_ppc64__
1865 case MONO_TYPE_I8:
1866 case MONO_TYPE_U8:
1867 save_mode = SAVE_TWO;
1868 break;
1869 #endif
1870 case MONO_TYPE_R4:
1871 case MONO_TYPE_R8:
1872 save_mode = SAVE_FP;
1873 break;
1874 case MONO_TYPE_VALUETYPE:
1875 save_mode = SAVE_STRUCT;
1876 break;
1877 default:
1878 save_mode = SAVE_ONE;
1879 break;
1882 switch (save_mode) {
1883 case SAVE_TWO:
1884 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1885 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1886 if (enable_arguments) {
1887 ppc_mr (code, ppc_r5, ppc_r4);
1888 ppc_mr (code, ppc_r4, ppc_r3);
1890 break;
1891 case SAVE_ONE:
1892 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1893 if (enable_arguments) {
1894 ppc_mr (code, ppc_r4, ppc_r3);
1896 break;
1897 case SAVE_FP:
1898 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1899 if (enable_arguments) {
1900 /* FIXME: what reg? */
1901 ppc_fmr (code, ppc_f3, ppc_f1);
1902 /* FIXME: use 8 byte load on PPC64 */
1903 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1904 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1906 break;
1907 case SAVE_STRUCT:
1908 if (enable_arguments) {
1909 /* FIXME: get the actual address */
1910 ppc_mr (code, ppc_r4, ppc_r3);
1912 break;
1913 case SAVE_NONE:
1914 default:
1915 break;
1918 ppc_load_ptr (code, ppc_r3, cfg->method);
1919 ppc_load_func (code, ppc_r0, func);
1920 ppc_mtlr (code, ppc_r0);
1921 ppc_blrl (code);
1923 switch (save_mode) {
1924 case SAVE_TWO:
1925 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1926 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1927 break;
1928 case SAVE_ONE:
1929 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1930 break;
1931 case SAVE_FP:
1932 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1933 break;
1934 case SAVE_NONE:
1935 default:
1936 break;
1939 return code;
1942 * Conditional branches have a small offset, so if it is likely overflowed,
1943 * we do a branch to the end of the method (uncond branches have much larger
1944 * offsets) where we perform the conditional and jump back unconditionally.
1945 * It's slightly slower, since we add two uncond branches, but it's very simple
1946 * with the current patch implementation and such large methods are likely not
1947 * going to be perf critical anyway.
1949 typedef struct {
1950 union {
1951 MonoBasicBlock *bb;
1952 const char *exception;
1953 } data;
1954 guint32 ip_offset;
1955 guint16 b0_cond;
1956 guint16 b1_cond;
1957 } MonoOvfJump;
1959 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1960 if (0 && ins->inst_true_bb->native_offset) { \
1961 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1962 } else { \
1963 int br_disp = ins->inst_true_bb->max_offset - offset; \
1964 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1965 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1966 ovfj->data.bb = ins->inst_true_bb; \
1967 ovfj->ip_offset = 0; \
1968 ovfj->b0_cond = (b0); \
1969 ovfj->b1_cond = (b1); \
1970 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1971 ppc_b (code, 0); \
1972 } else { \
1973 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1974 ppc_bc (code, (b0), (b1), 0); \
1978 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1980 /* emit an exception if condition is fail
1982 * We assign the extra code used to throw the implicit exceptions
1983 * to cfg->bb_exit as far as the big branch handling is concerned
1985 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1986 do { \
1987 int br_disp = cfg->bb_exit->max_offset - offset; \
1988 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1989 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1990 ovfj->data.exception = (exc_name); \
1991 ovfj->ip_offset = code - cfg->native_code; \
1992 ovfj->b0_cond = (b0); \
1993 ovfj->b1_cond = (b1); \
1994 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1995 ppc_bl (code, 0); \
1996 cfg->bb_exit->max_offset += 24; \
1997 } else { \
1998 mono_add_patch_info (cfg, code - cfg->native_code, \
1999 MONO_PATCH_INFO_EXC, exc_name); \
2000 ppc_bcl (code, (b0), (b1), 0); \
2002 } while (0);
2004 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2006 void
2007 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2011 static int
2012 normalize_opcode (int opcode)
2014 switch (opcode) {
2015 #ifndef __mono_ilp32__
2016 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2017 return OP_LOAD_MEMBASE;
2018 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2019 return OP_LOAD_MEMINDEX;
2020 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2021 return OP_STORE_MEMBASE_REG;
2022 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2023 return OP_STORE_MEMBASE_IMM;
2024 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2025 return OP_STORE_MEMINDEX;
2026 #endif
2027 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2028 return OP_SHR_IMM;
2029 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2030 return OP_SHR_UN_IMM;
2031 default:
2032 return opcode;
2036 void
2037 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2039 MonoInst *ins, *n, *last_ins = NULL;
2041 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2042 switch (normalize_opcode (ins->opcode)) {
2043 case OP_MUL_IMM:
2044 /* remove unnecessary multiplication with 1 */
2045 if (ins->inst_imm == 1) {
2046 if (ins->dreg != ins->sreg1) {
2047 ins->opcode = OP_MOVE;
2048 } else {
2049 MONO_DELETE_INS (bb, ins);
2050 continue;
2052 } else {
2053 int power2 = mono_is_power_of_two (ins->inst_imm);
2054 if (power2 > 0) {
2055 ins->opcode = OP_SHL_IMM;
2056 ins->inst_imm = power2;
2059 break;
2060 case OP_LOAD_MEMBASE:
2062 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2063 * OP_LOAD_MEMBASE offset(basereg), reg
2065 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2066 ins->inst_basereg == last_ins->inst_destbasereg &&
2067 ins->inst_offset == last_ins->inst_offset) {
2068 if (ins->dreg == last_ins->sreg1) {
2069 MONO_DELETE_INS (bb, ins);
2070 continue;
2071 } else {
2072 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2073 ins->opcode = OP_MOVE;
2074 ins->sreg1 = last_ins->sreg1;
2078 * Note: reg1 must be different from the basereg in the second load
2079 * OP_LOAD_MEMBASE offset(basereg), reg1
2080 * OP_LOAD_MEMBASE offset(basereg), reg2
2081 * -->
2082 * OP_LOAD_MEMBASE offset(basereg), reg1
2083 * OP_MOVE reg1, reg2
2085 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2086 ins->inst_basereg != last_ins->dreg &&
2087 ins->inst_basereg == last_ins->inst_basereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2090 if (ins->dreg == last_ins->dreg) {
2091 MONO_DELETE_INS (bb, ins);
2092 continue;
2093 } else {
2094 ins->opcode = OP_MOVE;
2095 ins->sreg1 = last_ins->dreg;
2098 //g_assert_not_reached ();
2100 #if 0
2102 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2103 * OP_LOAD_MEMBASE offset(basereg), reg
2104 * -->
2105 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2106 * OP_ICONST reg, imm
2108 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2109 ins->inst_basereg == last_ins->inst_destbasereg &&
2110 ins->inst_offset == last_ins->inst_offset) {
2111 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2112 ins->opcode = OP_ICONST;
2113 ins->inst_c0 = last_ins->inst_imm;
2114 g_assert_not_reached (); // check this rule
2115 #endif
2117 break;
2118 case OP_LOADU1_MEMBASE:
2119 case OP_LOADI1_MEMBASE:
2120 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2121 ins->inst_basereg == last_ins->inst_destbasereg &&
2122 ins->inst_offset == last_ins->inst_offset) {
2123 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2124 ins->sreg1 = last_ins->sreg1;
2126 break;
2127 case OP_LOADU2_MEMBASE:
2128 case OP_LOADI2_MEMBASE:
2129 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2130 ins->inst_basereg == last_ins->inst_destbasereg &&
2131 ins->inst_offset == last_ins->inst_offset) {
2132 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2133 ins->sreg1 = last_ins->sreg1;
2135 break;
2136 #ifdef __mono_ppc64__
2137 case OP_LOADU4_MEMBASE:
2138 case OP_LOADI4_MEMBASE:
2139 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2140 ins->inst_basereg == last_ins->inst_destbasereg &&
2141 ins->inst_offset == last_ins->inst_offset) {
2142 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2143 ins->sreg1 = last_ins->sreg1;
2145 break;
2146 #endif
2147 case OP_MOVE:
2148 ins->opcode = OP_MOVE;
2150 * OP_MOVE reg, reg
2152 if (ins->dreg == ins->sreg1) {
2153 MONO_DELETE_INS (bb, ins);
2154 continue;
2157 * OP_MOVE sreg, dreg
2158 * OP_MOVE dreg, sreg
2160 if (last_ins && last_ins->opcode == OP_MOVE &&
2161 ins->sreg1 == last_ins->dreg &&
2162 ins->dreg == last_ins->sreg1) {
2163 MONO_DELETE_INS (bb, ins);
2164 continue;
2166 break;
2168 last_ins = ins;
2169 ins = ins->next;
2171 bb->last_ins = last_ins;
2174 void
2175 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2177 switch (ins->opcode) {
2178 case OP_ICONV_TO_R_UN: {
2179 #if G_BYTE_ORDER == G_BIG_ENDIAN
2180 static const guint64 adjust_val = 0x4330000000000000ULL;
2181 #else
2182 static const guint64 adjust_val = 0x0000000000003043ULL;
2183 #endif
2184 int msw_reg = mono_alloc_ireg (cfg);
2185 int adj_reg = mono_alloc_freg (cfg);
2186 int tmp_reg = mono_alloc_freg (cfg);
2187 int basereg = ppc_sp;
2188 int offset = -8;
2189 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2190 if (!ppc_is_imm16 (offset + 4)) {
2191 basereg = mono_alloc_ireg (cfg);
2192 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2194 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2195 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2196 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2197 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2198 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2199 ins->opcode = OP_NOP;
2200 break;
2202 #ifndef __mono_ppc64__
2203 case OP_ICONV_TO_R4:
2204 case OP_ICONV_TO_R8: {
2205 /* If we have a PPC_FEATURE_64 machine we can avoid
2206 this and use the fcfid instruction. Otherwise
2207 on an old 32-bit chip and we have to do this the
2208 hard way. */
2209 if (!(cpu_hw_caps & PPC_ISA_64)) {
2210 /* FIXME: change precision for CEE_CONV_R4 */
2211 static const guint64 adjust_val = 0x4330000080000000ULL;
2212 int msw_reg = mono_alloc_ireg (cfg);
2213 int xored = mono_alloc_ireg (cfg);
2214 int adj_reg = mono_alloc_freg (cfg);
2215 int tmp_reg = mono_alloc_freg (cfg);
2216 int basereg = ppc_sp;
2217 int offset = -8;
2218 if (!ppc_is_imm16 (offset + 4)) {
2219 basereg = mono_alloc_ireg (cfg);
2220 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2222 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2223 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2224 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2225 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2226 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2227 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2228 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2229 if (ins->opcode == OP_ICONV_TO_R4)
2230 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2231 ins->opcode = OP_NOP;
2233 break;
2235 #endif
2236 case OP_CKFINITE: {
2237 int msw_reg = mono_alloc_ireg (cfg);
2238 int basereg = ppc_sp;
2239 int offset = -8;
2240 if (!ppc_is_imm16 (offset + 4)) {
2241 basereg = mono_alloc_ireg (cfg);
2242 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2244 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2245 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2246 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2247 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2248 ins->opcode = OP_NOP;
2249 break;
2251 #ifdef __mono_ppc64__
2252 case OP_IADD_OVF:
2253 case OP_IADD_OVF_UN:
2254 case OP_ISUB_OVF: {
2255 int shifted1_reg = mono_alloc_ireg (cfg);
2256 int shifted2_reg = mono_alloc_ireg (cfg);
2257 int result_shifted_reg = mono_alloc_ireg (cfg);
2259 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2260 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2261 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2262 if (ins->opcode == OP_IADD_OVF_UN)
2263 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2264 else
2265 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2266 ins->opcode = OP_NOP;
2268 #endif
2272 void
2273 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2275 switch (ins->opcode) {
2276 case OP_LADD_OVF:
2277 /* ADC sets the condition code */
2278 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2279 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2280 NULLIFY_INS (ins);
2281 break;
2282 case OP_LADD_OVF_UN:
2283 /* ADC sets the condition code */
2284 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2285 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2286 NULLIFY_INS (ins);
2287 break;
2288 case OP_LSUB_OVF:
2289 /* SBB sets the condition code */
2290 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2291 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2292 NULLIFY_INS (ins);
2293 break;
2294 case OP_LSUB_OVF_UN:
2295 /* SBB sets the condition code */
2296 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2297 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2298 NULLIFY_INS (ins);
2299 break;
2300 case OP_LNEG:
2301 /* From gcc generated code */
2302 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2303 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2304 NULLIFY_INS (ins);
2305 break;
2306 default:
2307 break;
2312 * the branch_b0_table should maintain the order of these
2313 * opcodes.
2314 case CEE_BEQ:
2315 case CEE_BGE:
2316 case CEE_BGT:
2317 case CEE_BLE:
2318 case CEE_BLT:
2319 case CEE_BNE_UN:
2320 case CEE_BGE_UN:
2321 case CEE_BGT_UN:
2322 case CEE_BLE_UN:
2323 case CEE_BLT_UN:
2325 static const guchar
2326 branch_b0_table [] = {
2327 PPC_BR_TRUE,
2328 PPC_BR_FALSE,
2329 PPC_BR_TRUE,
2330 PPC_BR_FALSE,
2331 PPC_BR_TRUE,
2333 PPC_BR_FALSE,
2334 PPC_BR_FALSE,
2335 PPC_BR_TRUE,
2336 PPC_BR_FALSE,
2337 PPC_BR_TRUE
2340 static const guchar
2341 branch_b1_table [] = {
2342 PPC_BR_EQ,
2343 PPC_BR_LT,
2344 PPC_BR_GT,
2345 PPC_BR_GT,
2346 PPC_BR_LT,
2348 PPC_BR_EQ,
2349 PPC_BR_LT,
2350 PPC_BR_GT,
2351 PPC_BR_GT,
2352 PPC_BR_LT
2355 #define NEW_INS(cfg,dest,op) do { \
2356 MONO_INST_NEW((cfg), (dest), (op)); \
2357 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2358 } while (0)
2360 static int
2361 map_to_reg_reg_op (int op)
2363 switch (op) {
2364 case OP_ADD_IMM:
2365 return OP_IADD;
2366 case OP_SUB_IMM:
2367 return OP_ISUB;
2368 case OP_AND_IMM:
2369 return OP_IAND;
2370 case OP_COMPARE_IMM:
2371 return OP_COMPARE;
2372 case OP_ICOMPARE_IMM:
2373 return OP_ICOMPARE;
2374 case OP_LCOMPARE_IMM:
2375 return OP_LCOMPARE;
2376 case OP_ADDCC_IMM:
2377 return OP_IADDCC;
2378 case OP_ADC_IMM:
2379 return OP_IADC;
2380 case OP_SUBCC_IMM:
2381 return OP_ISUBCC;
2382 case OP_SBB_IMM:
2383 return OP_ISBB;
2384 case OP_OR_IMM:
2385 return OP_IOR;
2386 case OP_XOR_IMM:
2387 return OP_IXOR;
2388 case OP_MUL_IMM:
2389 return OP_IMUL;
2390 case OP_LOAD_MEMBASE:
2391 return OP_LOAD_MEMINDEX;
2392 case OP_LOADI4_MEMBASE:
2393 return OP_LOADI4_MEMINDEX;
2394 case OP_LOADU4_MEMBASE:
2395 return OP_LOADU4_MEMINDEX;
2396 case OP_LOADI8_MEMBASE:
2397 return OP_LOADI8_MEMINDEX;
2398 case OP_LOADU1_MEMBASE:
2399 return OP_LOADU1_MEMINDEX;
2400 case OP_LOADI2_MEMBASE:
2401 return OP_LOADI2_MEMINDEX;
2402 case OP_LOADU2_MEMBASE:
2403 return OP_LOADU2_MEMINDEX;
2404 case OP_LOADI1_MEMBASE:
2405 return OP_LOADI1_MEMINDEX;
2406 case OP_LOADR4_MEMBASE:
2407 return OP_LOADR4_MEMINDEX;
2408 case OP_LOADR8_MEMBASE:
2409 return OP_LOADR8_MEMINDEX;
2410 case OP_STOREI1_MEMBASE_REG:
2411 return OP_STOREI1_MEMINDEX;
2412 case OP_STOREI2_MEMBASE_REG:
2413 return OP_STOREI2_MEMINDEX;
2414 case OP_STOREI4_MEMBASE_REG:
2415 return OP_STOREI4_MEMINDEX;
2416 case OP_STOREI8_MEMBASE_REG:
2417 return OP_STOREI8_MEMINDEX;
2418 case OP_STORE_MEMBASE_REG:
2419 return OP_STORE_MEMINDEX;
2420 case OP_STORER4_MEMBASE_REG:
2421 return OP_STORER4_MEMINDEX;
2422 case OP_STORER8_MEMBASE_REG:
2423 return OP_STORER8_MEMINDEX;
2424 case OP_STORE_MEMBASE_IMM:
2425 return OP_STORE_MEMBASE_REG;
2426 case OP_STOREI1_MEMBASE_IMM:
2427 return OP_STOREI1_MEMBASE_REG;
2428 case OP_STOREI2_MEMBASE_IMM:
2429 return OP_STOREI2_MEMBASE_REG;
2430 case OP_STOREI4_MEMBASE_IMM:
2431 return OP_STOREI4_MEMBASE_REG;
2432 case OP_STOREI8_MEMBASE_IMM:
2433 return OP_STOREI8_MEMBASE_REG;
2435 return mono_op_imm_to_op (op);
2438 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2440 #define compare_opcode_is_unsigned(opcode) \
2441 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2442 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2443 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2444 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2445 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2446 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2447 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2448 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2451 * Remove from the instruction list the instructions that can't be
2452 * represented with very simple instructions with no register
2453 * requirements.
2455 void
2456 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2458 MonoInst *ins, *next, *temp, *last_ins = NULL;
2459 int imm;
2461 MONO_BB_FOR_EACH_INS (bb, ins) {
2462 loop_start:
2463 switch (ins->opcode) {
2464 case OP_IDIV_UN_IMM:
2465 case OP_IDIV_IMM:
2466 case OP_IREM_IMM:
2467 case OP_IREM_UN_IMM:
2468 NEW_INS (cfg, temp, OP_ICONST);
2469 temp->inst_c0 = ins->inst_imm;
2470 temp->dreg = mono_alloc_ireg (cfg);
2471 ins->sreg2 = temp->dreg;
2472 if (ins->opcode == OP_IDIV_IMM)
2473 ins->opcode = OP_IDIV;
2474 else if (ins->opcode == OP_IREM_IMM)
2475 ins->opcode = OP_IREM;
2476 else if (ins->opcode == OP_IDIV_UN_IMM)
2477 ins->opcode = OP_IDIV_UN;
2478 else if (ins->opcode == OP_IREM_UN_IMM)
2479 ins->opcode = OP_IREM_UN;
2480 last_ins = temp;
2481 /* handle rem separately */
2482 goto loop_start;
2483 case OP_IREM:
2484 case OP_IREM_UN:
2485 CASE_PPC64 (OP_LREM)
2486 CASE_PPC64 (OP_LREM_UN) {
2487 MonoInst *mul;
2488 /* we change a rem dest, src1, src2 to
2489 * div temp1, src1, src2
2490 * mul temp2, temp1, src2
2491 * sub dest, src1, temp2
2493 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2494 NEW_INS (cfg, mul, OP_IMUL);
2495 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2496 ins->opcode = OP_ISUB;
2497 } else {
2498 NEW_INS (cfg, mul, OP_LMUL);
2499 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2500 ins->opcode = OP_LSUB;
2502 temp->sreg1 = ins->sreg1;
2503 temp->sreg2 = ins->sreg2;
2504 temp->dreg = mono_alloc_ireg (cfg);
2505 mul->sreg1 = temp->dreg;
2506 mul->sreg2 = ins->sreg2;
2507 mul->dreg = mono_alloc_ireg (cfg);
2508 ins->sreg2 = mul->dreg;
2509 break;
2511 case OP_IADD_IMM:
2512 CASE_PPC64 (OP_LADD_IMM)
2513 case OP_ADD_IMM:
2514 case OP_ADDCC_IMM:
2515 if (!ppc_is_imm16 (ins->inst_imm)) {
2516 NEW_INS (cfg, temp, OP_ICONST);
2517 temp->inst_c0 = ins->inst_imm;
2518 temp->dreg = mono_alloc_ireg (cfg);
2519 ins->sreg2 = temp->dreg;
2520 ins->opcode = map_to_reg_reg_op (ins->opcode);
2522 break;
2523 case OP_ISUB_IMM:
2524 CASE_PPC64 (OP_LSUB_IMM)
2525 case OP_SUB_IMM:
2526 if (!ppc_is_imm16 (-ins->inst_imm)) {
2527 NEW_INS (cfg, temp, OP_ICONST);
2528 temp->inst_c0 = ins->inst_imm;
2529 temp->dreg = mono_alloc_ireg (cfg);
2530 ins->sreg2 = temp->dreg;
2531 ins->opcode = map_to_reg_reg_op (ins->opcode);
2533 break;
2534 case OP_IAND_IMM:
2535 case OP_IOR_IMM:
2536 case OP_IXOR_IMM:
2537 case OP_LAND_IMM:
2538 case OP_LOR_IMM:
2539 case OP_LXOR_IMM:
2540 case OP_AND_IMM:
2541 case OP_OR_IMM:
2542 case OP_XOR_IMM: {
2543 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2544 #ifdef __mono_ppc64__
2545 if (ins->inst_imm & 0xffffffff00000000ULL)
2546 is_imm = TRUE;
2547 #endif
2548 if (is_imm) {
2549 NEW_INS (cfg, temp, OP_ICONST);
2550 temp->inst_c0 = ins->inst_imm;
2551 temp->dreg = mono_alloc_ireg (cfg);
2552 ins->sreg2 = temp->dreg;
2553 ins->opcode = map_to_reg_reg_op (ins->opcode);
2555 break;
2557 case OP_ISBB_IMM:
2558 case OP_IADC_IMM:
2559 case OP_SBB_IMM:
2560 case OP_SUBCC_IMM:
2561 case OP_ADC_IMM:
2562 NEW_INS (cfg, temp, OP_ICONST);
2563 temp->inst_c0 = ins->inst_imm;
2564 temp->dreg = mono_alloc_ireg (cfg);
2565 ins->sreg2 = temp->dreg;
2566 ins->opcode = map_to_reg_reg_op (ins->opcode);
2567 break;
2568 case OP_COMPARE_IMM:
2569 case OP_ICOMPARE_IMM:
2570 CASE_PPC64 (OP_LCOMPARE_IMM)
2571 next = ins->next;
2572 /* Branch opts can eliminate the branch */
2573 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2574 ins->opcode = OP_NOP;
2575 break;
2577 g_assert(next);
2578 if (compare_opcode_is_unsigned (next->opcode)) {
2579 if (!ppc_is_uimm16 (ins->inst_imm)) {
2580 NEW_INS (cfg, temp, OP_ICONST);
2581 temp->inst_c0 = ins->inst_imm;
2582 temp->dreg = mono_alloc_ireg (cfg);
2583 ins->sreg2 = temp->dreg;
2584 ins->opcode = map_to_reg_reg_op (ins->opcode);
2586 } else {
2587 if (!ppc_is_imm16 (ins->inst_imm)) {
2588 NEW_INS (cfg, temp, OP_ICONST);
2589 temp->inst_c0 = ins->inst_imm;
2590 temp->dreg = mono_alloc_ireg (cfg);
2591 ins->sreg2 = temp->dreg;
2592 ins->opcode = map_to_reg_reg_op (ins->opcode);
2595 break;
2596 case OP_IMUL_IMM:
2597 case OP_MUL_IMM:
2598 if (ins->inst_imm == 1) {
2599 ins->opcode = OP_MOVE;
2600 break;
2602 if (ins->inst_imm == 0) {
2603 ins->opcode = OP_ICONST;
2604 ins->inst_c0 = 0;
2605 break;
2607 imm = mono_is_power_of_two (ins->inst_imm);
2608 if (imm > 0) {
2609 ins->opcode = OP_SHL_IMM;
2610 ins->inst_imm = imm;
2611 break;
2613 if (!ppc_is_imm16 (ins->inst_imm)) {
2614 NEW_INS (cfg, temp, OP_ICONST);
2615 temp->inst_c0 = ins->inst_imm;
2616 temp->dreg = mono_alloc_ireg (cfg);
2617 ins->sreg2 = temp->dreg;
2618 ins->opcode = map_to_reg_reg_op (ins->opcode);
2620 break;
2621 case OP_LOCALLOC_IMM:
2622 NEW_INS (cfg, temp, OP_ICONST);
2623 temp->inst_c0 = ins->inst_imm;
2624 temp->dreg = mono_alloc_ireg (cfg);
2625 ins->sreg1 = temp->dreg;
2626 ins->opcode = OP_LOCALLOC;
2627 break;
2628 case OP_LOAD_MEMBASE:
2629 case OP_LOADI4_MEMBASE:
2630 CASE_PPC64 (OP_LOADI8_MEMBASE)
2631 case OP_LOADU4_MEMBASE:
2632 case OP_LOADI2_MEMBASE:
2633 case OP_LOADU2_MEMBASE:
2634 case OP_LOADI1_MEMBASE:
2635 case OP_LOADU1_MEMBASE:
2636 case OP_LOADR4_MEMBASE:
2637 case OP_LOADR8_MEMBASE:
2638 case OP_STORE_MEMBASE_REG:
2639 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2640 case OP_STOREI4_MEMBASE_REG:
2641 case OP_STOREI2_MEMBASE_REG:
2642 case OP_STOREI1_MEMBASE_REG:
2643 case OP_STORER4_MEMBASE_REG:
2644 case OP_STORER8_MEMBASE_REG:
2645 /* we can do two things: load the immed in a register
2646 * and use an indexed load, or see if the immed can be
2647 * represented as an ad_imm + a load with a smaller offset
2648 * that fits. We just do the first for now, optimize later.
2650 if (ppc_is_imm16 (ins->inst_offset))
2651 break;
2652 NEW_INS (cfg, temp, OP_ICONST);
2653 temp->inst_c0 = ins->inst_offset;
2654 temp->dreg = mono_alloc_ireg (cfg);
2655 ins->sreg2 = temp->dreg;
2656 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 break;
2658 case OP_STORE_MEMBASE_IMM:
2659 case OP_STOREI1_MEMBASE_IMM:
2660 case OP_STOREI2_MEMBASE_IMM:
2661 case OP_STOREI4_MEMBASE_IMM:
2662 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2663 NEW_INS (cfg, temp, OP_ICONST);
2664 temp->inst_c0 = ins->inst_imm;
2665 temp->dreg = mono_alloc_ireg (cfg);
2666 ins->sreg1 = temp->dreg;
2667 ins->opcode = map_to_reg_reg_op (ins->opcode);
2668 last_ins = temp;
2669 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2670 case OP_R8CONST:
2671 case OP_R4CONST:
2672 if (cfg->compile_aot) {
2673 /* Keep these in the aot case */
2674 break;
2676 NEW_INS (cfg, temp, OP_ICONST);
2677 temp->inst_c0 = (gulong)ins->inst_p0;
2678 temp->dreg = mono_alloc_ireg (cfg);
2679 ins->inst_basereg = temp->dreg;
2680 ins->inst_offset = 0;
2681 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2682 last_ins = temp;
2683 /* make it handle the possibly big ins->inst_offset
2684 * later optimize to use lis + load_membase
2686 goto loop_start;
2688 last_ins = ins;
2690 bb->last_ins = last_ins;
2691 bb->max_vreg = cfg->next_vreg;
2694 static guchar*
2695 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2697 long offset = cfg->arch.fp_conv_var_offset;
2698 long sub_offset;
2699 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2700 #ifdef __mono_ppc64__
2701 if (size == 8) {
2702 ppc_fctidz (code, ppc_f0, sreg);
2703 sub_offset = 0;
2704 } else
2705 #endif
2707 ppc_fctiwz (code, ppc_f0, sreg);
2708 sub_offset = 4;
2710 if (ppc_is_imm16 (offset + sub_offset)) {
2711 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2712 if (size == 8)
2713 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2714 else
2715 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2716 } else {
2717 ppc_load (code, dreg, offset);
2718 ppc_add (code, dreg, dreg, cfg->frame_reg);
2719 ppc_stfd (code, ppc_f0, 0, dreg);
2720 if (size == 8)
2721 ppc_ldr (code, dreg, sub_offset, dreg);
2722 else
2723 ppc_lwz (code, dreg, sub_offset, dreg);
2725 if (!is_signed) {
2726 if (size == 1)
2727 ppc_andid (code, dreg, dreg, 0xff);
2728 else if (size == 2)
2729 ppc_andid (code, dreg, dreg, 0xffff);
2730 #ifdef __mono_ppc64__
2731 else if (size == 4)
2732 ppc_clrldi (code, dreg, dreg, 32);
2733 #endif
2734 } else {
2735 if (size == 1)
2736 ppc_extsb (code, dreg, dreg);
2737 else if (size == 2)
2738 ppc_extsh (code, dreg, dreg);
2739 #ifdef __mono_ppc64__
2740 else if (size == 4)
2741 ppc_extsw (code, dreg, dreg);
2742 #endif
2744 return code;
2747 typedef struct {
2748 guchar *code;
2749 const guchar *target;
2750 int absolute;
2751 int found;
2752 } PatchData;
2754 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2756 static int
2757 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2758 #ifdef __mono_ppc64__
2759 g_assert_not_reached ();
2760 #else
2761 PatchData *pdata = (PatchData*)user_data;
2762 guchar *code = data;
2763 guint32 *thunks = data;
2764 guint32 *endthunks = (guint32*)(code + bsize);
2765 guint32 load [2];
2766 guchar *templ;
2767 int count = 0;
2768 int difflow, diffhigh;
2770 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2771 difflow = (char*)pdata->code - (char*)thunks;
2772 diffhigh = (char*)pdata->code - (char*)endthunks;
2773 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2774 return 0;
2776 templ = (guchar*)load;
2777 ppc_load_sequence (templ, ppc_r0, pdata->target);
2779 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2780 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2781 while (thunks < endthunks) {
2782 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2783 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2784 ppc_patch (pdata->code, (guchar*)thunks);
2785 pdata->found = 1;
2787 static int num_thunks = 0;
2788 num_thunks++;
2789 if ((num_thunks % 20) == 0)
2790 g_print ("num_thunks lookup: %d\n", num_thunks);
2792 return 1;
2793 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2794 /* found a free slot instead: emit thunk */
2795 code = (guchar*)thunks;
2796 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2797 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2798 ppc_mtctr (code, ppc_r0);
2799 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2800 mono_arch_flush_icache ((guchar*)thunks, 16);
2802 ppc_patch (pdata->code, (guchar*)thunks);
2803 pdata->found = 1;
2805 static int num_thunks = 0;
2806 num_thunks++;
2807 if ((num_thunks % 20) == 0)
2808 g_print ("num_thunks: %d\n", num_thunks);
2810 return 1;
2812 /* skip 16 bytes, the size of the thunk */
2813 thunks += 4;
2814 count++;
2816 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2818 #endif
2819 return 0;
2822 static void
2823 handle_thunk (int absolute, guchar *code, const guchar *target) {
2824 MonoDomain *domain = mono_domain_get ();
2825 PatchData pdata;
2827 pdata.code = code;
2828 pdata.target = target;
2829 pdata.absolute = absolute;
2830 pdata.found = 0;
2832 mono_domain_lock (domain);
2833 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2835 if (!pdata.found) {
2836 /* this uses the first available slot */
2837 pdata.found = 2;
2838 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2840 mono_domain_unlock (domain);
2842 if (pdata.found != 1)
2843 g_print ("thunk failed for %p from %p\n", target, code);
2844 g_assert (pdata.found == 1);
2847 static void
2848 patch_ins (guint8 *code, guint32 ins)
2850 *(guint32*)code = GUINT32_TO_BE (ins);
2851 mono_arch_flush_icache (code, 4);
2854 void
2855 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2857 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2858 guint32 prim = ins >> 26;
2859 guint32 ovf;
2861 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2862 if (prim == 18) {
2863 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2864 gint diff = target - code;
2865 g_assert (!is_fd);
2866 if (diff >= 0){
2867 if (diff <= 33554431){
2868 ins = (18 << 26) | (diff) | (ins & 1);
2869 patch_ins (code, ins);
2870 return;
2872 } else {
2873 /* diff between 0 and -33554432 */
2874 if (diff >= -33554432){
2875 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2876 patch_ins (code, ins);
2877 return;
2881 if ((glong)target >= 0){
2882 if ((glong)target <= 33554431){
2883 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2884 patch_ins (code, ins);
2885 return;
2887 } else {
2888 if ((glong)target >= -33554432){
2889 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2890 patch_ins (code, ins);
2891 return;
2895 handle_thunk (TRUE, code, target);
2896 return;
2898 g_assert_not_reached ();
2902 if (prim == 16) {
2903 g_assert (!is_fd);
2904 // absolute address
2905 if (ins & 2) {
2906 guint32 li = (gulong)target;
2907 ins = (ins & 0xffff0000) | (ins & 3);
2908 ovf = li & 0xffff0000;
2909 if (ovf != 0 && ovf != 0xffff0000)
2910 g_assert_not_reached ();
2911 li &= 0xffff;
2912 ins |= li;
2913 // FIXME: assert the top bits of li are 0
2914 } else {
2915 gint diff = target - code;
2916 ins = (ins & 0xffff0000) | (ins & 3);
2917 ovf = diff & 0xffff0000;
2918 if (ovf != 0 && ovf != 0xffff0000)
2919 g_assert_not_reached ();
2920 diff &= 0xffff;
2921 ins |= diff;
2923 patch_ins (code, ins);
2924 return;
2927 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2928 #ifdef __mono_ppc64__
2929 guint32 *seq = (guint32*)code;
2930 guint32 *branch_ins;
2932 /* the trampoline code will try to patch the blrl, blr, bcctr */
2933 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2934 branch_ins = seq;
2935 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2936 code -= 32;
2937 else
2938 code -= 24;
2939 } else {
2940 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2941 branch_ins = seq + 8;
2942 else
2943 branch_ins = seq + 6;
2946 seq = (guint32*)code;
2947 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2948 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2950 if (ppc_is_load_op (seq [5])) {
2951 g_assert (ppc_is_load_op (seq [6]));
2953 if (!is_fd) {
2954 guint8 *buf = (guint8*)&seq [5];
2955 ppc_mr (buf, ppc_r0, ppc_r11);
2956 ppc_nop (buf);
2958 } else {
2959 if (is_fd)
2960 target = mono_get_addr_from_ftnptr ((gpointer)target);
2963 /* FIXME: make this thread safe */
2964 /* FIXME: we're assuming we're using r11 here */
2965 ppc_load_ptr_sequence (code, ppc_r11, target);
2966 mono_arch_flush_icache ((guint8*)seq, 28);
2967 #else
2968 guint32 *seq;
2969 /* the trampoline code will try to patch the blrl, blr, bcctr */
2970 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2971 code -= 12;
2973 /* this is the lis/ori/mtlr/blrl sequence */
2974 seq = (guint32*)code;
2975 g_assert ((seq [0] >> 26) == 15);
2976 g_assert ((seq [1] >> 26) == 24);
2977 g_assert ((seq [2] >> 26) == 31);
2978 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2979 /* FIXME: make this thread safe */
2980 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2981 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2982 mono_arch_flush_icache (code - 8, 8);
2983 #endif
2984 } else {
2985 g_assert_not_reached ();
2987 // g_print ("patched with 0x%08x\n", ins);
2990 void
2991 ppc_patch (guchar *code, const guchar *target)
2993 ppc_patch_full (code, target, FALSE);
2996 void
2997 mono_ppc_patch (guchar *code, const guchar *target)
2999 ppc_patch (code, target);
3002 static guint8*
3003 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3005 switch (ins->opcode) {
3006 case OP_FCALL:
3007 case OP_FCALL_REG:
3008 case OP_FCALL_MEMBASE:
3009 if (ins->dreg != ppc_f1)
3010 ppc_fmr (code, ins->dreg, ppc_f1);
3011 break;
3014 return code;
3017 static int
3018 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3020 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3023 static guint8*
3024 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3026 long size = cfg->param_area;
3028 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3029 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3031 if (!size)
3032 return code;
3034 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3035 if (ppc_is_imm16 (-size)) {
3036 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3037 } else {
3038 ppc_load (code, ppc_r11, -size);
3039 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3042 return code;
3045 static guint8*
3046 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3048 long size = cfg->param_area;
3050 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3051 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3053 if (!size)
3054 return code;
3056 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3057 if (ppc_is_imm16 (size)) {
3058 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3059 } else {
3060 ppc_load (code, ppc_r11, size);
3061 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3064 return code;
3067 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3069 #ifndef DISABLE_JIT
3070 void
3071 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3073 MonoInst *ins, *next;
3074 MonoCallInst *call;
3075 guint offset;
3076 guint8 *code = cfg->native_code + cfg->code_len;
3077 MonoInst *last_ins = NULL;
3078 guint last_offset = 0;
3079 int max_len, cpos;
3080 int L;
3082 /* we don't align basic blocks of loops on ppc */
3084 if (cfg->verbose_level > 2)
3085 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3087 cpos = bb->max_offset;
3089 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3090 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3091 //g_assert (!mono_compile_aot);
3092 //cpos += 6;
3093 //if (bb->cil_code)
3094 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3095 /* this is not thread save, but good enough */
3096 /* fixme: howto handle overflows? */
3097 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3100 MONO_BB_FOR_EACH_INS (bb, ins) {
3101 offset = code - cfg->native_code;
3103 max_len = ins_native_length (cfg, ins);
3105 if (offset > (cfg->code_size - max_len - 16)) {
3106 cfg->code_size *= 2;
3107 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3108 code = cfg->native_code + offset;
3110 // if (ins->cil_code)
3111 // g_print ("cil code\n");
3112 mono_debug_record_line_number (cfg, ins, offset);
3114 switch (normalize_opcode (ins->opcode)) {
3115 case OP_RELAXED_NOP:
3116 case OP_NOP:
3117 case OP_DUMMY_USE:
3118 case OP_DUMMY_STORE:
3119 case OP_NOT_REACHED:
3120 case OP_NOT_NULL:
3121 break;
3122 case OP_SEQ_POINT: {
3123 int i;
3125 if (cfg->compile_aot)
3126 NOT_IMPLEMENTED;
3129 * Read from the single stepping trigger page. This will cause a
3130 * SIGSEGV when single stepping is enabled.
3131 * We do this _before_ the breakpoint, so single stepping after
3132 * a breakpoint is hit will step to the next IL offset.
3134 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3135 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3136 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3139 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3142 * A placeholder for a possible breakpoint inserted by
3143 * mono_arch_set_breakpoint ().
3145 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3146 ppc_nop (code);
3147 break;
3149 case OP_TLS_GET:
3150 emit_tls_access (code, ins->dreg, ins->inst_offset);
3151 break;
3152 case OP_BIGMUL:
3153 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3154 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3155 ppc_mr (code, ppc_r4, ppc_r0);
3156 break;
3157 case OP_BIGMUL_UN:
3158 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3159 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3160 ppc_mr (code, ppc_r4, ppc_r0);
3161 break;
3162 case OP_MEMORY_BARRIER:
3163 ppc_sync (code);
3164 break;
3165 case OP_STOREI1_MEMBASE_REG:
3166 if (ppc_is_imm16 (ins->inst_offset)) {
3167 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3168 } else {
3169 if (ppc_is_imm32 (ins->inst_offset)) {
3170 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3171 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3172 } else {
3173 ppc_load (code, ppc_r0, ins->inst_offset);
3174 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3177 break;
3178 case OP_STOREI2_MEMBASE_REG:
3179 if (ppc_is_imm16 (ins->inst_offset)) {
3180 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3181 } else {
3182 if (ppc_is_imm32 (ins->inst_offset)) {
3183 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3184 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3185 } else {
3186 ppc_load (code, ppc_r0, ins->inst_offset);
3187 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3190 break;
3191 case OP_STORE_MEMBASE_REG:
3192 if (ppc_is_imm16 (ins->inst_offset)) {
3193 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3194 } else {
3195 if (ppc_is_imm32 (ins->inst_offset)) {
3196 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3197 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3198 } else {
3199 ppc_load (code, ppc_r0, ins->inst_offset);
3200 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3203 break;
3204 #ifdef __mono_ilp32__
3205 case OP_STOREI8_MEMBASE_REG:
3206 if (ppc_is_imm16 (ins->inst_offset)) {
3207 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3208 } else {
3209 ppc_load (code, ppc_r0, ins->inst_offset);
3210 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3212 break;
3213 #endif
3214 case OP_STOREI1_MEMINDEX:
3215 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3216 break;
3217 case OP_STOREI2_MEMINDEX:
3218 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3219 break;
3220 case OP_STORE_MEMINDEX:
3221 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3222 break;
3223 case OP_LOADU4_MEM:
3224 g_assert_not_reached ();
3225 break;
3226 case OP_LOAD_MEMBASE:
3227 if (ppc_is_imm16 (ins->inst_offset)) {
3228 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3229 } else {
3230 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3231 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3232 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3233 } else {
3234 ppc_load (code, ppc_r0, ins->inst_offset);
3235 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3238 break;
3239 case OP_LOADI4_MEMBASE:
3240 #ifdef __mono_ppc64__
3241 if (ppc_is_imm16 (ins->inst_offset)) {
3242 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3243 } else {
3244 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3245 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3246 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3247 } else {
3248 ppc_load (code, ppc_r0, ins->inst_offset);
3249 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3252 break;
3253 #endif
3254 case OP_LOADU4_MEMBASE:
3255 if (ppc_is_imm16 (ins->inst_offset)) {
3256 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3257 } else {
3258 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3259 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3260 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3261 } else {
3262 ppc_load (code, ppc_r0, ins->inst_offset);
3263 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3266 break;
3267 case OP_LOADI1_MEMBASE:
3268 case OP_LOADU1_MEMBASE:
3269 if (ppc_is_imm16 (ins->inst_offset)) {
3270 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3271 } else {
3272 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3273 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3274 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3275 } else {
3276 ppc_load (code, ppc_r0, ins->inst_offset);
3277 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3280 if (ins->opcode == OP_LOADI1_MEMBASE)
3281 ppc_extsb (code, ins->dreg, ins->dreg);
3282 break;
3283 case OP_LOADU2_MEMBASE:
3284 if (ppc_is_imm16 (ins->inst_offset)) {
3285 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3286 } else {
3287 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3288 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3289 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3290 } else {
3291 ppc_load (code, ppc_r0, ins->inst_offset);
3292 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3295 break;
3296 case OP_LOADI2_MEMBASE:
3297 if (ppc_is_imm16 (ins->inst_offset)) {
3298 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3299 } else {
3300 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3301 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3302 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3303 } else {
3304 ppc_load (code, ppc_r0, ins->inst_offset);
3305 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3308 break;
3309 #ifdef __mono_ilp32__
3310 case OP_LOADI8_MEMBASE:
3311 if (ppc_is_imm16 (ins->inst_offset)) {
3312 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3313 } else {
3314 ppc_load (code, ppc_r0, ins->inst_offset);
3315 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3317 break;
3318 #endif
3319 case OP_LOAD_MEMINDEX:
3320 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3321 break;
3322 case OP_LOADI4_MEMINDEX:
3323 #ifdef __mono_ppc64__
3324 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3325 break;
3326 #endif
3327 case OP_LOADU4_MEMINDEX:
3328 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3329 break;
3330 case OP_LOADU2_MEMINDEX:
3331 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3332 break;
3333 case OP_LOADI2_MEMINDEX:
3334 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3335 break;
3336 case OP_LOADU1_MEMINDEX:
3337 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3338 break;
3339 case OP_LOADI1_MEMINDEX:
3340 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3341 ppc_extsb (code, ins->dreg, ins->dreg);
3342 break;
3343 case OP_ICONV_TO_I1:
3344 CASE_PPC64 (OP_LCONV_TO_I1)
3345 ppc_extsb (code, ins->dreg, ins->sreg1);
3346 break;
3347 case OP_ICONV_TO_I2:
3348 CASE_PPC64 (OP_LCONV_TO_I2)
3349 ppc_extsh (code, ins->dreg, ins->sreg1);
3350 break;
3351 case OP_ICONV_TO_U1:
3352 CASE_PPC64 (OP_LCONV_TO_U1)
3353 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3354 break;
3355 case OP_ICONV_TO_U2:
3356 CASE_PPC64 (OP_LCONV_TO_U2)
3357 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3358 break;
3359 case OP_COMPARE:
3360 case OP_ICOMPARE:
3361 CASE_PPC64 (OP_LCOMPARE)
3362 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3363 next = ins->next;
3364 if (next && compare_opcode_is_unsigned (next->opcode))
3365 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3366 else
3367 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3368 break;
3369 case OP_COMPARE_IMM:
3370 case OP_ICOMPARE_IMM:
3371 CASE_PPC64 (OP_LCOMPARE_IMM)
3372 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3373 next = ins->next;
3374 if (next && compare_opcode_is_unsigned (next->opcode)) {
3375 if (ppc_is_uimm16 (ins->inst_imm)) {
3376 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3377 } else {
3378 g_assert_not_reached ();
3380 } else {
3381 if (ppc_is_imm16 (ins->inst_imm)) {
3382 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3383 } else {
3384 g_assert_not_reached ();
3387 break;
3388 case OP_BREAK:
3390 * gdb does not like encountering a trap in the debugged code. So
3391 * instead of emitting a trap, we emit a call a C function and place a
3392 * breakpoint there.
3394 //ppc_break (code);
3395 ppc_mr (code, ppc_r3, ins->sreg1);
3396 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3397 (gpointer)"mono_break");
3398 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3399 ppc_load_func (code, ppc_r0, 0);
3400 ppc_mtlr (code, ppc_r0);
3401 ppc_blrl (code);
3402 } else {
3403 ppc_bl (code, 0);
3405 break;
3406 case OP_ADDCC:
3407 case OP_IADDCC:
3408 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3409 break;
3410 case OP_IADD:
3411 CASE_PPC64 (OP_LADD)
3412 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3413 break;
3414 case OP_ADC:
3415 case OP_IADC:
3416 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3417 break;
3418 case OP_ADDCC_IMM:
3419 if (ppc_is_imm16 (ins->inst_imm)) {
3420 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3421 } else {
3422 g_assert_not_reached ();
3424 break;
3425 case OP_ADD_IMM:
3426 case OP_IADD_IMM:
3427 CASE_PPC64 (OP_LADD_IMM)
3428 if (ppc_is_imm16 (ins->inst_imm)) {
3429 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3430 } else {
3431 g_assert_not_reached ();
3433 break;
3434 case OP_IADD_OVF:
3435 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3437 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3438 ppc_mfspr (code, ppc_r0, ppc_xer);
3439 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3440 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3441 break;
3442 case OP_IADD_OVF_UN:
3443 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3445 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3446 ppc_mfspr (code, ppc_r0, ppc_xer);
3447 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3448 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3449 break;
3450 case OP_ISUB_OVF:
3451 CASE_PPC64 (OP_LSUB_OVF)
3452 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3454 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3455 ppc_mfspr (code, ppc_r0, ppc_xer);
3456 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3457 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3458 break;
3459 case OP_ISUB_OVF_UN:
3460 CASE_PPC64 (OP_LSUB_OVF_UN)
3461 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3463 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3464 ppc_mfspr (code, ppc_r0, ppc_xer);
3465 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3466 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3467 break;
3468 case OP_ADD_OVF_CARRY:
3469 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3471 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3472 ppc_mfspr (code, ppc_r0, ppc_xer);
3473 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3474 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3475 break;
3476 case OP_ADD_OVF_UN_CARRY:
3477 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3479 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3480 ppc_mfspr (code, ppc_r0, ppc_xer);
3481 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3482 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3483 break;
3484 case OP_SUB_OVF_CARRY:
3485 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3487 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3488 ppc_mfspr (code, ppc_r0, ppc_xer);
3489 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3490 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3491 break;
3492 case OP_SUB_OVF_UN_CARRY:
3493 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3495 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3496 ppc_mfspr (code, ppc_r0, ppc_xer);
3497 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3498 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3499 break;
3500 case OP_SUBCC:
3501 case OP_ISUBCC:
3502 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3503 break;
3504 case OP_ISUB:
3505 CASE_PPC64 (OP_LSUB)
3506 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3507 break;
3508 case OP_SBB:
3509 case OP_ISBB:
3510 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3511 break;
3512 case OP_SUB_IMM:
3513 case OP_ISUB_IMM:
3514 CASE_PPC64 (OP_LSUB_IMM)
3515 // we add the negated value
3516 if (ppc_is_imm16 (-ins->inst_imm))
3517 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3518 else {
3519 g_assert_not_reached ();
3521 break;
3522 case OP_PPC_SUBFIC:
3523 g_assert (ppc_is_imm16 (ins->inst_imm));
3524 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3525 break;
3526 case OP_PPC_SUBFZE:
3527 ppc_subfze (code, ins->dreg, ins->sreg1);
3528 break;
3529 case OP_IAND:
3530 CASE_PPC64 (OP_LAND)
3531 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3532 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3533 break;
3534 case OP_AND_IMM:
3535 case OP_IAND_IMM:
3536 CASE_PPC64 (OP_LAND_IMM)
3537 if (!(ins->inst_imm & 0xffff0000)) {
3538 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3539 } else if (!(ins->inst_imm & 0xffff)) {
3540 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3541 } else {
3542 g_assert_not_reached ();
3544 break;
3545 case OP_IDIV:
3546 CASE_PPC64 (OP_LDIV) {
3547 guint8 *divisor_is_m1;
3548 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3550 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3551 divisor_is_m1 = code;
3552 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3553 ppc_lis (code, ppc_r0, 0x8000);
3554 #ifdef __mono_ppc64__
3555 if (ins->opcode == OP_LDIV)
3556 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3557 #endif
3558 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3559 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3560 ppc_patch (divisor_is_m1, code);
3561 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3563 if (ins->opcode == OP_IDIV)
3564 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3565 #ifdef __mono_ppc64__
3566 else
3567 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3568 #endif
3569 ppc_mfspr (code, ppc_r0, ppc_xer);
3570 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3571 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3572 break;
3574 case OP_IDIV_UN:
3575 CASE_PPC64 (OP_LDIV_UN)
3576 if (ins->opcode == OP_IDIV_UN)
3577 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3578 #ifdef __mono_ppc64__
3579 else
3580 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3581 #endif
3582 ppc_mfspr (code, ppc_r0, ppc_xer);
3583 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3584 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3585 break;
3586 case OP_DIV_IMM:
3587 case OP_IREM:
3588 case OP_IREM_UN:
3589 case OP_REM_IMM:
3590 g_assert_not_reached ();
3591 case OP_IOR:
3592 CASE_PPC64 (OP_LOR)
3593 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3594 break;
3595 case OP_OR_IMM:
3596 case OP_IOR_IMM:
3597 CASE_PPC64 (OP_LOR_IMM)
3598 if (!(ins->inst_imm & 0xffff0000)) {
3599 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3600 } else if (!(ins->inst_imm & 0xffff)) {
3601 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3602 } else {
3603 g_assert_not_reached ();
3605 break;
3606 case OP_IXOR:
3607 CASE_PPC64 (OP_LXOR)
3608 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3609 break;
3610 case OP_IXOR_IMM:
3611 case OP_XOR_IMM:
3612 CASE_PPC64 (OP_LXOR_IMM)
3613 if (!(ins->inst_imm & 0xffff0000)) {
3614 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3615 } else if (!(ins->inst_imm & 0xffff)) {
3616 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3617 } else {
3618 g_assert_not_reached ();
3620 break;
3621 case OP_ISHL:
3622 CASE_PPC64 (OP_LSHL)
3623 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3624 break;
3625 case OP_SHL_IMM:
3626 case OP_ISHL_IMM:
3627 CASE_PPC64 (OP_LSHL_IMM)
3628 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3629 break;
3630 case OP_ISHR:
3631 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3632 break;
3633 case OP_SHR_IMM:
3634 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3635 break;
3636 case OP_SHR_UN_IMM:
3637 if (MASK_SHIFT_IMM (ins->inst_imm))
3638 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3639 else
3640 ppc_mr (code, ins->dreg, ins->sreg1);
3641 break;
3642 case OP_ISHR_UN:
3643 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3644 break;
3645 case OP_INOT:
3646 CASE_PPC64 (OP_LNOT)
3647 ppc_not (code, ins->dreg, ins->sreg1);
3648 break;
3649 case OP_INEG:
3650 CASE_PPC64 (OP_LNEG)
3651 ppc_neg (code, ins->dreg, ins->sreg1);
3652 break;
3653 case OP_IMUL:
3654 CASE_PPC64 (OP_LMUL)
3655 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3656 break;
3657 case OP_IMUL_IMM:
3658 case OP_MUL_IMM:
3659 CASE_PPC64 (OP_LMUL_IMM)
3660 if (ppc_is_imm16 (ins->inst_imm)) {
3661 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3662 } else {
3663 g_assert_not_reached ();
3665 break;
3666 case OP_IMUL_OVF:
3667 CASE_PPC64 (OP_LMUL_OVF)
3668 /* we annot use mcrxr, since it's not implemented on some processors
3669 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3671 if (ins->opcode == OP_IMUL_OVF)
3672 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3673 #ifdef __mono_ppc64__
3674 else
3675 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3676 #endif
3677 ppc_mfspr (code, ppc_r0, ppc_xer);
3678 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3679 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3680 break;
3681 case OP_IMUL_OVF_UN:
3682 CASE_PPC64 (OP_LMUL_OVF_UN)
3683 /* we first multiply to get the high word and compare to 0
3684 * to set the flags, then the result is discarded and then
3685 * we multiply to get the lower * bits result
3687 if (ins->opcode == OP_IMUL_OVF_UN)
3688 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3689 #ifdef __mono_ppc64__
3690 else
3691 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3692 #endif
3693 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3694 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3695 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3696 break;
3697 case OP_ICONST:
3698 ppc_load (code, ins->dreg, ins->inst_c0);
3699 break;
3700 case OP_I8CONST: {
3701 ppc_load (code, ins->dreg, ins->inst_l);
3702 break;
3704 case OP_LOAD_GOTADDR:
3705 /* The PLT implementation depends on this */
3706 g_assert (ins->dreg == ppc_r30);
3708 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3709 break;
3710 case OP_GOT_ENTRY:
3711 // FIXME: Fix max instruction length
3712 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3713 /* arch_emit_got_access () patches this */
3714 ppc_load32 (code, ppc_r0, 0);
3715 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3716 break;
3717 case OP_AOTCONST:
3718 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3719 ppc_load_sequence (code, ins->dreg, 0);
3720 break;
3721 CASE_PPC32 (OP_ICONV_TO_I4)
3722 CASE_PPC32 (OP_ICONV_TO_U4)
3723 case OP_MOVE:
3724 ppc_mr (code, ins->dreg, ins->sreg1);
3725 break;
3726 case OP_SETLRET: {
3727 int saved = ins->sreg1;
3728 if (ins->sreg1 == ppc_r3) {
3729 ppc_mr (code, ppc_r0, ins->sreg1);
3730 saved = ppc_r0;
3732 if (ins->sreg2 != ppc_r3)
3733 ppc_mr (code, ppc_r3, ins->sreg2);
3734 if (saved != ppc_r4)
3735 ppc_mr (code, ppc_r4, saved);
3736 break;
3738 case OP_FMOVE:
3739 ppc_fmr (code, ins->dreg, ins->sreg1);
3740 break;
3741 case OP_FCONV_TO_R4:
3742 ppc_frsp (code, ins->dreg, ins->sreg1);
3743 break;
3744 case OP_TAILCALL: {
3745 int i, pos;
3746 MonoCallInst *call = (MonoCallInst*)ins;
3749 * Keep in sync with mono_arch_emit_epilog
3751 g_assert (!cfg->method->save_lmf);
3753 * Note: we can use ppc_r11 here because it is dead anyway:
3754 * we're leaving the method.
3756 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3757 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3758 if (ppc_is_imm16 (ret_offset)) {
3759 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3760 } else {
3761 ppc_load (code, ppc_r11, ret_offset);
3762 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3764 ppc_mtlr (code, ppc_r0);
3767 if (ppc_is_imm16 (cfg->stack_usage)) {
3768 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3769 } else {
3770 /* cfg->stack_usage is an int, so we can use
3771 * an addis/addi sequence here even in 64-bit. */
3772 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3773 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3775 if (!cfg->method->save_lmf) {
3776 pos = 0;
3777 for (i = 31; i >= 13; --i) {
3778 if (cfg->used_int_regs & (1 << i)) {
3779 pos += sizeof (gpointer);
3780 ppc_ldptr (code, i, -pos, ppc_r11);
3783 } else {
3784 /* FIXME restore from MonoLMF: though this can't happen yet */
3787 /* Copy arguments on the stack to our argument area */
3788 if (call->stack_usage) {
3789 code = emit_memcpy (code, call->stack_usage, ppc_r11, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3790 /* r11 was clobbered */
3791 g_assert (cfg->frame_reg == ppc_sp);
3792 if (ppc_is_imm16 (cfg->stack_usage)) {
3793 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3794 } else {
3795 /* cfg->stack_usage is an int, so we can use
3796 * an addis/addi sequence here even in 64-bit. */
3797 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3798 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3802 ppc_mr (code, ppc_sp, ppc_r11);
3803 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3804 if (cfg->compile_aot) {
3805 /* arch_emit_got_access () patches this */
3806 ppc_load32 (code, ppc_r0, 0);
3807 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3808 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3809 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3810 #else
3811 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3812 #endif
3813 ppc_mtctr (code, ppc_r0);
3814 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3815 } else {
3816 ppc_b (code, 0);
3818 break;
3820 case OP_CHECK_THIS:
3821 /* ensure ins->sreg1 is not NULL */
3822 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3823 break;
3824 case OP_ARGLIST: {
3825 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3826 if (ppc_is_imm16 (cookie_offset)) {
3827 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3828 } else {
3829 ppc_load (code, ppc_r0, cookie_offset);
3830 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3832 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3833 break;
3835 case OP_FCALL:
3836 case OP_LCALL:
3837 case OP_VCALL:
3838 case OP_VCALL2:
3839 case OP_VOIDCALL:
3840 case OP_CALL:
3841 call = (MonoCallInst*)ins;
3842 if (ins->flags & MONO_INST_HAS_METHOD)
3843 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3844 else
3845 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3846 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3847 ppc_load_func (code, ppc_r0, 0);
3848 ppc_mtlr (code, ppc_r0);
3849 ppc_blrl (code);
3850 } else {
3851 ppc_bl (code, 0);
3853 /* FIXME: this should be handled somewhere else in the new jit */
3854 code = emit_move_return_value (cfg, ins, code);
3855 break;
3856 case OP_FCALL_REG:
3857 case OP_LCALL_REG:
3858 case OP_VCALL_REG:
3859 case OP_VCALL2_REG:
3860 case OP_VOIDCALL_REG:
3861 case OP_CALL_REG:
3862 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3863 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3864 /* FIXME: if we know that this is a method, we
3865 can omit this load */
3866 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3867 ppc_mtlr (code, ppc_r0);
3868 #else
3869 ppc_mtlr (code, ins->sreg1);
3870 #endif
3871 ppc_blrl (code);
3872 /* FIXME: this should be handled somewhere else in the new jit */
3873 code = emit_move_return_value (cfg, ins, code);
3874 break;
3875 case OP_FCALL_MEMBASE:
3876 case OP_LCALL_MEMBASE:
3877 case OP_VCALL_MEMBASE:
3878 case OP_VCALL2_MEMBASE:
3879 case OP_VOIDCALL_MEMBASE:
3880 case OP_CALL_MEMBASE:
3881 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
3882 /* The trampolines clobber this */
3883 ppc_mr (code, ppc_r29, ins->sreg1);
3884 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3885 } else {
3886 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3888 ppc_mtlr (code, ppc_r0);
3889 ppc_blrl (code);
3890 /* FIXME: this should be handled somewhere else in the new jit */
3891 code = emit_move_return_value (cfg, ins, code);
3892 break;
3893 case OP_LOCALLOC: {
3894 guint8 * zero_loop_jump, * zero_loop_start;
3895 /* keep alignment */
3896 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3897 int area_offset = alloca_waste;
3898 area_offset &= ~31;
3899 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3900 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3901 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3902 /* use ctr to store the number of words to 0 if needed */
3903 if (ins->flags & MONO_INST_INIT) {
3904 /* we zero 4 bytes at a time:
3905 * we add 7 instead of 3 so that we set the counter to
3906 * at least 1, otherwise the bdnz instruction will make
3907 * it negative and iterate billions of times.
3909 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3910 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3911 ppc_mtctr (code, ppc_r0);
3913 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3914 ppc_neg (code, ppc_r11, ppc_r11);
3915 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3917 /* FIXME: make this loop work in 8 byte
3918 increments on PPC64 */
3919 if (ins->flags & MONO_INST_INIT) {
3920 /* adjust the dest reg by -4 so we can use stwu */
3921 /* we actually adjust -8 because we let the loop
3922 * run at least once
3924 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3925 ppc_li (code, ppc_r11, 0);
3926 zero_loop_start = code;
3927 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3928 zero_loop_jump = code;
3929 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3930 ppc_patch (zero_loop_jump, zero_loop_start);
3932 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3933 break;
3935 case OP_THROW: {
3936 //ppc_break (code);
3937 ppc_mr (code, ppc_r3, ins->sreg1);
3938 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3939 (gpointer)"mono_arch_throw_exception");
3940 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3941 ppc_load_func (code, ppc_r0, 0);
3942 ppc_mtlr (code, ppc_r0);
3943 ppc_blrl (code);
3944 } else {
3945 ppc_bl (code, 0);
3947 break;
3949 case OP_RETHROW: {
3950 //ppc_break (code);
3951 ppc_mr (code, ppc_r3, ins->sreg1);
3952 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3953 (gpointer)"mono_arch_rethrow_exception");
3954 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3955 ppc_load_func (code, ppc_r0, 0);
3956 ppc_mtlr (code, ppc_r0);
3957 ppc_blrl (code);
3958 } else {
3959 ppc_bl (code, 0);
3961 break;
3963 case OP_START_HANDLER: {
3964 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3965 g_assert (spvar->inst_basereg != ppc_sp);
3966 code = emit_reserve_param_area (cfg, code);
3967 ppc_mflr (code, ppc_r0);
3968 if (ppc_is_imm16 (spvar->inst_offset)) {
3969 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3970 } else {
3971 ppc_load (code, ppc_r11, spvar->inst_offset);
3972 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3974 break;
3976 case OP_ENDFILTER: {
3977 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3978 g_assert (spvar->inst_basereg != ppc_sp);
3979 code = emit_unreserve_param_area (cfg, code);
3980 if (ins->sreg1 != ppc_r3)
3981 ppc_mr (code, ppc_r3, ins->sreg1);
3982 if (ppc_is_imm16 (spvar->inst_offset)) {
3983 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3984 } else {
3985 ppc_load (code, ppc_r11, spvar->inst_offset);
3986 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3988 ppc_mtlr (code, ppc_r0);
3989 ppc_blr (code);
3990 break;
3992 case OP_ENDFINALLY: {
3993 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3994 g_assert (spvar->inst_basereg != ppc_sp);
3995 code = emit_unreserve_param_area (cfg, code);
3996 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3997 ppc_mtlr (code, ppc_r0);
3998 ppc_blr (code);
3999 break;
4001 case OP_CALL_HANDLER:
4002 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4003 ppc_bl (code, 0);
4004 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4005 break;
4006 case OP_LABEL:
4007 ins->inst_c0 = code - cfg->native_code;
4008 break;
4009 case OP_BR:
4010 /*if (ins->inst_target_bb->native_offset) {
4011 ppc_b (code, 0);
4012 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4013 } else*/ {
4014 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4015 ppc_b (code, 0);
4017 break;
4018 case OP_BR_REG:
4019 ppc_mtctr (code, ins->sreg1);
4020 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4021 break;
4022 case OP_CEQ:
4023 case OP_ICEQ:
4024 CASE_PPC64 (OP_LCEQ)
4025 ppc_li (code, ins->dreg, 0);
4026 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4027 ppc_li (code, ins->dreg, 1);
4028 break;
4029 case OP_CLT:
4030 case OP_CLT_UN:
4031 case OP_ICLT:
4032 case OP_ICLT_UN:
4033 CASE_PPC64 (OP_LCLT)
4034 CASE_PPC64 (OP_LCLT_UN)
4035 ppc_li (code, ins->dreg, 1);
4036 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4037 ppc_li (code, ins->dreg, 0);
4038 break;
4039 case OP_CGT:
4040 case OP_CGT_UN:
4041 case OP_ICGT:
4042 case OP_ICGT_UN:
4043 CASE_PPC64 (OP_LCGT)
4044 CASE_PPC64 (OP_LCGT_UN)
4045 ppc_li (code, ins->dreg, 1);
4046 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4047 ppc_li (code, ins->dreg, 0);
4048 break;
4049 case OP_COND_EXC_EQ:
4050 case OP_COND_EXC_NE_UN:
4051 case OP_COND_EXC_LT:
4052 case OP_COND_EXC_LT_UN:
4053 case OP_COND_EXC_GT:
4054 case OP_COND_EXC_GT_UN:
4055 case OP_COND_EXC_GE:
4056 case OP_COND_EXC_GE_UN:
4057 case OP_COND_EXC_LE:
4058 case OP_COND_EXC_LE_UN:
4059 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4060 break;
4061 case OP_COND_EXC_IEQ:
4062 case OP_COND_EXC_INE_UN:
4063 case OP_COND_EXC_ILT:
4064 case OP_COND_EXC_ILT_UN:
4065 case OP_COND_EXC_IGT:
4066 case OP_COND_EXC_IGT_UN:
4067 case OP_COND_EXC_IGE:
4068 case OP_COND_EXC_IGE_UN:
4069 case OP_COND_EXC_ILE:
4070 case OP_COND_EXC_ILE_UN:
4071 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4072 break;
4073 case OP_IBEQ:
4074 case OP_IBNE_UN:
4075 case OP_IBLT:
4076 case OP_IBLT_UN:
4077 case OP_IBGT:
4078 case OP_IBGT_UN:
4079 case OP_IBGE:
4080 case OP_IBGE_UN:
4081 case OP_IBLE:
4082 case OP_IBLE_UN:
4083 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4084 break;
4086 /* floating point opcodes */
4087 case OP_R8CONST:
4088 g_assert (cfg->compile_aot);
4090 /* FIXME: Optimize this */
4091 ppc_bl (code, 1);
4092 ppc_mflr (code, ppc_r11);
4093 ppc_b (code, 3);
4094 *(double*)code = *(double*)ins->inst_p0;
4095 code += 8;
4096 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4097 break;
4098 case OP_R4CONST:
4099 g_assert_not_reached ();
4100 break;
4101 case OP_STORER8_MEMBASE_REG:
4102 if (ppc_is_imm16 (ins->inst_offset)) {
4103 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4104 } else {
4105 if (ppc_is_imm32 (ins->inst_offset)) {
4106 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4107 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4108 } else {
4109 ppc_load (code, ppc_r0, ins->inst_offset);
4110 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4113 break;
4114 case OP_LOADR8_MEMBASE:
4115 if (ppc_is_imm16 (ins->inst_offset)) {
4116 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4117 } else {
4118 if (ppc_is_imm32 (ins->inst_offset)) {
4119 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4120 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4121 } else {
4122 ppc_load (code, ppc_r0, ins->inst_offset);
4123 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4126 break;
4127 case OP_STORER4_MEMBASE_REG:
4128 ppc_frsp (code, ins->sreg1, ins->sreg1);
4129 if (ppc_is_imm16 (ins->inst_offset)) {
4130 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4131 } else {
4132 if (ppc_is_imm32 (ins->inst_offset)) {
4133 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4134 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4135 } else {
4136 ppc_load (code, ppc_r0, ins->inst_offset);
4137 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4140 break;
4141 case OP_LOADR4_MEMBASE:
4142 if (ppc_is_imm16 (ins->inst_offset)) {
4143 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4144 } else {
4145 if (ppc_is_imm32 (ins->inst_offset)) {
4146 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4147 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4148 } else {
4149 ppc_load (code, ppc_r0, ins->inst_offset);
4150 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4153 break;
4154 case OP_LOADR4_MEMINDEX:
4155 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4156 break;
4157 case OP_LOADR8_MEMINDEX:
4158 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4159 break;
4160 case OP_STORER4_MEMINDEX:
4161 ppc_frsp (code, ins->sreg1, ins->sreg1);
4162 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4163 break;
4164 case OP_STORER8_MEMINDEX:
4165 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4166 break;
4167 case CEE_CONV_R_UN:
4168 case CEE_CONV_R4: /* FIXME: change precision */
4169 case CEE_CONV_R8:
4170 g_assert_not_reached ();
4171 case OP_FCONV_TO_I1:
4172 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4173 break;
4174 case OP_FCONV_TO_U1:
4175 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4176 break;
4177 case OP_FCONV_TO_I2:
4178 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4179 break;
4180 case OP_FCONV_TO_U2:
4181 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4182 break;
4183 case OP_FCONV_TO_I4:
4184 case OP_FCONV_TO_I:
4185 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4186 break;
4187 case OP_FCONV_TO_U4:
4188 case OP_FCONV_TO_U:
4189 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4190 break;
4191 case OP_LCONV_TO_R_UN:
4192 g_assert_not_reached ();
4193 /* Implemented as helper calls */
4194 break;
4195 case OP_LCONV_TO_OVF_I4_2:
4196 case OP_LCONV_TO_OVF_I: {
4197 #ifdef __mono_ppc64__
4198 NOT_IMPLEMENTED;
4199 #else
4200 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4201 // Check if its negative
4202 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4203 negative_branch = code;
4204 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4205 // Its positive msword == 0
4206 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4207 msword_positive_branch = code;
4208 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4210 ovf_ex_target = code;
4211 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4212 // Negative
4213 ppc_patch (negative_branch, code);
4214 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4215 msword_negative_branch = code;
4216 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4217 ppc_patch (msword_negative_branch, ovf_ex_target);
4219 ppc_patch (msword_positive_branch, code);
4220 if (ins->dreg != ins->sreg1)
4221 ppc_mr (code, ins->dreg, ins->sreg1);
4222 break;
4223 #endif
4225 case OP_SQRT:
4226 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4227 break;
4228 case OP_FADD:
4229 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4230 break;
4231 case OP_FSUB:
4232 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4233 break;
4234 case OP_FMUL:
4235 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4236 break;
4237 case OP_FDIV:
4238 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4239 break;
4240 case OP_FNEG:
4241 ppc_fneg (code, ins->dreg, ins->sreg1);
4242 break;
4243 case OP_FREM:
4244 /* emulated */
4245 g_assert_not_reached ();
4246 break;
4247 case OP_FCOMPARE:
4248 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4249 break;
4250 case OP_FCEQ:
4251 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4252 ppc_li (code, ins->dreg, 0);
4253 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4254 ppc_li (code, ins->dreg, 1);
4255 break;
4256 case OP_FCLT:
4257 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4258 ppc_li (code, ins->dreg, 1);
4259 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4260 ppc_li (code, ins->dreg, 0);
4261 break;
4262 case OP_FCLT_UN:
4263 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4264 ppc_li (code, ins->dreg, 1);
4265 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4266 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4267 ppc_li (code, ins->dreg, 0);
4268 break;
4269 case OP_FCGT:
4270 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4271 ppc_li (code, ins->dreg, 1);
4272 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4273 ppc_li (code, ins->dreg, 0);
4274 break;
4275 case OP_FCGT_UN:
4276 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4277 ppc_li (code, ins->dreg, 1);
4278 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4279 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4280 ppc_li (code, ins->dreg, 0);
4281 break;
4282 case OP_FBEQ:
4283 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4284 break;
4285 case OP_FBNE_UN:
4286 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4287 break;
4288 case OP_FBLT:
4289 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4290 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4291 break;
4292 case OP_FBLT_UN:
4293 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4294 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4295 break;
4296 case OP_FBGT:
4297 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4298 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4299 break;
4300 case OP_FBGT_UN:
4301 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4302 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4303 break;
4304 case OP_FBGE:
4305 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4306 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4307 break;
4308 case OP_FBGE_UN:
4309 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4310 break;
4311 case OP_FBLE:
4312 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4313 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4314 break;
4315 case OP_FBLE_UN:
4316 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4317 break;
4318 case OP_CKFINITE:
4319 g_assert_not_reached ();
4320 case OP_CHECK_FINITE: {
4321 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4322 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4323 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4324 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4325 break;
4326 case OP_JUMP_TABLE:
4327 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4328 #ifdef __mono_ppc64__
4329 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4330 #else
4331 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4332 #endif
4333 break;
4336 #ifdef __mono_ppc64__
4337 case OP_ICONV_TO_I4:
4338 case OP_SEXT_I4:
4339 ppc_extsw (code, ins->dreg, ins->sreg1);
4340 break;
4341 case OP_ICONV_TO_U4:
4342 case OP_ZEXT_I4:
4343 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4344 break;
4345 case OP_ICONV_TO_R4:
4346 case OP_ICONV_TO_R8:
4347 case OP_LCONV_TO_R4:
4348 case OP_LCONV_TO_R8: {
4349 int tmp;
4350 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4351 ppc_extsw (code, ppc_r0, ins->sreg1);
4352 tmp = ppc_r0;
4353 } else {
4354 tmp = ins->sreg1;
4356 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4357 ppc_mffgpr (code, ins->dreg, tmp);
4358 } else {
4359 ppc_str (code, tmp, -8, ppc_r1);
4360 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4362 ppc_fcfid (code, ins->dreg, ins->dreg);
4363 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4364 ppc_frsp (code, ins->dreg, ins->dreg);
4365 break;
4367 case OP_LSHR:
4368 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4369 break;
4370 case OP_LSHR_UN:
4371 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4372 break;
4373 case OP_COND_EXC_C:
4374 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4376 ppc_mfspr (code, ppc_r0, ppc_xer);
4377 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4378 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4379 break;
4380 case OP_COND_EXC_OV:
4381 ppc_mfspr (code, ppc_r0, ppc_xer);
4382 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4383 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4384 break;
4385 case OP_LBEQ:
4386 case OP_LBNE_UN:
4387 case OP_LBLT:
4388 case OP_LBLT_UN:
4389 case OP_LBGT:
4390 case OP_LBGT_UN:
4391 case OP_LBGE:
4392 case OP_LBGE_UN:
4393 case OP_LBLE:
4394 case OP_LBLE_UN:
4395 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4396 break;
4397 case OP_FCONV_TO_I8:
4398 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4399 break;
4400 case OP_FCONV_TO_U8:
4401 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4402 break;
4403 case OP_STOREI4_MEMBASE_REG:
4404 if (ppc_is_imm16 (ins->inst_offset)) {
4405 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4406 } else {
4407 ppc_load (code, ppc_r0, ins->inst_offset);
4408 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4410 break;
4411 case OP_STOREI4_MEMINDEX:
4412 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4413 break;
4414 case OP_ISHR_IMM:
4415 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4416 break;
4417 case OP_ISHR_UN_IMM:
4418 if (ins->inst_imm & 0x1f)
4419 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4420 else
4421 ppc_mr (code, ins->dreg, ins->sreg1);
4422 break;
4423 case OP_ATOMIC_ADD_NEW_I4:
4424 case OP_ATOMIC_ADD_NEW_I8: {
4425 guint8 *loop = code, *branch;
4426 g_assert (ins->inst_offset == 0);
4427 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4428 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4429 else
4430 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4431 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4432 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4433 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4434 else
4435 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4436 branch = code;
4437 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4438 ppc_patch (branch, loop);
4439 ppc_mr (code, ins->dreg, ppc_r0);
4440 break;
4442 #else
4443 case OP_ICONV_TO_R4:
4444 case OP_ICONV_TO_R8: {
4445 if (cpu_hw_caps & PPC_ISA_64) {
4446 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4447 ppc_stw (code, ppc_r0, -8, ppc_r1);
4448 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4449 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4450 ppc_fcfid (code, ins->dreg, ins->dreg);
4451 if (ins->opcode == OP_ICONV_TO_R4)
4452 ppc_frsp (code, ins->dreg, ins->dreg);
4454 break;
4456 #endif
4457 case OP_ATOMIC_CAS_I4:
4458 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4459 int location = ins->sreg1;
4460 int value = ins->sreg2;
4461 int comparand = ins->sreg3;
4462 guint8 *start, *not_equal, *lost_reservation;
4464 start = code;
4465 if (ins->opcode == OP_ATOMIC_CAS_I4)
4466 ppc_lwarx (code, ppc_r0, 0, location);
4467 #ifdef __mono_ppc64__
4468 else
4469 ppc_ldarx (code, ppc_r0, 0, location);
4470 #endif
4471 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4473 not_equal = code;
4474 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4475 if (ins->opcode == OP_ATOMIC_CAS_I4)
4476 ppc_stwcxd (code, value, 0, location);
4477 #ifdef __mono_ppc64__
4478 else
4479 ppc_stdcxd (code, value, 0, location);
4480 #endif
4482 lost_reservation = code;
4483 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4484 ppc_patch (lost_reservation, start);
4486 ppc_patch (not_equal, code);
4487 ppc_mr (code, ins->dreg, ppc_r0);
4488 break;
4491 default:
4492 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4493 g_assert_not_reached ();
4496 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4497 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4498 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4499 g_assert_not_reached ();
4502 cpos += max_len;
4504 last_ins = ins;
4505 last_offset = offset;
4508 cfg->code_len = code - cfg->native_code;
4510 #endif /* !DISABLE_JIT */
4512 void
4513 mono_arch_register_lowlevel_calls (void)
4515 /* The signature doesn't matter */
4516 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4519 #ifdef __mono_ppc64__
4520 #define patch_load_sequence(ip,val) do {\
4521 guint16 *__load = (guint16*)(ip); \
4522 g_assert (sizeof (val) == sizeof (gsize)); \
4523 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4524 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4525 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4526 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4527 } while (0)
4528 #else
4529 #define patch_load_sequence(ip,val) do {\
4530 guint16 *__lis_ori = (guint16*)(ip); \
4531 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4532 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4533 } while (0)
4534 #endif
4536 #ifndef DISABLE_JIT
4537 void
4538 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4540 MonoJumpInfo *patch_info;
4541 gboolean compile_aot = !run_cctors;
4543 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4544 unsigned char *ip = patch_info->ip.i + code;
4545 unsigned char *target;
4546 gboolean is_fd = FALSE;
4548 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4550 if (compile_aot) {
4551 switch (patch_info->type) {
4552 case MONO_PATCH_INFO_BB:
4553 case MONO_PATCH_INFO_LABEL:
4554 break;
4555 default:
4556 /* No need to patch these */
4557 continue;
4561 switch (patch_info->type) {
4562 case MONO_PATCH_INFO_IP:
4563 patch_load_sequence (ip, ip);
4564 continue;
4565 case MONO_PATCH_INFO_METHOD_REL:
4566 g_assert_not_reached ();
4567 *((gpointer *)(ip)) = code + patch_info->data.offset;
4568 continue;
4569 case MONO_PATCH_INFO_SWITCH: {
4570 gpointer *table = (gpointer *)patch_info->data.table->table;
4571 int i;
4573 patch_load_sequence (ip, table);
4575 for (i = 0; i < patch_info->data.table->table_size; i++) {
4576 table [i] = (glong)patch_info->data.table->table [i] + code;
4578 /* we put into the table the absolute address, no need for ppc_patch in this case */
4579 continue;
4581 case MONO_PATCH_INFO_METHODCONST:
4582 case MONO_PATCH_INFO_CLASS:
4583 case MONO_PATCH_INFO_IMAGE:
4584 case MONO_PATCH_INFO_FIELD:
4585 case MONO_PATCH_INFO_VTABLE:
4586 case MONO_PATCH_INFO_IID:
4587 case MONO_PATCH_INFO_SFLDA:
4588 case MONO_PATCH_INFO_LDSTR:
4589 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4590 case MONO_PATCH_INFO_LDTOKEN:
4591 /* from OP_AOTCONST : lis + ori */
4592 patch_load_sequence (ip, target);
4593 continue;
4594 case MONO_PATCH_INFO_R4:
4595 case MONO_PATCH_INFO_R8:
4596 g_assert_not_reached ();
4597 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4598 continue;
4599 case MONO_PATCH_INFO_EXC_NAME:
4600 g_assert_not_reached ();
4601 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4602 continue;
4603 case MONO_PATCH_INFO_NONE:
4604 case MONO_PATCH_INFO_BB_OVF:
4605 case MONO_PATCH_INFO_EXC_OVF:
4606 /* everything is dealt with at epilog output time */
4607 continue;
4608 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4609 case MONO_PATCH_INFO_INTERNAL_METHOD:
4610 case MONO_PATCH_INFO_ABS:
4611 case MONO_PATCH_INFO_CLASS_INIT:
4612 case MONO_PATCH_INFO_RGCTX_FETCH:
4613 is_fd = TRUE;
4614 break;
4615 #endif
4616 default:
4617 break;
4619 ppc_patch_full (ip, target, is_fd);
4624 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4625 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4626 * the instruction offset immediate for all the registers.
4628 static guint8*
4629 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4631 int i;
4632 if (!save_lmf) {
4633 for (i = 13; i <= 31; i++) {
4634 if (used_int_regs & (1 << i)) {
4635 ppc_str (code, i, pos, base_reg);
4636 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4637 pos += sizeof (mgreg_t);
4640 } else {
4641 /* pos is the start of the MonoLMF structure */
4642 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4643 for (i = 13; i <= 31; i++) {
4644 ppc_str (code, i, offset, base_reg);
4645 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4646 offset += sizeof (mgreg_t);
4648 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4649 for (i = 14; i < 32; i++) {
4650 ppc_stfd (code, i, offset, base_reg);
4651 offset += sizeof (gdouble);
4654 return code;
4658 * Stack frame layout:
4660 * ------------------- sp
4661 * MonoLMF structure or saved registers
4662 * -------------------
4663 * spilled regs
4664 * -------------------
4665 * locals
4666 * -------------------
4667 * optional 8 bytes for tracing
4668 * -------------------
4669 * param area size is cfg->param_area
4670 * -------------------
4671 * linkage area size is PPC_STACK_PARAM_OFFSET
4672 * ------------------- sp
4673 * red zone
4675 guint8 *
4676 mono_arch_emit_prolog (MonoCompile *cfg)
4678 MonoMethod *method = cfg->method;
4679 MonoBasicBlock *bb;
4680 MonoMethodSignature *sig;
4681 MonoInst *inst;
4682 long alloc_size, pos, max_offset, cfa_offset;
4683 int i;
4684 guint8 *code;
4685 CallInfo *cinfo;
4686 int tracing = 0;
4687 int lmf_offset = 0;
4688 int tailcall_struct_index;
4690 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4691 tracing = 1;
4693 sig = mono_method_signature (method);
4694 cfg->code_size = 512 + sig->param_count * 32;
4695 code = cfg->native_code = g_malloc (cfg->code_size);
4697 cfa_offset = 0;
4699 /* We currently emit unwind info for aot, but don't use it */
4700 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4702 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4703 ppc_mflr (code, ppc_r0);
4704 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4705 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4708 alloc_size = cfg->stack_offset;
4709 pos = 0;
4711 if (!method->save_lmf) {
4712 for (i = 31; i >= 13; --i) {
4713 if (cfg->used_int_regs & (1 << i)) {
4714 pos += sizeof (mgreg_t);
4717 } else {
4718 pos += sizeof (MonoLMF);
4719 lmf_offset = pos;
4721 alloc_size += pos;
4722 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4723 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4724 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4725 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4728 cfg->stack_usage = alloc_size;
4729 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4730 if (alloc_size) {
4731 if (ppc_is_imm16 (-alloc_size)) {
4732 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4733 cfa_offset = alloc_size;
4734 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4735 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4736 } else {
4737 if (pos)
4738 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4739 ppc_load (code, ppc_r0, -alloc_size);
4740 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4741 cfa_offset = alloc_size;
4742 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4743 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4746 if (cfg->frame_reg != ppc_sp) {
4747 ppc_mr (code, cfg->frame_reg, ppc_sp);
4748 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4751 /* store runtime generic context */
4752 if (cfg->rgctx_var) {
4753 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4754 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4756 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4759 /* compute max_offset in order to use short forward jumps
4760 * we always do it on ppc because the immediate displacement
4761 * for jumps is too small
4763 max_offset = 0;
4764 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4765 MonoInst *ins;
4766 bb->max_offset = max_offset;
4768 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4769 max_offset += 6;
4771 MONO_BB_FOR_EACH_INS (bb, ins)
4772 max_offset += ins_native_length (cfg, ins);
4775 /* load arguments allocated to register from the stack */
4776 pos = 0;
4778 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4780 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4781 ArgInfo *ainfo = &cinfo->ret;
4783 inst = cfg->vret_addr;
4784 g_assert (inst);
4786 if (ppc_is_imm16 (inst->inst_offset)) {
4787 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4788 } else {
4789 ppc_load (code, ppc_r11, inst->inst_offset);
4790 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4794 tailcall_struct_index = 0;
4795 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4796 ArgInfo *ainfo = cinfo->args + i;
4797 inst = cfg->args [pos];
4799 if (cfg->verbose_level > 2)
4800 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4801 if (inst->opcode == OP_REGVAR) {
4802 if (ainfo->regtype == RegTypeGeneral)
4803 ppc_mr (code, inst->dreg, ainfo->reg);
4804 else if (ainfo->regtype == RegTypeFP)
4805 ppc_fmr (code, inst->dreg, ainfo->reg);
4806 else if (ainfo->regtype == RegTypeBase) {
4807 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4808 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4809 } else
4810 g_assert_not_reached ();
4812 if (cfg->verbose_level > 2)
4813 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4814 } else {
4815 /* the argument should be put on the stack: FIXME handle size != word */
4816 if (ainfo->regtype == RegTypeGeneral) {
4817 switch (ainfo->size) {
4818 case 1:
4819 if (ppc_is_imm16 (inst->inst_offset)) {
4820 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4821 } else {
4822 if (ppc_is_imm32 (inst->inst_offset)) {
4823 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4824 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4825 } else {
4826 ppc_load (code, ppc_r11, inst->inst_offset);
4827 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4830 break;
4831 case 2:
4832 if (ppc_is_imm16 (inst->inst_offset)) {
4833 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4834 } else {
4835 if (ppc_is_imm32 (inst->inst_offset)) {
4836 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4837 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4838 } else {
4839 ppc_load (code, ppc_r11, inst->inst_offset);
4840 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4843 break;
4844 #ifdef __mono_ppc64__
4845 case 4:
4846 if (ppc_is_imm16 (inst->inst_offset)) {
4847 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4848 } else {
4849 if (ppc_is_imm32 (inst->inst_offset)) {
4850 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4851 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4852 } else {
4853 ppc_load (code, ppc_r11, inst->inst_offset);
4854 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4857 break;
4858 case 8:
4859 if (ppc_is_imm16 (inst->inst_offset)) {
4860 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4861 } else {
4862 ppc_load (code, ppc_r11, inst->inst_offset);
4863 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4865 break;
4866 #else
4867 case 8:
4868 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4869 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4870 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4871 } else {
4872 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4873 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4874 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4875 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4877 break;
4878 #endif
4879 default:
4880 if (ppc_is_imm16 (inst->inst_offset)) {
4881 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4882 } else {
4883 if (ppc_is_imm32 (inst->inst_offset)) {
4884 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4885 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4886 } else {
4887 ppc_load (code, ppc_r11, inst->inst_offset);
4888 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4891 break;
4893 } else if (ainfo->regtype == RegTypeBase) {
4894 g_assert (ppc_is_imm16 (ainfo->offset));
4895 /* load the previous stack pointer in r11 */
4896 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4897 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4898 switch (ainfo->size) {
4899 case 1:
4900 if (ppc_is_imm16 (inst->inst_offset)) {
4901 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4902 } else {
4903 if (ppc_is_imm32 (inst->inst_offset)) {
4904 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4905 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4906 } else {
4907 ppc_load (code, ppc_r11, inst->inst_offset);
4908 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4911 break;
4912 case 2:
4913 if (ppc_is_imm16 (inst->inst_offset)) {
4914 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4915 } else {
4916 if (ppc_is_imm32 (inst->inst_offset)) {
4917 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4918 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4919 } else {
4920 ppc_load (code, ppc_r11, inst->inst_offset);
4921 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4924 break;
4925 #ifdef __mono_ppc64__
4926 case 4:
4927 if (ppc_is_imm16 (inst->inst_offset)) {
4928 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4929 } else {
4930 if (ppc_is_imm32 (inst->inst_offset)) {
4931 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4932 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4933 } else {
4934 ppc_load (code, ppc_r11, inst->inst_offset);
4935 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4938 break;
4939 case 8:
4940 if (ppc_is_imm16 (inst->inst_offset)) {
4941 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4942 } else {
4943 ppc_load (code, ppc_r11, inst->inst_offset);
4944 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4946 break;
4947 #else
4948 case 8:
4949 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4950 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4951 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4952 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4953 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4954 } else {
4955 /* use r12 to load the 2nd half of the long before we clobber r11. */
4956 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4957 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4958 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4959 ppc_stw (code, ppc_r0, 0, ppc_r11);
4960 ppc_stw (code, ppc_r12, 4, ppc_r11);
4962 break;
4963 #endif
4964 default:
4965 if (ppc_is_imm16 (inst->inst_offset)) {
4966 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4967 } else {
4968 if (ppc_is_imm32 (inst->inst_offset)) {
4969 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4970 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4971 } else {
4972 ppc_load (code, ppc_r11, inst->inst_offset);
4973 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4976 break;
4978 } else if (ainfo->regtype == RegTypeFP) {
4979 g_assert (ppc_is_imm16 (inst->inst_offset));
4980 if (ainfo->size == 8)
4981 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4982 else if (ainfo->size == 4)
4983 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4984 else
4985 g_assert_not_reached ();
4986 } else if (ainfo->regtype == RegTypeStructByVal) {
4987 int doffset = inst->inst_offset;
4988 int soffset = 0;
4989 int cur_reg;
4990 int size = 0;
4991 g_assert (ppc_is_imm16 (inst->inst_offset));
4992 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
4993 /* FIXME: what if there is no class? */
4994 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4995 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4996 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
4997 #if __APPLE__
4999 * Darwin handles 1 and 2 byte
5000 * structs specially by
5001 * loading h/b into the arg
5002 * register. Only done for
5003 * pinvokes.
5005 if (size == 2)
5006 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5007 else if (size == 1)
5008 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5009 else
5010 #endif
5012 #ifdef __mono_ppc64__
5013 if (ainfo->bytes) {
5014 g_assert (cur_reg == 0);
5015 ppc_sldi (code, ppc_r0, ainfo->reg,
5016 (sizeof (gpointer) - ainfo->bytes) * 8);
5017 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5018 } else
5019 #endif
5021 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5022 inst->inst_basereg);
5025 soffset += sizeof (gpointer);
5026 doffset += sizeof (gpointer);
5028 if (ainfo->vtsize) {
5029 /* FIXME: we need to do the shifting here, too */
5030 if (ainfo->bytes)
5031 NOT_IMPLEMENTED;
5032 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5033 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5034 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5035 code = emit_memcpy (code, size - soffset,
5036 inst->inst_basereg, doffset,
5037 ppc_r11, ainfo->offset + soffset);
5038 } else {
5039 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5040 inst->inst_basereg, doffset,
5041 ppc_r11, ainfo->offset + soffset);
5044 } else if (ainfo->regtype == RegTypeStructByAddr) {
5045 /* if it was originally a RegTypeBase */
5046 if (ainfo->offset) {
5047 /* load the previous stack pointer in r11 */
5048 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5049 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5050 } else {
5051 ppc_mr (code, ppc_r11, ainfo->reg);
5054 if (cfg->tailcall_valuetype_addrs) {
5055 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5057 g_assert (ppc_is_imm16 (addr->inst_offset));
5058 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5060 tailcall_struct_index++;
5063 g_assert (ppc_is_imm16 (inst->inst_offset));
5064 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5065 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5066 } else
5067 g_assert_not_reached ();
5069 pos++;
5072 if (method->save_lmf) {
5073 if (lmf_pthread_key != -1) {
5074 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5075 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5076 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5077 } else {
5078 if (cfg->compile_aot) {
5079 /* Compute the got address which is needed by the PLT entry */
5080 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5082 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5083 (gpointer)"mono_get_lmf_addr");
5084 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5085 ppc_load_func (code, ppc_r0, 0);
5086 ppc_mtlr (code, ppc_r0);
5087 ppc_blrl (code);
5088 } else {
5089 ppc_bl (code, 0);
5092 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5093 /* lmf_offset is the offset from the previous stack pointer,
5094 * alloc_size is the total stack space allocated, so the offset
5095 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5096 * The pointer to the struct is put in ppc_r11 (new_lmf).
5097 * The callee-saved registers are already in the MonoLMF structure
5099 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5100 /* ppc_r3 is the result from mono_get_lmf_addr () */
5101 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5102 /* new_lmf->previous_lmf = *lmf_addr */
5103 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5104 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5105 /* *(lmf_addr) = r11 */
5106 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5107 /* save method info */
5108 if (cfg->compile_aot)
5109 // FIXME:
5110 ppc_load (code, ppc_r0, 0);
5111 else
5112 ppc_load_ptr (code, ppc_r0, method);
5113 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5114 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5115 /* save the current IP */
5116 if (cfg->compile_aot) {
5117 ppc_bl (code, 1);
5118 ppc_mflr (code, ppc_r0);
5119 } else {
5120 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5121 #ifdef __mono_ppc64__
5122 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5123 #else
5124 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5125 #endif
5127 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5130 if (tracing)
5131 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5133 cfg->code_len = code - cfg->native_code;
5134 g_assert (cfg->code_len <= cfg->code_size);
5135 g_free (cinfo);
5137 return code;
5140 void
5141 mono_arch_emit_epilog (MonoCompile *cfg)
5143 MonoMethod *method = cfg->method;
5144 int pos, i;
5145 int max_epilog_size = 16 + 20*4;
5146 guint8 *code;
5148 if (cfg->method->save_lmf)
5149 max_epilog_size += 128;
5151 if (mono_jit_trace_calls != NULL)
5152 max_epilog_size += 50;
5154 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5155 max_epilog_size += 50;
5157 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5158 cfg->code_size *= 2;
5159 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5160 cfg->stat_code_reallocs++;
5164 * Keep in sync with OP_JMP
5166 code = cfg->native_code + cfg->code_len;
5168 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5169 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5171 pos = 0;
5173 if (method->save_lmf) {
5174 int lmf_offset;
5175 pos += sizeof (MonoLMF);
5176 lmf_offset = pos;
5177 /* save the frame reg in r8 */
5178 ppc_mr (code, ppc_r8, cfg->frame_reg);
5179 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5180 /* r5 = previous_lmf */
5181 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5182 /* r6 = lmf_addr */
5183 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5184 /* *(lmf_addr) = previous_lmf */
5185 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5186 /* FIXME: speedup: there is no actual need to restore the registers if
5187 * we didn't actually change them (idea from Zoltan).
5189 /* restore iregs */
5190 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5191 /* restore fregs */
5192 /*for (i = 14; i < 32; i++) {
5193 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5195 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5196 /* use the saved copy of the frame reg in r8 */
5197 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5198 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5199 ppc_mtlr (code, ppc_r0);
5201 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5202 } else {
5203 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5204 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5205 if (ppc_is_imm16 (return_offset)) {
5206 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5207 } else {
5208 ppc_load (code, ppc_r11, return_offset);
5209 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5211 ppc_mtlr (code, ppc_r0);
5213 if (ppc_is_imm16 (cfg->stack_usage)) {
5214 int offset = cfg->stack_usage;
5215 for (i = 13; i <= 31; i++) {
5216 if (cfg->used_int_regs & (1 << i))
5217 offset -= sizeof (mgreg_t);
5219 if (cfg->frame_reg != ppc_sp)
5220 ppc_mr (code, ppc_r11, cfg->frame_reg);
5221 /* note r31 (possibly the frame register) is restored last */
5222 for (i = 13; i <= 31; i++) {
5223 if (cfg->used_int_regs & (1 << i)) {
5224 ppc_ldr (code, i, offset, cfg->frame_reg);
5225 offset += sizeof (mgreg_t);
5228 if (cfg->frame_reg != ppc_sp)
5229 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5230 else
5231 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5232 } else {
5233 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5234 if (cfg->used_int_regs) {
5235 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5236 for (i = 31; i >= 13; --i) {
5237 if (cfg->used_int_regs & (1 << i)) {
5238 pos += sizeof (mgreg_t);
5239 ppc_ldr (code, i, -pos, ppc_r11);
5242 ppc_mr (code, ppc_sp, ppc_r11);
5243 } else {
5244 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5249 ppc_blr (code);
5251 cfg->code_len = code - cfg->native_code;
5253 g_assert (cfg->code_len < cfg->code_size);
5256 #endif /* ifndef DISABLE_JIT */
5258 /* remove once throw_exception_by_name is eliminated */
5259 static int
5260 exception_id_by_name (const char *name)
5262 if (strcmp (name, "IndexOutOfRangeException") == 0)
5263 return MONO_EXC_INDEX_OUT_OF_RANGE;
5264 if (strcmp (name, "OverflowException") == 0)
5265 return MONO_EXC_OVERFLOW;
5266 if (strcmp (name, "ArithmeticException") == 0)
5267 return MONO_EXC_ARITHMETIC;
5268 if (strcmp (name, "DivideByZeroException") == 0)
5269 return MONO_EXC_DIVIDE_BY_ZERO;
5270 if (strcmp (name, "InvalidCastException") == 0)
5271 return MONO_EXC_INVALID_CAST;
5272 if (strcmp (name, "NullReferenceException") == 0)
5273 return MONO_EXC_NULL_REF;
5274 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5275 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5276 if (strcmp (name, "ArgumentException") == 0)
5277 return MONO_EXC_ARGUMENT;
5278 g_error ("Unknown intrinsic exception %s\n", name);
5279 return 0;
5282 #ifndef DISABLE_JIT
5283 void
5284 mono_arch_emit_exceptions (MonoCompile *cfg)
5286 MonoJumpInfo *patch_info;
5287 int i;
5288 guint8 *code;
5289 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5290 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5291 int max_epilog_size = 50;
5293 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5294 exc_throw_pos [i] = NULL;
5295 exc_throw_found [i] = 0;
5298 /* count the number of exception infos */
5301 * make sure we have enough space for exceptions
5303 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5304 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5305 i = exception_id_by_name (patch_info->data.target);
5306 if (!exc_throw_found [i]) {
5307 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5308 exc_throw_found [i] = TRUE;
5310 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5311 max_epilog_size += 12;
5312 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5313 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5314 i = exception_id_by_name (ovfj->data.exception);
5315 if (!exc_throw_found [i]) {
5316 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5317 exc_throw_found [i] = TRUE;
5319 max_epilog_size += 8;
5323 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5324 cfg->code_size *= 2;
5325 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5326 cfg->stat_code_reallocs++;
5329 code = cfg->native_code + cfg->code_len;
5331 /* add code to raise exceptions */
5332 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5333 switch (patch_info->type) {
5334 case MONO_PATCH_INFO_BB_OVF: {
5335 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5336 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5337 /* patch the initial jump */
5338 ppc_patch (ip, code);
5339 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5340 ppc_b (code, 0);
5341 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5342 /* jump back to the true target */
5343 ppc_b (code, 0);
5344 ip = ovfj->data.bb->native_offset + cfg->native_code;
5345 ppc_patch (code - 4, ip);
5346 patch_info->type = MONO_PATCH_INFO_NONE;
5347 break;
5349 case MONO_PATCH_INFO_EXC_OVF: {
5350 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5351 MonoJumpInfo *newji;
5352 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5353 unsigned char *bcl = code;
5354 /* patch the initial jump: we arrived here with a call */
5355 ppc_patch (ip, code);
5356 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5357 ppc_b (code, 0);
5358 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5359 /* patch the conditional jump to the right handler */
5360 /* make it processed next */
5361 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5362 newji->type = MONO_PATCH_INFO_EXC;
5363 newji->ip.i = bcl - cfg->native_code;
5364 newji->data.target = ovfj->data.exception;
5365 newji->next = patch_info->next;
5366 patch_info->next = newji;
5367 patch_info->type = MONO_PATCH_INFO_NONE;
5368 break;
5370 case MONO_PATCH_INFO_EXC: {
5371 MonoClass *exc_class;
5373 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5374 i = exception_id_by_name (patch_info->data.target);
5375 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5376 ppc_patch (ip, exc_throw_pos [i]);
5377 patch_info->type = MONO_PATCH_INFO_NONE;
5378 break;
5379 } else {
5380 exc_throw_pos [i] = code;
5383 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5384 g_assert (exc_class);
5386 ppc_patch (ip, code);
5387 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5388 ppc_load (code, ppc_r3, exc_class->type_token);
5389 /* we got here from a conditional call, so the calling ip is set in lr */
5390 ppc_mflr (code, ppc_r4);
5391 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5392 patch_info->data.name = "mono_arch_throw_corlib_exception";
5393 patch_info->ip.i = code - cfg->native_code;
5394 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5395 ppc_load_func (code, ppc_r0, 0);
5396 ppc_mtctr (code, ppc_r0);
5397 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5398 } else {
5399 ppc_bl (code, 0);
5401 break;
5403 default:
5404 /* do nothing */
5405 break;
5409 cfg->code_len = code - cfg->native_code;
5411 g_assert (cfg->code_len <= cfg->code_size);
5413 #endif
5415 #if DEAD_CODE
5416 static int
5417 try_offset_access (void *value, guint32 idx)
5419 register void* me __asm__ ("r2");
5420 void ***p = (void***)((char*)me + 284);
5421 int idx1 = idx / 32;
5422 int idx2 = idx % 32;
5423 if (!p [idx1])
5424 return 0;
5425 if (value != p[idx1][idx2])
5426 return 0;
5427 return 1;
5429 #endif
5431 static void
5432 setup_tls_access (void)
5434 guint32 ptk;
5436 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5437 size_t conf_size = 0;
5438 char confbuf[128];
5439 #else
5440 /* FIXME for darwin */
5441 guint32 *ins, *code;
5442 guint32 cmplwi_1023, li_0x48, blr_ins;
5443 #endif
5445 #ifdef TARGET_PS3
5446 tls_mode = TLS_MODE_FAILED;
5447 #endif
5449 if (tls_mode == TLS_MODE_FAILED)
5450 return;
5451 if (g_getenv ("MONO_NO_TLS")) {
5452 tls_mode = TLS_MODE_FAILED;
5453 return;
5456 if (tls_mode == TLS_MODE_DETECT) {
5457 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5458 tls_mode = TLS_MODE_DARWIN_G4;
5459 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5460 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5461 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5462 tls_mode = TLS_MODE_NPTL;
5463 #elif !defined(TARGET_PS3)
5464 ins = (guint32*)pthread_getspecific;
5465 /* uncond branch to the real method */
5466 if ((*ins >> 26) == 18) {
5467 gint32 val;
5468 val = (*ins & ~3) << 6;
5469 val >>= 6;
5470 if (*ins & 2) {
5471 /* absolute */
5472 ins = (guint32*)(long)val;
5473 } else {
5474 ins = (guint32*) ((char*)ins + val);
5477 code = &cmplwi_1023;
5478 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5479 code = &li_0x48;
5480 ppc_li (code, ppc_r4, 0x48);
5481 code = &blr_ins;
5482 ppc_blr (code);
5483 if (*ins == cmplwi_1023) {
5484 int found_lwz_284 = 0;
5485 for (ptk = 0; ptk < 20; ++ptk) {
5486 ++ins;
5487 if (!*ins || *ins == blr_ins)
5488 break;
5489 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5490 found_lwz_284 = 1;
5491 break;
5494 if (!found_lwz_284) {
5495 tls_mode = TLS_MODE_FAILED;
5496 return;
5498 tls_mode = TLS_MODE_LTHREADS;
5499 } else if (*ins == li_0x48) {
5500 ++ins;
5501 /* uncond branch to the real method */
5502 if ((*ins >> 26) == 18) {
5503 gint32 val;
5504 val = (*ins & ~3) << 6;
5505 val >>= 6;
5506 if (*ins & 2) {
5507 /* absolute */
5508 ins = (guint32*)(long)val;
5509 } else {
5510 ins = (guint32*) ((char*)ins + val);
5512 code = (guint32*)&val;
5513 ppc_li (code, ppc_r0, 0x7FF2);
5514 if (ins [1] == val) {
5515 /* Darwin on G4, implement */
5516 tls_mode = TLS_MODE_FAILED;
5517 return;
5518 } else {
5519 code = (guint32*)&val;
5520 ppc_mfspr (code, ppc_r3, 104);
5521 if (ins [1] != val) {
5522 tls_mode = TLS_MODE_FAILED;
5523 return;
5525 tls_mode = TLS_MODE_DARWIN_G5;
5527 } else {
5528 tls_mode = TLS_MODE_FAILED;
5529 return;
5531 } else {
5532 tls_mode = TLS_MODE_FAILED;
5533 return;
5535 #endif
5537 #ifndef TARGET_PS3
5538 if (tls_mode == TLS_MODE_DETECT)
5539 tls_mode = TLS_MODE_FAILED;
5540 if (tls_mode == TLS_MODE_FAILED)
5541 return;
5542 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5543 monodomain_key = mono_domain_get_tls_offset();
5545 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5546 mono_domain_get_tls_offset returning -1) then use keyed access. */
5547 if (monodomain_key == -1) {
5548 ptk = mono_domain_get_tls_key ();
5549 if (ptk < 1024)
5550 monodomain_key = ptk;
5553 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5554 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5557 #if 0
5558 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5559 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5560 if (lmf_pthread_key == -1) {
5561 ptk = mono_jit_tls_id;
5562 if (ptk < 1024) {
5563 /*g_print ("MonoLMF at: %d\n", ptk);*/
5564 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5565 init_tls_failed = 1;
5566 return;
5568 lmf_pthread_key = ptk;
5571 #endif
5573 #endif
5576 void
5577 mono_arch_finish_init (void)
5579 setup_tls_access ();
5582 void
5583 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5587 #ifdef MONO_ARCH_HAVE_IMT
5589 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5590 #define BR_SIZE 4
5591 #define LOADSTORE_SIZE 4
5592 #define JUMP_IMM_SIZE 12
5593 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5594 #define ENABLE_WRONG_METHOD_CHECK 0
5597 * LOCKING: called with the domain lock held
5599 gpointer
5600 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5601 gpointer fail_tramp)
5603 int i;
5604 int size = 0;
5605 guint8 *code, *start;
5607 for (i = 0; i < count; ++i) {
5608 MonoIMTCheckItem *item = imt_entries [i];
5609 if (item->is_equals) {
5610 if (item->check_target_idx) {
5611 if (!item->compare_done)
5612 item->chunk_size += CMP_SIZE;
5613 if (item->has_target_code)
5614 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5615 else
5616 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5617 } else {
5618 if (fail_tramp) {
5619 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5620 if (!item->has_target_code)
5621 item->chunk_size += LOADSTORE_SIZE;
5622 } else {
5623 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5624 #if ENABLE_WRONG_METHOD_CHECK
5625 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5626 #endif
5629 } else {
5630 item->chunk_size += CMP_SIZE + BR_SIZE;
5631 imt_entries [item->check_target_idx]->compare_done = TRUE;
5633 size += item->chunk_size;
5635 /* the initial load of the vtable address */
5636 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5637 if (fail_tramp) {
5638 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5639 } else {
5640 code = mono_domain_code_reserve (domain, size);
5642 start = code;
5645 * We need to save and restore r11 because it might be
5646 * used by the caller as the vtable register, so
5647 * clobbering it will trip up the magic trampoline.
5649 * FIXME: Get rid of this by making sure that r11 is
5650 * not used as the vtable register in interface calls.
5652 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5653 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5655 for (i = 0; i < count; ++i) {
5656 MonoIMTCheckItem *item = imt_entries [i];
5657 item->code_target = code;
5658 if (item->is_equals) {
5659 if (item->check_target_idx) {
5660 if (!item->compare_done) {
5661 ppc_load (code, ppc_r0, (gsize)item->key);
5662 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5664 item->jmp_code = code;
5665 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5666 if (item->has_target_code) {
5667 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5668 } else {
5669 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5670 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5672 ppc_mtctr (code, ppc_r0);
5673 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5674 } else {
5675 if (fail_tramp) {
5676 ppc_load (code, ppc_r0, (gulong)item->key);
5677 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5678 item->jmp_code = code;
5679 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5680 if (item->has_target_code) {
5681 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5682 } else {
5683 g_assert (vtable);
5684 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5685 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5687 ppc_mtctr (code, ppc_r0);
5688 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5689 ppc_patch (item->jmp_code, code);
5690 ppc_load_ptr (code, ppc_r0, fail_tramp);
5691 ppc_mtctr (code, ppc_r0);
5692 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5693 item->jmp_code = NULL;
5694 } else {
5695 /* enable the commented code to assert on wrong method */
5696 #if ENABLE_WRONG_METHOD_CHECK
5697 ppc_load (code, ppc_r0, (guint32)item->key);
5698 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5699 item->jmp_code = code;
5700 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5701 #endif
5702 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5703 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5704 ppc_mtctr (code, ppc_r0);
5705 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5706 #if ENABLE_WRONG_METHOD_CHECK
5707 ppc_patch (item->jmp_code, code);
5708 ppc_break (code);
5709 item->jmp_code = NULL;
5710 #endif
5713 } else {
5714 ppc_load (code, ppc_r0, (gulong)item->key);
5715 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5716 item->jmp_code = code;
5717 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5720 /* patch the branches to get to the target items */
5721 for (i = 0; i < count; ++i) {
5722 MonoIMTCheckItem *item = imt_entries [i];
5723 if (item->jmp_code) {
5724 if (item->check_target_idx) {
5725 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5730 if (!fail_tramp)
5731 mono_stats.imt_thunks_size += code - start;
5732 g_assert (code - start <= size);
5733 mono_arch_flush_icache (start, size);
5734 return start;
5737 MonoMethod*
5738 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5740 mgreg_t *r = (mgreg_t*)regs;
5742 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5744 #endif
5746 MonoVTable*
5747 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5749 mgreg_t *r = (mgreg_t*)regs;
5751 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5754 GSList*
5755 mono_arch_get_cie_program (void)
5757 GSList *l = NULL;
5759 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5761 return l;
5764 MonoInst*
5765 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5767 /* FIXME: */
5768 return NULL;
5771 gboolean
5772 mono_arch_print_tree (MonoInst *tree, int arity)
5774 return 0;
5777 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5779 MonoInst* ins;
5781 setup_tls_access ();
5782 if (monodomain_key == -1)
5783 return NULL;
5785 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5786 ins->inst_offset = monodomain_key;
5787 return ins;
5790 mgreg_t
5791 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5793 if (reg == ppc_r1)
5794 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5796 g_assert (reg >= ppc_r13);
5798 return ctx->regs [reg - ppc_r13];
5801 guint32
5802 mono_arch_get_patch_offset (guint8 *code)
5804 return 0;
5808 * mono_aot_emit_load_got_addr:
5810 * Emit code to load the got address.
5811 * On PPC, the result is placed into r30.
5813 guint8*
5814 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5816 ppc_bl (code, 1);
5817 ppc_mflr (code, ppc_r30);
5818 if (cfg)
5819 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5820 else
5821 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5822 /* arch_emit_got_address () patches this */
5823 #if defined(TARGET_POWERPC64)
5824 ppc_nop (code);
5825 ppc_nop (code);
5826 ppc_nop (code);
5827 ppc_nop (code);
5828 #else
5829 ppc_load32 (code, ppc_r0, 0);
5830 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5831 #endif
5833 return code;
5837 * mono_ppc_emit_load_aotconst:
5839 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5840 * TARGET from the mscorlib GOT in full-aot code.
5841 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5842 * r11.
5844 guint8*
5845 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5847 /* Load the mscorlib got address */
5848 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5849 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5850 /* arch_emit_got_access () patches this */
5851 ppc_load32 (code, ppc_r0, 0);
5852 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5854 return code;
5857 /* Soft Debug support */
5858 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5861 * BREAKPOINTS
5865 * mono_arch_set_breakpoint:
5867 * See mini-amd64.c for docs.
5869 void
5870 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5872 guint8 *code = ip;
5873 guint8 *orig_code = code;
5875 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5876 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5878 g_assert (code - orig_code == BREAKPOINT_SIZE);
5880 mono_arch_flush_icache (orig_code, code - orig_code);
5884 * mono_arch_clear_breakpoint:
5886 * See mini-amd64.c for docs.
5888 void
5889 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5891 guint8 *code = ip;
5892 int i;
5894 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5895 ppc_nop (code);
5897 mono_arch_flush_icache (ip, code - ip);
5901 * mono_arch_is_breakpoint_event:
5903 * See mini-amd64.c for docs.
5905 gboolean
5906 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5908 siginfo_t* sinfo = (siginfo_t*) info;
5909 /* Sometimes the address is off by 4 */
5910 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5911 return TRUE;
5912 else
5913 return FALSE;
5917 * mono_arch_skip_breakpoint:
5919 * See mini-amd64.c for docs.
5921 void
5922 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5924 /* skip the ldptr */
5925 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5929 * SINGLE STEPPING
5933 * mono_arch_start_single_stepping:
5935 * See mini-amd64.c for docs.
5937 void
5938 mono_arch_start_single_stepping (void)
5940 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5944 * mono_arch_stop_single_stepping:
5946 * See mini-amd64.c for docs.
5948 void
5949 mono_arch_stop_single_stepping (void)
5951 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5955 * mono_arch_is_single_step_event:
5957 * See mini-amd64.c for docs.
5959 gboolean
5960 mono_arch_is_single_step_event (void *info, void *sigctx)
5962 siginfo_t* sinfo = (siginfo_t*) info;
5963 /* Sometimes the address is off by 4 */
5964 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5965 return TRUE;
5966 else
5967 return FALSE;
5971 * mono_arch_skip_single_step:
5973 * See mini-amd64.c for docs.
5975 void
5976 mono_arch_skip_single_step (MonoContext *ctx)
5978 /* skip the ldptr */
5979 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5983 * mono_arch_create_seq_point_info:
5985 * See mini-amd64.c for docs.
5987 gpointer
5988 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5990 NOT_IMPLEMENTED;
5991 return NULL;
5994 #endif