2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
21 int mono_exc_esp_offset
= 0;
24 mono_arch_regname (int reg
) {
25 static const char * rnames
[] = {
26 "ppc_r0", "ppc_sp", "ppc_r2", "ppc_r3", "ppc_r4",
27 "ppc_r5", "ppc_r6", "ppc_r7", "ppc_r8", "ppc_r9",
28 "ppc_r10", "ppc_r11", "ppc_r12", "ppc_r13", "ppc_r14",
29 "ppc_r15", "ppc_r16", "ppc_r17", "ppc_r18", "ppc_r19",
30 "ppc_r20", "ppc_r21", "ppc_r22", "ppc_r23", "ppc_r24",
31 "ppc_r25", "ppc_r26", "ppc_r27", "ppc_r28", "ppc_r29",
34 if (reg
>= 0 && reg
< 32)
39 /* this function overwrites r0 */
41 emit_memcpy (guint8
*code
, int size
, int dreg
, int doffset
, int sreg
, int soffset
)
43 /* unrolled, use the counter in big */
45 ppc_lwz (code
, ppc_r0
, soffset
, sreg
);
46 ppc_stw (code
, ppc_r0
, doffset
, dreg
);
52 ppc_lhz (code
, ppc_r0
, soffset
, sreg
);
53 ppc_sth (code
, ppc_r0
, doffset
, dreg
);
59 ppc_lbz (code
, ppc_r0
, soffset
, sreg
);
60 ppc_stb (code
, ppc_r0
, doffset
, dreg
);
69 * mono_arch_get_argument_info:
70 * @csig: a method signature
71 * @param_count: the number of parameters to consider
72 * @arg_info: an array to store the result infos
74 * Gathers information on parameters such as size, alignment and
75 * padding. arg_info should be large enought to hold param_count + 1 entries.
77 * Returns the size of the activation frame.
80 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
82 int k
, frame_size
= 0;
86 if (MONO_TYPE_ISSTRUCT (csig
->ret
)) {
87 frame_size
+= sizeof (gpointer
);
91 arg_info
[0].offset
= offset
;
94 frame_size
+= sizeof (gpointer
);
98 arg_info
[0].size
= frame_size
;
100 for (k
= 0; k
< param_count
; k
++) {
103 size
= mono_type_native_stack_size (csig
->params
[k
], &align
);
105 size
= mono_type_stack_size (csig
->params
[k
], &align
);
107 /* ignore alignment for now */
110 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
111 arg_info
[k
].pad
= pad
;
113 arg_info
[k
+ 1].pad
= 0;
114 arg_info
[k
+ 1].size
= size
;
116 arg_info
[k
+ 1].offset
= offset
;
120 align
= MONO_ARCH_FRAME_ALIGNMENT
;
121 frame_size
+= pad
= (align
- (frame_size
& (align
- 1))) & (align
- 1);
122 arg_info
[k
].pad
= pad
;
128 * Initialize the cpu to execute managed code.
131 mono_arch_cpu_init (void)
136 * This function returns the optimizations supported on this cpu.
139 mono_arch_cpu_optimizazions (guint32
*exclude_mask
)
143 /* no ppc-specific optimizations yet */
144 *exclude_mask
= MONO_OPT_INLINE
;
149 is_regsize_var (MonoType
*t
) {
159 case MONO_TYPE_OBJECT
:
160 case MONO_TYPE_STRING
:
161 case MONO_TYPE_CLASS
:
162 case MONO_TYPE_SZARRAY
:
163 case MONO_TYPE_ARRAY
:
165 case MONO_TYPE_VALUETYPE
:
166 if (t
->data
.klass
->enumtype
)
167 return is_regsize_var (t
->data
.klass
->enum_basetype
);
174 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
179 for (i
= 0; i
< cfg
->num_varinfo
; i
++) {
180 MonoInst
*ins
= cfg
->varinfo
[i
];
181 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
184 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
187 if (ins
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
) || (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
190 /* we can only allocate 32 bit values */
191 if (is_regsize_var (ins
->inst_vtype
)) {
192 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
193 g_assert (i
== vmv
->idx
);
194 vars
= mono_varlist_insert_sorted (cfg
, vars
, vmv
, FALSE
);
201 #define USE_EXTRA_TEMPS ((1<<30) | (1<<29))
202 //#define USE_EXTRA_TEMPS 0
205 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
209 if (cfg
->frame_reg
!= ppc_sp
)
214 for (i
= 13; i
< top
; ++i
)
215 regs
= g_list_prepend (regs
, GUINT_TO_POINTER (i
));
221 * mono_arch_regalloc_cost:
223 * Return the cost, in number of memory references, of the action of
224 * allocating the variable VMV into a register during global register
228 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
234 // code from ppc/tramp.c, try to keep in sync
235 #define MIN_CACHE_LINE 8
238 mono_arch_flush_icache (guint8
*code
, gint size
)
244 for (i
= 0; i
< size
; i
+= MIN_CACHE_LINE
, p
+= MIN_CACHE_LINE
) {
245 asm ("dcbst 0,%0;" : : "r"(p
) : "memory");
249 for (i
= 0; i
< size
; i
+= MIN_CACHE_LINE
, p
+= MIN_CACHE_LINE
) {
250 asm ("icbi 0,%0; sync;" : : "r"(p
) : "memory");
256 #define NOT_IMPLEMENTED(x) \
257 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
260 #define ALWAYS_ON_STACK(s) s
261 #define FP_ALSO_IN_REG(s) s
263 #define ALWAYS_ON_STACK(s)
264 #define FP_ALSO_IN_REG(s) s
265 #define ALIGN_DOUBLES
278 guint16 vtsize
; /* in param area */
280 guint8 regtype
: 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
281 guint8 size
: 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
295 add_general (guint
*gr
, guint
*stack_size
, ArgInfo
*ainfo
, gboolean simple
)
298 if (*gr
>= 3 + PPC_NUM_REG_ARGS
) {
299 ainfo
->offset
= PPC_STACK_PARAM_OFFSET
+ *stack_size
;
300 ainfo
->reg
= ppc_sp
; /* in the caller */
301 ainfo
->regtype
= RegTypeBase
;
304 ALWAYS_ON_STACK (*stack_size
+= 4);
308 if (*gr
>= 3 + PPC_NUM_REG_ARGS
- 1) {
310 //*stack_size += (*stack_size % 8);
312 ainfo
->offset
= PPC_STACK_PARAM_OFFSET
+ *stack_size
;
313 ainfo
->reg
= ppc_sp
; /* in the caller */
314 ainfo
->regtype
= RegTypeBase
;
321 ALWAYS_ON_STACK (*stack_size
+= 8);
330 calculate_sizes (MonoMethodSignature
*sig
, gboolean is_pinvoke
)
333 int n
= sig
->hasthis
+ sig
->param_count
;
335 guint32 stack_size
= 0;
336 CallInfo
*cinfo
= g_malloc0 (sizeof (CallInfo
) + sizeof (ArgInfo
) * n
);
338 fr
= PPC_FIRST_FPARG_REG
;
339 gr
= PPC_FIRST_ARG_REG
;
341 /* FIXME: handle returning a struct */
342 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
343 add_general (&gr
, &stack_size
, &cinfo
->ret
, TRUE
);
344 cinfo
->struct_ret
= PPC_FIRST_ARG_REG
;
349 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
352 DEBUG(printf("params: %d\n", sig
->param_count
));
353 for (i
= 0; i
< sig
->param_count
; ++i
) {
354 DEBUG(printf("param %d: ", i
));
355 if (sig
->params
[i
]->byref
) {
356 DEBUG(printf("byref\n"));
357 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
361 simpletype
= sig
->params
[i
]->type
;
363 switch (simpletype
) {
364 case MONO_TYPE_BOOLEAN
:
367 cinfo
->args
[n
].size
= 1;
368 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
374 cinfo
->args
[n
].size
= 2;
375 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
380 cinfo
->args
[n
].size
= 4;
381 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
387 case MONO_TYPE_FNPTR
:
388 case MONO_TYPE_CLASS
:
389 case MONO_TYPE_OBJECT
:
390 case MONO_TYPE_STRING
:
391 case MONO_TYPE_SZARRAY
:
392 case MONO_TYPE_ARRAY
:
393 cinfo
->args
[n
].size
= sizeof (gpointer
);
394 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
397 case MONO_TYPE_VALUETYPE
: {
399 if (sig
->params
[i
]->data
.klass
->enumtype
) {
400 simpletype
= sig
->params
[i
]->data
.klass
->enum_basetype
->type
;
404 size
= mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
);
406 size
= mono_class_value_size (sig
->params
[i
]->data
.klass
, NULL
);
407 DEBUG(printf ("load %d bytes struct\n",
408 mono_class_native_size (sig
->params
[i
]->data
.klass
, NULL
)));
409 #if PPC_PASS_STRUCTS_BY_VALUE
411 int align_size
= size
;
413 align_size
+= (sizeof (gpointer
) - 1);
414 align_size
&= ~(sizeof (gpointer
) - 1);
415 nwords
= (align_size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
416 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
417 if (gr
> PPC_LAST_ARG_REG
|| (size
>= 3 && size
% 4 != 0)) {
418 cinfo
->args
[n
].size
= 0;
419 cinfo
->args
[n
].vtsize
= nwords
;
421 int rest
= PPC_LAST_ARG_REG
- gr
+ 1;
422 int n_in_regs
= rest
>= nwords
? nwords
: rest
;
423 cinfo
->args
[n
].size
= n_in_regs
;
424 cinfo
->args
[n
].vtsize
= nwords
- n_in_regs
;
425 cinfo
->args
[n
].reg
= gr
;
428 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
429 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
430 stack_size
+= nwords
* sizeof (gpointer
);
433 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
434 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
439 case MONO_TYPE_TYPEDBYREF
: {
440 int size
= sizeof (MonoTypedRef
);
441 /* keep in sync or merge with the valuetype case */
442 #if PPC_PASS_STRUCTS_BY_VALUE
444 int nwords
= (size
+ sizeof (gpointer
) -1 ) / sizeof (gpointer
);
445 cinfo
->args
[n
].regtype
= RegTypeStructByVal
;
446 if (gr
<= PPC_LAST_ARG_REG
) {
447 int rest
= PPC_LAST_ARG_REG
- gr
+ 1;
448 int n_in_regs
= rest
>= nwords
? nwords
: rest
;
449 cinfo
->args
[n
].size
= n_in_regs
;
450 cinfo
->args
[n
].vtsize
= nwords
- n_in_regs
;
451 cinfo
->args
[n
].reg
= gr
;
454 cinfo
->args
[n
].size
= 0;
455 cinfo
->args
[n
].vtsize
= nwords
;
457 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
458 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
459 stack_size
+= nwords
* sizeof (gpointer
);
462 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, TRUE
);
463 cinfo
->args
[n
].regtype
= RegTypeStructByAddr
;
470 cinfo
->args
[n
].size
= 8;
471 add_general (&gr
, &stack_size
, cinfo
->args
+ n
, FALSE
);
475 cinfo
->args
[n
].size
= 4;
477 /* It was 7, now it is 8 in LinuxPPC */
478 if (fr
<= PPC_LAST_FPARG_REG
) {
479 cinfo
->args
[n
].regtype
= RegTypeFP
;
480 cinfo
->args
[n
].reg
= fr
;
482 FP_ALSO_IN_REG (gr
++);
483 ALWAYS_ON_STACK (stack_size
+= 4);
485 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
486 cinfo
->args
[n
].regtype
= RegTypeBase
;
487 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
493 cinfo
->args
[n
].size
= 8;
494 /* It was 7, now it is 8 in LinuxPPC */
495 if (fr
<= PPC_LAST_FPARG_REG
) {
496 cinfo
->args
[n
].regtype
= RegTypeFP
;
497 cinfo
->args
[n
].reg
= fr
;
499 FP_ALSO_IN_REG (gr
+= 2);
500 ALWAYS_ON_STACK (stack_size
+= 8);
502 cinfo
->args
[n
].offset
= PPC_STACK_PARAM_OFFSET
+ stack_size
;
503 cinfo
->args
[n
].regtype
= RegTypeBase
;
504 cinfo
->args
[n
].reg
= ppc_sp
; /* in the caller*/
510 g_error ("Can't trampoline 0x%x", sig
->params
[i
]->type
);
515 simpletype
= sig
->ret
->type
;
517 switch (simpletype
) {
518 case MONO_TYPE_BOOLEAN
:
529 case MONO_TYPE_FNPTR
:
530 case MONO_TYPE_CLASS
:
531 case MONO_TYPE_OBJECT
:
532 case MONO_TYPE_SZARRAY
:
533 case MONO_TYPE_ARRAY
:
534 case MONO_TYPE_STRING
:
535 cinfo
->ret
.reg
= ppc_r3
;
539 cinfo
->ret
.reg
= ppc_r3
;
543 cinfo
->ret
.reg
= ppc_f1
;
544 cinfo
->ret
.regtype
= RegTypeFP
;
546 case MONO_TYPE_VALUETYPE
:
547 if (sig
->ret
->data
.klass
->enumtype
) {
548 simpletype
= sig
->ret
->data
.klass
->enum_basetype
->type
;
552 case MONO_TYPE_TYPEDBYREF
:
556 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
560 /* align stack size to 16 */
561 DEBUG (printf (" stack size: %d (%d)\n", (stack_size
+ 15) & ~15, stack_size
));
562 stack_size
= (stack_size
+ 15) & ~15;
564 cinfo
->stack_usage
= stack_size
;
570 * Set var information according to the calling convention. ppc version.
571 * The locals var stuff should most likely be split in another method.
574 mono_arch_allocate_vars (MonoCompile
*m
)
576 MonoMethodSignature
*sig
;
577 MonoMethodHeader
*header
;
579 int i
, offset
, size
, align
, curinst
;
580 int frame_reg
= ppc_sp
;
582 /* allow room for the vararg method args: void* and long/double */
583 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (m
->method
))
584 m
->param_area
= MAX (m
->param_area
, sizeof (gpointer
)*8);
585 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
586 * call convs needs to be handled this way.
588 if (m
->flags
& MONO_CFG_HAS_VARARGS
)
589 m
->param_area
= MAX (m
->param_area
, sizeof (gpointer
)*8);
591 header
= mono_method_get_header (m
->method
);
594 * We use the frame register also for any method that has
595 * exception clauses. This way, when the handlers are called,
596 * the code will reference local variables using the frame reg instead of
597 * the stack pointer: if we had to restore the stack pointer, we'd
598 * corrupt the method frames that are already on the stack (since
599 * filters get called before stack unwinding happens) when the filter
600 * code would call any method (this also applies to finally etc.).
602 if ((m
->flags
& MONO_CFG_HAS_ALLOCA
) || header
->num_clauses
)
604 m
->frame_reg
= frame_reg
;
605 if (frame_reg
!= ppc_sp
) {
606 m
->used_int_regs
|= 1 << frame_reg
;
609 sig
= m
->method
->signature
;
613 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
614 m
->ret
->opcode
= OP_REGVAR
;
615 m
->ret
->inst_c0
= ppc_r3
;
617 /* FIXME: handle long and FP values */
618 switch (sig
->ret
->type
) {
622 m
->ret
->opcode
= OP_REGVAR
;
623 m
->ret
->inst_c0
= ppc_r3
;
627 /* local vars are at a positive offset from the stack pointer */
629 * also note that if the function uses alloca, we use ppc_r31
630 * to point at the local variables.
632 offset
= PPC_MINIMAL_STACK_SIZE
; /* linkage area */
633 /* align the offset to 16 bytes: not sure this is needed here */
635 //offset &= ~(16 - 1);
637 /* add parameter area size for called functions */
638 offset
+= m
->param_area
;
642 /* allow room to save the return value */
643 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (m
->method
))
646 /* the MonoLMF structure is stored just below the stack pointer */
649 /* this stuff should not be needed on ppc and the new jit,
650 * because a call on ppc to the handlers doesn't change the
651 * stack pointer and the jist doesn't manipulate the stack pointer
652 * for operations involving valuetypes.
654 /* reserve space to store the esp */
655 offset
+= sizeof (gpointer
);
657 /* this is a global constant */
658 mono_exc_esp_offset
= offset
;
661 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
663 offset
+= sizeof(gpointer
) - 1;
664 offset
&= ~(sizeof(gpointer
) - 1);
665 inst
->inst_offset
= offset
;
666 inst
->opcode
= OP_REGOFFSET
;
667 inst
->inst_basereg
= frame_reg
;
668 offset
+= sizeof(gpointer
);
670 curinst
= m
->locals_start
;
671 for (i
= curinst
; i
< m
->num_varinfo
; ++i
) {
672 inst
= m
->varinfo
[i
];
673 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
)
676 /* inst->unused indicates native sized value types, this is used by the
677 * pinvoke wrappers when they call functions returning structure */
678 if (inst
->unused
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
)
679 size
= mono_class_native_size (inst
->inst_vtype
->data
.klass
, &align
);
681 size
= mono_type_size (inst
->inst_vtype
, &align
);
684 offset
&= ~(align
- 1);
685 inst
->inst_offset
= offset
;
686 inst
->opcode
= OP_REGOFFSET
;
687 inst
->inst_basereg
= frame_reg
;
689 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
694 inst
= m
->varinfo
[curinst
];
695 if (inst
->opcode
!= OP_REGVAR
) {
696 inst
->opcode
= OP_REGOFFSET
;
697 inst
->inst_basereg
= frame_reg
;
698 offset
+= sizeof (gpointer
) - 1;
699 offset
&= ~(sizeof (gpointer
) - 1);
700 inst
->inst_offset
= offset
;
701 offset
+= sizeof (gpointer
);
706 for (i
= 0; i
< sig
->param_count
; ++i
) {
707 inst
= m
->varinfo
[curinst
];
708 if (inst
->opcode
!= OP_REGVAR
) {
709 inst
->opcode
= OP_REGOFFSET
;
710 inst
->inst_basereg
= frame_reg
;
711 size
= mono_type_size (sig
->params
[i
], &align
);
713 offset
&= ~(align
- 1);
714 inst
->inst_offset
= offset
;
720 /* align the offset to 16 bytes */
725 m
->stack_offset
= offset
;
729 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
730 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
734 * take the arguments and generate the arch-specific
735 * instructions to properly call the function in call.
736 * This includes pushing, moving arguments to the right register
738 * Issue: who does the spilling if needed, and when?
741 mono_arch_call_opcode (MonoCompile
*cfg
, MonoBasicBlock
* bb
, MonoCallInst
*call
, int is_virtual
) {
743 MonoMethodSignature
*sig
;
748 sig
= call
->signature
;
749 n
= sig
->param_count
+ sig
->hasthis
;
751 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
752 if (cinfo
->struct_ret
)
753 call
->used_iregs
|= 1 << cinfo
->struct_ret
;
755 for (i
= 0; i
< n
; ++i
) {
756 ainfo
= cinfo
->args
+ i
;
757 if (is_virtual
&& i
== 0) {
758 /* the argument will be attached to the call instrucion */
760 call
->used_iregs
|= 1 << ainfo
->reg
;
762 MONO_INST_NEW (cfg
, arg
, OP_OUTARG
);
764 arg
->cil_code
= in
->cil_code
;
766 arg
->type
= in
->type
;
767 /* prepend, we'll need to reverse them later */
768 arg
->next
= call
->out_args
;
769 call
->out_args
= arg
;
770 if (ainfo
->regtype
== RegTypeGeneral
) {
771 arg
->unused
= ainfo
->reg
;
772 call
->used_iregs
|= 1 << ainfo
->reg
;
773 if (arg
->type
== STACK_I8
)
774 call
->used_iregs
|= 1 << (ainfo
->reg
+ 1);
775 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
776 /* FIXME: where si the data allocated? */
777 arg
->unused
= ainfo
->reg
;
778 call
->used_iregs
|= 1 << ainfo
->reg
;
779 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
781 /* mark the used regs */
782 for (cur_reg
= 0; cur_reg
< ainfo
->size
; ++cur_reg
) {
783 call
->used_iregs
|= 1 << (ainfo
->reg
+ cur_reg
);
785 arg
->opcode
= OP_OUTARG_VT
;
786 arg
->unused
= ainfo
->reg
| (ainfo
->size
<< 8) | (ainfo
->vtsize
<< 16);
787 arg
->inst_imm
= ainfo
->offset
;
788 } else if (ainfo
->regtype
== RegTypeBase
) {
789 arg
->opcode
= OP_OUTARG
;
790 arg
->unused
= ainfo
->reg
| (ainfo
->size
<< 8);
791 arg
->inst_imm
= ainfo
->offset
;
792 } else if (ainfo
->regtype
== RegTypeFP
) {
793 arg
->opcode
= OP_OUTARG_R8
;
794 arg
->unused
= ainfo
->reg
;
795 call
->used_fregs
|= 1 << ainfo
->reg
;
796 if (ainfo
->size
== 4) {
797 arg
->opcode
= OP_OUTARG_R8
;
798 /* we reduce the precision */
800 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
801 conv->inst_left = arg->inst_left;
802 arg->inst_left = conv;*/
805 g_assert_not_reached ();
810 * Reverse the call->out_args list.
813 MonoInst
*prev
= NULL
, *list
= call
->out_args
, *next
;
820 call
->out_args
= prev
;
822 call
->stack_usage
= cinfo
->stack_usage
;
823 cfg
->param_area
= MAX (cfg
->param_area
, cinfo
->stack_usage
);
824 cfg
->flags
|= MONO_CFG_HAS_CALLS
;
826 * should set more info in call, such as the stack space
827 * used by the args that needs to be added back to esp
835 * Allow tracing to work with this interface (with an optional argument)
839 * This may be needed on some archs or for debugging support.
842 mono_arch_instrument_mem_needs (MonoMethod
*method
, int *stack
, int *code
)
844 /* no stack room needed now (may be needed for FASTCALL-trace support) */
846 /* split prolog-epilog requirements? */
847 *code
= 50; /* max bytes needed: check this number */
851 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
855 ppc_load (code
, ppc_r3
, cfg
->method
);
856 ppc_li (code
, ppc_r4
, 0); /* NULL ebp for now */
857 ppc_load (code
, ppc_r0
, func
);
858 ppc_mtlr (code
, ppc_r0
);
872 mono_arch_instrument_epilog (MonoCompile
*cfg
, void *func
, void *p
, gboolean enable_arguments
)
875 int save_mode
= SAVE_NONE
;
876 MonoMethod
*method
= cfg
->method
;
877 int rtype
= method
->signature
->ret
->type
;
878 int save_offset
= PPC_STACK_PARAM_OFFSET
+ cfg
->param_area
;
885 /* special case string .ctor icall */
886 if (strcmp (".ctor", method
->name
) && method
->klass
== mono_defaults
.string_class
)
887 save_mode
= SAVE_ONE
;
889 save_mode
= SAVE_NONE
;
893 save_mode
= SAVE_TWO
;
899 case MONO_TYPE_VALUETYPE
:
900 if (method
->signature
->ret
->data
.klass
->enumtype
) {
901 rtype
= method
->signature
->ret
->data
.klass
->enum_basetype
->type
;
904 save_mode
= SAVE_STRUCT
;
907 save_mode
= SAVE_ONE
;
913 ppc_stw (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
914 ppc_stw (code
, ppc_r4
, save_offset
+ 4, cfg
->frame_reg
);
915 if (enable_arguments
) {
916 ppc_mr (code
, ppc_r5
, ppc_r4
);
917 ppc_mr (code
, ppc_r4
, ppc_r3
);
921 ppc_stw (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
922 if (enable_arguments
) {
923 ppc_mr (code
, ppc_r4
, ppc_r3
);
927 ppc_stfd (code
, ppc_f1
, save_offset
, cfg
->frame_reg
);
928 if (enable_arguments
) {
929 /* FIXME: what reg? */
930 ppc_fmr (code
, ppc_f3
, ppc_f1
);
931 ppc_lwz (code
, ppc_r4
, save_offset
, cfg
->frame_reg
);
932 ppc_lwz (code
, ppc_r5
, save_offset
+ 4, cfg
->frame_reg
);
936 if (enable_arguments
) {
937 /* FIXME: get the actual address */
938 ppc_mr (code
, ppc_r4
, ppc_r3
);
946 ppc_load (code
, ppc_r3
, cfg
->method
);
947 ppc_load (code
, ppc_r0
, func
);
948 ppc_mtlr (code
, ppc_r0
);
953 ppc_lwz (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
954 ppc_lwz (code
, ppc_r4
, save_offset
+ 4, cfg
->frame_reg
);
957 ppc_lwz (code
, ppc_r3
, save_offset
, cfg
->frame_reg
);
960 ppc_lfd (code
, ppc_f1
, save_offset
, cfg
->frame_reg
);
970 * Conditional branches have a small offset, so if it is likely overflowed,
971 * we do a branch to the end of the method (uncond branches have much larger
972 * offsets) where we perform the conditional and jump back unconditionally.
973 * It's slightly slower, since we add two uncond branches, but it's very simple
974 * with the current patch implementation and such large methods are likely not
975 * going to be perf critical anyway.
984 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
985 if (ins->flags & MONO_INST_BRLABEL) { \
986 if (0 && ins->inst_i0->inst_c0) { \
987 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
989 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
990 ppc_bc (code, (b0), (b1), 0); \
993 if (0 && ins->inst_true_bb->native_offset) { \
994 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
996 int br_disp = ins->inst_true_bb->max_offset - offset; \
997 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
998 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
999 ovfj->bb = ins->inst_true_bb; \
1001 ovfj->b0_cond = (b0); \
1002 ovfj->b1_cond = (b1); \
1003 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1006 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1007 ppc_bc (code, (b0), (b1), 0); \
1012 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1014 /* emit an exception if condition is fail
1016 * We assign the extra code used to throw the implicit exceptions
1017 * to cfg->bb_exit as far as the big branch handling is concerned
1019 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1021 int br_disp = cfg->bb_exit->max_offset - offset; \
1022 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1023 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1026 ovfj->b0_cond = (b0); \
1027 ovfj->b1_cond = (b1); \
1028 /* FIXME: test this code */ \
1029 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1031 cfg->bb_exit->max_offset += 24; \
1033 mono_add_patch_info (cfg, code - cfg->native_code, \
1034 MONO_PATCH_INFO_EXC, exc_name); \
1035 ppc_bc (code, (b0), (b1), 0); \
1039 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1042 peephole_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1044 MonoInst
*ins
, *last_ins
= NULL
;
1049 switch (ins
->opcode
) {
1051 /* remove unnecessary multiplication with 1 */
1052 if (ins
->inst_imm
== 1) {
1053 if (ins
->dreg
!= ins
->sreg1
) {
1054 ins
->opcode
= OP_MOVE
;
1056 last_ins
->next
= ins
->next
;
1061 int power2
= mono_is_power_of_two (ins
->inst_imm
);
1063 ins
->opcode
= OP_SHL_IMM
;
1064 ins
->inst_imm
= power2
;
1068 case OP_LOAD_MEMBASE
:
1069 case OP_LOADI4_MEMBASE
:
1071 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1072 * OP_LOAD_MEMBASE offset(basereg), reg
1074 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
1075 || last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
1076 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1077 ins
->inst_offset
== last_ins
->inst_offset
) {
1078 if (ins
->dreg
== last_ins
->sreg1
) {
1079 last_ins
->next
= ins
->next
;
1083 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1084 ins
->opcode
= OP_MOVE
;
1085 ins
->sreg1
= last_ins
->sreg1
;
1089 * Note: reg1 must be different from the basereg in the second load
1090 * OP_LOAD_MEMBASE offset(basereg), reg1
1091 * OP_LOAD_MEMBASE offset(basereg), reg2
1093 * OP_LOAD_MEMBASE offset(basereg), reg1
1094 * OP_MOVE reg1, reg2
1096 } if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
1097 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
1098 ins
->inst_basereg
!= last_ins
->dreg
&&
1099 ins
->inst_basereg
== last_ins
->inst_basereg
&&
1100 ins
->inst_offset
== last_ins
->inst_offset
) {
1102 if (ins
->dreg
== last_ins
->dreg
) {
1103 last_ins
->next
= ins
->next
;
1107 ins
->opcode
= OP_MOVE
;
1108 ins
->sreg1
= last_ins
->dreg
;
1111 //g_assert_not_reached ();
1115 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1116 * OP_LOAD_MEMBASE offset(basereg), reg
1118 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1119 * OP_ICONST reg, imm
1121 } else if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_IMM
1122 || last_ins
->opcode
== OP_STORE_MEMBASE_IMM
) &&
1123 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1124 ins
->inst_offset
== last_ins
->inst_offset
) {
1125 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1126 ins
->opcode
= OP_ICONST
;
1127 ins
->inst_c0
= last_ins
->inst_imm
;
1128 g_assert_not_reached (); // check this rule
1132 case OP_LOADU1_MEMBASE
:
1133 case OP_LOADI1_MEMBASE
:
1134 if (last_ins
&& (last_ins
->opcode
== OP_STOREI1_MEMBASE_REG
) &&
1135 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1136 ins
->inst_offset
== last_ins
->inst_offset
) {
1137 if (ins
->dreg
== last_ins
->sreg1
) {
1138 last_ins
->next
= ins
->next
;
1142 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1143 ins
->opcode
= OP_MOVE
;
1144 ins
->sreg1
= last_ins
->sreg1
;
1148 case OP_LOADU2_MEMBASE
:
1149 case OP_LOADI2_MEMBASE
:
1150 if (last_ins
&& (last_ins
->opcode
== OP_STOREI2_MEMBASE_REG
) &&
1151 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
1152 ins
->inst_offset
== last_ins
->inst_offset
) {
1153 if (ins
->dreg
== last_ins
->sreg1
) {
1154 last_ins
->next
= ins
->next
;
1158 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1159 ins
->opcode
= OP_MOVE
;
1160 ins
->sreg1
= last_ins
->sreg1
;
1168 ins
->opcode
= OP_MOVE
;
1172 if (ins
->dreg
== ins
->sreg1
) {
1174 last_ins
->next
= ins
->next
;
1179 * OP_MOVE sreg, dreg
1180 * OP_MOVE dreg, sreg
1182 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
1183 ins
->sreg1
== last_ins
->dreg
&&
1184 ins
->dreg
== last_ins
->sreg1
) {
1185 last_ins
->next
= ins
->next
;
1194 bb
->last_ins
= last_ins
;
1198 * the branch_b0_table should maintain the order of these
1212 branch_b0_table
[] = {
1227 branch_b1_table
[] = {
1242 * returns the offset used by spillvar. It allocates a new
1243 * spill variable if necessary.
1246 mono_spillvar_offset (MonoCompile
*cfg
, int spillvar
)
1248 MonoSpillInfo
**si
, *info
;
1251 si
= &cfg
->spill_info
;
1253 while (i
<= spillvar
) {
1256 *si
= info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
));
1258 info
->offset
= cfg
->stack_offset
;
1259 cfg
->stack_offset
+= sizeof (gpointer
);
1263 return (*si
)->offset
;
1269 g_assert_not_reached ();
1274 mono_spillvar_offset_float (MonoCompile
*cfg
, int spillvar
)
1276 MonoSpillInfo
**si
, *info
;
1279 si
= &cfg
->spill_info_float
;
1281 while (i
<= spillvar
) {
1284 *si
= info
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoSpillInfo
));
1286 cfg
->stack_offset
+= 7;
1287 cfg
->stack_offset
&= ~7;
1288 info
->offset
= cfg
->stack_offset
;
1289 cfg
->stack_offset
+= sizeof (double);
1293 return (*si
)->offset
;
1299 g_assert_not_reached ();
1304 #define DEBUG(a) if (cfg->verbose_level > 1) a
1306 /* use ppc_r3-ppc_10,ppc_r12 as temp registers, f1-f13 for FP registers */
1307 #define PPC_CALLER_REGS ((0xff<<3) | (1<<12) | USE_EXTRA_TEMPS)
1308 #define PPC_CALLER_FREGS (0x3ffe)
1310 #define reg_is_freeable(r) (PPC_CALLER_REGS & 1 << (r))
1311 #define freg_is_freeable(r) ((r) >= 1 && (r) <= 13)
1320 static const char*const * ins_spec
= ppcg4
;
1323 print_ins (int i
, MonoInst
*ins
)
1325 const char *spec
= ins_spec
[ins
->opcode
];
1326 g_print ("\t%-2d %s", i
, mono_inst_name (ins
->opcode
));
1327 if (spec
[MONO_INST_DEST
]) {
1328 if (ins
->dreg
>= MONO_MAX_IREGS
)
1329 g_print (" R%d <-", ins
->dreg
);
1331 g_print (" %s <-", mono_arch_regname (ins
->dreg
));
1333 if (spec
[MONO_INST_SRC1
]) {
1334 if (ins
->sreg1
>= MONO_MAX_IREGS
)
1335 g_print (" R%d", ins
->sreg1
);
1337 g_print (" %s", mono_arch_regname (ins
->sreg1
));
1339 if (spec
[MONO_INST_SRC2
]) {
1340 if (ins
->sreg2
>= MONO_MAX_IREGS
)
1341 g_print (" R%d", ins
->sreg2
);
1343 g_print (" %s", mono_arch_regname (ins
->sreg2
));
1345 if (spec
[MONO_INST_CLOB
])
1346 g_print (" clobbers: %c", spec
[MONO_INST_CLOB
]);
1351 print_regtrack (RegTrack
*t
, int num
)
1357 for (i
= 0; i
< num
; ++i
) {
1360 if (i
>= MONO_MAX_IREGS
) {
1361 g_snprintf (buf
, sizeof(buf
), "R%d", i
);
1364 r
= mono_arch_regname (i
);
1365 g_print ("liveness: %s [%d - %d]\n", r
, t
[i
].born_in
, t
[i
].last_use
);
1369 typedef struct InstList InstList
;
1377 static inline InstList
*
1378 inst_list_prepend (MonoMemPool
*pool
, InstList
*list
, MonoInst
*data
)
1380 InstList
*item
= mono_mempool_alloc (pool
, sizeof (InstList
));
1390 * Force the spilling of the variable in the symbolic register 'reg'.
1393 get_register_force_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, int reg
)
1398 sel
= cfg
->rs
->iassign
[reg
];
1399 /*i = cfg->rs->isymbolic [sel];
1400 g_assert (i == reg);*/
1402 spill
= ++cfg
->spill_count
;
1403 cfg
->rs
->iassign
[i
] = -spill
- 1;
1404 mono_regstate_free_int (cfg
->rs
, sel
);
1405 /* we need to create a spill var and insert a load to sel after the current instruction */
1406 MONO_INST_NEW (cfg
, load
, OP_LOAD_MEMBASE
);
1408 load
->inst_basereg
= cfg
->frame_reg
;
1409 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
1411 while (ins
->next
!= item
->prev
->data
)
1414 load
->next
= ins
->next
;
1416 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
1417 i
= mono_regstate_alloc_int (cfg
->rs
, 1 << sel
);
1418 g_assert (i
== sel
);
1424 get_register_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, guint32 regmask
, int reg
)
1429 DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg
, regmask
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
));
1430 /* exclude the registers in the current instruction */
1431 if (reg
!= ins
->sreg1
&& (reg_is_freeable (ins
->sreg1
) || (ins
->sreg1
>= MONO_MAX_IREGS
&& cfg
->rs
->iassign
[ins
->sreg1
] >= 0))) {
1432 if (ins
->sreg1
>= MONO_MAX_IREGS
)
1433 regmask
&= ~ (1 << cfg
->rs
->iassign
[ins
->sreg1
]);
1435 regmask
&= ~ (1 << ins
->sreg1
);
1436 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins
->sreg1
)));
1438 if (reg
!= ins
->sreg2
&& (reg_is_freeable (ins
->sreg2
) || (ins
->sreg2
>= MONO_MAX_IREGS
&& cfg
->rs
->iassign
[ins
->sreg2
] >= 0))) {
1439 if (ins
->sreg2
>= MONO_MAX_IREGS
)
1440 regmask
&= ~ (1 << cfg
->rs
->iassign
[ins
->sreg2
]);
1442 regmask
&= ~ (1 << ins
->sreg2
);
1443 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins
->sreg2
), ins
->sreg2
));
1445 if (reg
!= ins
->dreg
&& reg_is_freeable (ins
->dreg
)) {
1446 regmask
&= ~ (1 << ins
->dreg
);
1447 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins
->dreg
)));
1450 DEBUG (g_print ("available regmask: 0x%08x\n", regmask
));
1451 g_assert (regmask
); /* need at least a register we can free */
1453 /* we should track prev_use and spill the register that's farther */
1454 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
) {
1455 if (regmask
& (1 << i
)) {
1457 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel
), cfg
->rs
->iassign
[sel
]));
1461 i
= cfg
->rs
->isymbolic
[sel
];
1462 spill
= ++cfg
->spill_count
;
1463 cfg
->rs
->iassign
[i
] = -spill
- 1;
1464 mono_regstate_free_int (cfg
->rs
, sel
);
1465 /* we need to create a spill var and insert a load to sel after the current instruction */
1466 MONO_INST_NEW (cfg
, load
, OP_LOAD_MEMBASE
);
1468 load
->inst_basereg
= cfg
->frame_reg
;
1469 load
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
1471 while (ins
->next
!= item
->prev
->data
)
1474 load
->next
= ins
->next
;
1476 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
1477 i
= mono_regstate_alloc_int (cfg
->rs
, 1 << sel
);
1478 g_assert (i
== sel
);
1484 get_float_register_spilling (MonoCompile
*cfg
, InstList
*item
, MonoInst
*ins
, guint32 regmask
, int reg
)
1489 DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg
, regmask
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
));
1490 /* exclude the registers in the current instruction */
1491 if (reg
!= ins
->sreg1
&& (freg_is_freeable (ins
->sreg1
) || (ins
->sreg1
>= MONO_MAX_FREGS
&& cfg
->rs
->fassign
[ins
->sreg1
] >= 0))) {
1492 if (ins
->sreg1
>= MONO_MAX_FREGS
)
1493 regmask
&= ~ (1 << cfg
->rs
->fassign
[ins
->sreg1
]);
1495 regmask
&= ~ (1 << ins
->sreg1
);
1496 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins
->sreg1
)));
1498 if (reg
!= ins
->sreg2
&& (freg_is_freeable (ins
->sreg2
) || (ins
->sreg2
>= MONO_MAX_FREGS
&& cfg
->rs
->fassign
[ins
->sreg2
] >= 0))) {
1499 if (ins
->sreg2
>= MONO_MAX_FREGS
)
1500 regmask
&= ~ (1 << cfg
->rs
->fassign
[ins
->sreg2
]);
1502 regmask
&= ~ (1 << ins
->sreg2
);
1503 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins
->sreg2
), ins
->sreg2
));
1505 if (reg
!= ins
->dreg
&& freg_is_freeable (ins
->dreg
)) {
1506 regmask
&= ~ (1 << ins
->dreg
);
1507 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins
->dreg
)));
1510 DEBUG (g_print ("available regmask: 0x%08x\n", regmask
));
1511 g_assert (regmask
); /* need at least a register we can free */
1513 /* we should track prev_use and spill the register that's farther */
1514 for (i
= 0; i
< MONO_MAX_FREGS
; ++i
) {
1515 if (regmask
& (1 << i
)) {
1517 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel
), cfg
->rs
->fassign
[sel
]));
1521 i
= cfg
->rs
->fsymbolic
[sel
];
1522 spill
= ++cfg
->spill_count
;
1523 cfg
->rs
->fassign
[i
] = -spill
- 1;
1524 mono_regstate_free_float(cfg
->rs
, sel
);
1525 /* we need to create a spill var and insert a load to sel after the current instruction */
1526 MONO_INST_NEW (cfg
, load
, OP_LOADR8_MEMBASE
);
1528 load
->inst_basereg
= cfg
->frame_reg
;
1529 load
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
1531 while (ins
->next
!= item
->prev
->data
)
1534 load
->next
= ins
->next
;
1536 DEBUG (g_print ("SPILLED LOAD FP (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill
, load
->inst_offset
, i
, mono_arch_regname (sel
)));
1537 i
= mono_regstate_alloc_float (cfg
->rs
, 1 << sel
);
1538 g_assert (i
== sel
);
1544 create_copy_ins (MonoCompile
*cfg
, int dest
, int src
, MonoInst
*ins
)
1547 MONO_INST_NEW (cfg
, copy
, OP_MOVE
);
1551 copy
->next
= ins
->next
;
1554 DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src
), mono_arch_regname (dest
)));
1559 create_copy_ins_float (MonoCompile
*cfg
, int dest
, int src
, MonoInst
*ins
)
1562 MONO_INST_NEW (cfg
, copy
, OP_FMOVE
);
1566 copy
->next
= ins
->next
;
1569 DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src
), mono_arch_regname (dest
)));
1574 create_spilled_store (MonoCompile
*cfg
, int spill
, int reg
, int prev_reg
, MonoInst
*ins
)
1577 MONO_INST_NEW (cfg
, store
, OP_STORE_MEMBASE_REG
);
1579 store
->inst_destbasereg
= cfg
->frame_reg
;
1580 store
->inst_offset
= mono_spillvar_offset (cfg
, spill
);
1582 store
->next
= ins
->next
;
1585 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill
, store
->inst_offset
, prev_reg
, mono_arch_regname (reg
)));
1590 create_spilled_store_float (MonoCompile
*cfg
, int spill
, int reg
, int prev_reg
, MonoInst
*ins
)
1593 MONO_INST_NEW (cfg
, store
, OP_STORER8_MEMBASE_REG
);
1595 store
->inst_destbasereg
= cfg
->frame_reg
;
1596 store
->inst_offset
= mono_spillvar_offset_float (cfg
, spill
);
1598 store
->next
= ins
->next
;
1601 DEBUG (g_print ("SPILLED STORE FP (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill
, store
->inst_offset
, prev_reg
, mono_arch_regname (reg
)));
1606 insert_before_ins (MonoInst
*ins
, InstList
*item
, MonoInst
* to_insert
)
1609 g_assert (item
->next
);
1610 prev
= item
->next
->data
;
1612 while (prev
->next
!= ins
)
1614 to_insert
->next
= ins
;
1615 prev
->next
= to_insert
;
1617 * needed otherwise in the next instruction we can add an ins to the
1618 * end and that would get past this instruction.
1620 item
->data
= to_insert
;
1624 alloc_int_reg (MonoCompile
*cfg
, InstList
*curinst
, MonoInst
*ins
, int sym_reg
, guint32 allow_mask
)
1626 int val
= cfg
->rs
->iassign
[sym_reg
];
1630 /* the register gets spilled after this inst */
1633 val
= mono_regstate_alloc_int (cfg
->rs
, allow_mask
);
1635 val
= get_register_spilling (cfg
, curinst
, ins
, allow_mask
, sym_reg
);
1636 cfg
->rs
->iassign
[sym_reg
] = val
;
1637 /* add option to store before the instruction for src registers */
1639 create_spilled_store (cfg
, spill
, val
, sym_reg
, ins
);
1641 cfg
->rs
->isymbolic
[val
] = sym_reg
;
1646 * Local register allocation.
1647 * We first scan the list of instructions and we save the liveness info of
1648 * each register (when the register is first used, when it's value is set etc.).
1649 * We also reverse the list of instructions (in the InstList list) because assigning
1650 * registers backwards allows for more tricks to be used.
1653 mono_arch_local_regalloc (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
1656 MonoRegState
*rs
= cfg
->rs
;
1658 RegTrack
*reginfo
, *reginfof
;
1659 RegTrack
*reginfo1
, *reginfo2
, *reginfod
;
1660 InstList
*tmp
, *reversed
= NULL
;
1662 guint32 src1_mask
, src2_mask
, dest_mask
;
1663 guint32 cur_iregs
, cur_fregs
;
1667 rs
->next_vireg
= bb
->max_ireg
;
1668 rs
->next_vfreg
= bb
->max_freg
;
1669 mono_regstate_assign (rs
);
1670 reginfo
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (RegTrack
) * rs
->next_vireg
);
1671 reginfof
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (RegTrack
) * rs
->next_vfreg
);
1672 rs
->ifree_mask
= PPC_CALLER_REGS
;
1673 rs
->ffree_mask
= PPC_CALLER_FREGS
;
1677 DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb
->block_num
));
1678 /* forward pass on the instructions to collect register liveness info */
1680 spec
= ins_spec
[ins
->opcode
];
1681 DEBUG (print_ins (i
, ins
));
1682 /*if (spec [MONO_INST_CLOB] == 'c') {
1683 MonoCallInst * call = (MonoCallInst*)ins;
1686 if (spec
[MONO_INST_SRC1
]) {
1687 if (spec
[MONO_INST_SRC1
] == 'f')
1688 reginfo1
= reginfof
;
1691 reginfo1
[ins
->sreg1
].prev_use
= reginfo1
[ins
->sreg1
].last_use
;
1692 reginfo1
[ins
->sreg1
].last_use
= i
;
1696 if (spec
[MONO_INST_SRC2
]) {
1697 if (spec
[MONO_INST_SRC2
] == 'f')
1698 reginfo2
= reginfof
;
1701 reginfo2
[ins
->sreg2
].prev_use
= reginfo2
[ins
->sreg2
].last_use
;
1702 reginfo2
[ins
->sreg2
].last_use
= i
;
1706 if (spec
[MONO_INST_DEST
]) {
1707 if (spec
[MONO_INST_DEST
] == 'f')
1708 reginfod
= reginfof
;
1711 if (spec
[MONO_INST_DEST
] != 'b') /* it's not just a base register */
1712 reginfod
[ins
->dreg
].killed_in
= i
;
1713 reginfod
[ins
->dreg
].prev_use
= reginfod
[ins
->dreg
].last_use
;
1714 reginfod
[ins
->dreg
].last_use
= i
;
1715 if (reginfod
[ins
->dreg
].born_in
== 0 || reginfod
[ins
->dreg
].born_in
> i
)
1716 reginfod
[ins
->dreg
].born_in
= i
;
1717 if (spec
[MONO_INST_DEST
] == 'l') {
1718 /* result in eax:edx, the virtual register is allocated sequentially */
1719 reginfod
[ins
->dreg
+ 1].prev_use
= reginfod
[ins
->dreg
+ 1].last_use
;
1720 reginfod
[ins
->dreg
+ 1].last_use
= i
;
1721 if (reginfod
[ins
->dreg
+ 1].born_in
== 0 || reginfod
[ins
->dreg
+ 1].born_in
> i
)
1722 reginfod
[ins
->dreg
+ 1].born_in
= i
;
1727 reversed
= inst_list_prepend (cfg
->mempool
, reversed
, ins
);
1732 cur_iregs
= PPC_CALLER_REGS
;
1733 cur_fregs
= PPC_CALLER_FREGS
;
1735 DEBUG (print_regtrack (reginfo
, rs
->next_vireg
));
1736 DEBUG (print_regtrack (reginfof
, rs
->next_vfreg
));
1739 int prev_dreg
, prev_sreg1
, prev_sreg2
;
1742 spec
= ins_spec
[ins
->opcode
];
1743 DEBUG (g_print ("processing:"));
1744 DEBUG (print_ins (i
, ins
));
1745 /* make the register available for allocation: FIXME add fp reg */
1746 if (ins
->opcode
== OP_SETREG
|| ins
->opcode
== OP_SETREGIMM
) {
1747 cur_iregs
|= 1 << ins
->dreg
;
1748 DEBUG (g_print ("adding %d to cur_iregs\n", ins
->dreg
));
1749 } else if (ins
->opcode
== OP_SETFREG
) {
1750 cur_fregs
|= 1 << ins
->dreg
;
1751 DEBUG (g_print ("adding %d to cur_fregs\n", ins
->dreg
));
1752 } else if (spec
[MONO_INST_CLOB
] == 'c') {
1753 MonoCallInst
*cinst
= (MonoCallInst
*)ins
;
1754 DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst
->used_iregs
, cur_iregs
));
1755 DEBUG (g_print ("excluding fpregs 0x%x from cur_fregs (0x%x)\n", cinst
->used_fregs
, cur_fregs
));
1756 cur_iregs
&= ~cinst
->used_iregs
;
1757 cur_fregs
&= ~cinst
->used_fregs
;
1758 DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs
));
1759 DEBUG (g_print ("available cur_fregs: 0x%x\n", cur_fregs
));
1760 /* registers used by the calling convention are excluded from
1761 * allocation: they will be selectively enabled when they are
1762 * assigned by the special SETREG opcodes.
1765 dest_mask
= src1_mask
= src2_mask
= cur_iregs
;
1766 /* update for use with FP regs... */
1767 if (spec
[MONO_INST_DEST
] == 'f') {
1768 dest_mask
= cur_fregs
;
1769 if (ins
->dreg
>= MONO_MAX_FREGS
) {
1770 val
= rs
->fassign
[ins
->dreg
];
1771 prev_dreg
= ins
->dreg
;
1775 /* the register gets spilled after this inst */
1778 val
= mono_regstate_alloc_float (rs
, dest_mask
);
1780 val
= get_float_register_spilling (cfg
, tmp
, ins
, dest_mask
, ins
->dreg
);
1781 rs
->fassign
[ins
->dreg
] = val
;
1783 create_spilled_store_float (cfg
, spill
, val
, prev_dreg
, ins
);
1785 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val
), ins
->dreg
));
1786 rs
->fsymbolic
[val
] = prev_dreg
;
1788 if (spec
[MONO_INST_CLOB
] == 'c' && ins
->dreg
!= ppc_f1
) {
1789 /* this instruction only outputs to ppc_f1, need to copy */
1790 create_copy_ins_float (cfg
, ins
->dreg
, ppc_f1
, ins
);
1795 if (freg_is_freeable (ins
->dreg
) && prev_dreg
>= 0 && (reginfof
[prev_dreg
].born_in
>= i
|| !(cur_fregs
& (1 << ins
->dreg
)))) {
1796 DEBUG (g_print ("\tfreeable float %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfof
[prev_dreg
].born_in
));
1797 mono_regstate_free_float (rs
, ins
->dreg
);
1799 } else if (ins
->dreg
>= MONO_MAX_IREGS
) {
1800 val
= rs
->iassign
[ins
->dreg
];
1801 prev_dreg
= ins
->dreg
;
1805 /* the register gets spilled after this inst */
1808 val
= mono_regstate_alloc_int (rs
, dest_mask
);
1810 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, ins
->dreg
);
1811 rs
->iassign
[ins
->dreg
] = val
;
1813 create_spilled_store (cfg
, spill
, val
, prev_dreg
, ins
);
1815 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val
), ins
->dreg
));
1816 rs
->isymbolic
[val
] = prev_dreg
;
1818 if (spec
[MONO_INST_DEST
] == 'l') {
1819 int hreg
= prev_dreg
+ 1;
1820 val
= rs
->iassign
[hreg
];
1824 /* the register gets spilled after this inst */
1827 val
= mono_regstate_alloc_int (rs
, dest_mask
);
1829 val
= get_register_spilling (cfg
, tmp
, ins
, dest_mask
, hreg
);
1830 rs
->iassign
[hreg
] = val
;
1832 create_spilled_store (cfg
, spill
, val
, hreg
, ins
);
1834 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val
), hreg
));
1835 rs
->isymbolic
[val
] = hreg
;
1836 /* FIXME:? ins->dreg = val; */
1837 if (ins
->dreg
== ppc_r4
) {
1839 create_copy_ins (cfg
, val
, ppc_r3
, ins
);
1840 } else if (ins
->dreg
== ppc_r3
) {
1841 if (val
== ppc_r4
) {
1843 create_copy_ins (cfg
, ppc_r4
, ppc_r0
, ins
);
1844 create_copy_ins (cfg
, ppc_r3
, ppc_r4
, ins
);
1845 create_copy_ins (cfg
, ppc_r0
, ppc_r3
, ins
);
1847 /* two forced copies */
1848 create_copy_ins (cfg
, ins
->dreg
, ppc_r4
, ins
);
1849 create_copy_ins (cfg
, val
, ppc_r3
, ins
);
1852 if (val
== ppc_r3
) {
1853 create_copy_ins (cfg
, ins
->dreg
, ppc_r4
, ins
);
1855 /* two forced copies */
1856 create_copy_ins (cfg
, val
, ppc_r3
, ins
);
1857 create_copy_ins (cfg
, ins
->dreg
, ppc_r4
, ins
);
1860 if (reg_is_freeable (val
) && hreg
>= 0 && (reginfo
[hreg
].born_in
>= i
&& !(cur_iregs
& (1 << val
)))) {
1861 DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val
), hreg
));
1862 mono_regstate_free_int (rs
, val
);
1864 } else if (spec
[MONO_INST_DEST
] == 'a' && ins
->dreg
!= ppc_r3
&& spec
[MONO_INST_CLOB
] != 'd') {
1865 /* this instruction only outputs to ppc_r3, need to copy */
1866 create_copy_ins (cfg
, ins
->dreg
, ppc_r3
, ins
);
1871 if (spec
[MONO_INST_DEST
] == 'f' && freg_is_freeable (ins
->dreg
) && prev_dreg
>= 0 && (reginfof
[prev_dreg
].born_in
>= i
)) {
1872 DEBUG (g_print ("\tfreeable float %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfof
[prev_dreg
].born_in
));
1873 mono_regstate_free_float (rs
, ins
->dreg
);
1874 } else if (spec
[MONO_INST_DEST
] != 'f' && reg_is_freeable (ins
->dreg
) && prev_dreg
>= 0 && (reginfo
[prev_dreg
].born_in
>= i
)) {
1875 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins
->dreg
), prev_dreg
, reginfo
[prev_dreg
].born_in
));
1876 mono_regstate_free_int (rs
, ins
->dreg
);
1878 if (spec
[MONO_INST_SRC1
] == 'f') {
1879 src1_mask
= cur_fregs
;
1880 if (ins
->sreg1
>= MONO_MAX_FREGS
) {
1881 val
= rs
->fassign
[ins
->sreg1
];
1882 prev_sreg1
= ins
->sreg1
;
1886 /* the register gets spilled after this inst */
1889 //g_assert (val == -1); /* source cannot be spilled */
1890 val
= mono_regstate_alloc_float (rs
, src1_mask
);
1892 val
= get_float_register_spilling (cfg
, tmp
, ins
, src1_mask
, ins
->sreg1
);
1893 rs
->fassign
[ins
->sreg1
] = val
;
1894 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val
), ins
->sreg1
));
1896 MonoInst
*store
= create_spilled_store_float (cfg
, spill
, val
, prev_sreg1
, NULL
);
1897 insert_before_ins (ins
, tmp
, store
);
1900 rs
->fsymbolic
[val
] = prev_sreg1
;
1905 } else if (ins
->sreg1
>= MONO_MAX_IREGS
) {
1906 val
= rs
->iassign
[ins
->sreg1
];
1907 prev_sreg1
= ins
->sreg1
;
1911 /* the register gets spilled after this inst */
1914 if (0 && ins
->opcode
== OP_MOVE
) {
1916 * small optimization: the dest register is already allocated
1917 * but the src one is not: we can simply assign the same register
1918 * here and peephole will get rid of the instruction later.
1919 * This optimization may interfere with the clobbering handling:
1920 * it removes a mov operation that will be added again to handle clobbering.
1921 * There are also some other issues that should with make testjit.
1923 mono_regstate_alloc_int (rs
, 1 << ins
->dreg
);
1924 val
= rs
->iassign
[ins
->sreg1
] = ins
->dreg
;
1925 //g_assert (val >= 0);
1926 DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val
), ins
->sreg1
));
1928 //g_assert (val == -1); /* source cannot be spilled */
1929 val
= mono_regstate_alloc_int (rs
, src1_mask
);
1931 val
= get_register_spilling (cfg
, tmp
, ins
, src1_mask
, ins
->sreg1
);
1932 rs
->iassign
[ins
->sreg1
] = val
;
1933 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val
), ins
->sreg1
));
1936 MonoInst
*store
= create_spilled_store (cfg
, spill
, val
, prev_sreg1
, NULL
);
1937 insert_before_ins (ins
, tmp
, store
);
1940 rs
->isymbolic
[val
] = prev_sreg1
;
1945 if (spec
[MONO_INST_SRC2
] == 'f') {
1946 src2_mask
= cur_fregs
;
1947 if (ins
->sreg2
>= MONO_MAX_FREGS
) {
1948 val
= rs
->fassign
[ins
->sreg2
];
1949 prev_sreg2
= ins
->sreg2
;
1953 /* the register gets spilled after this inst */
1956 val
= mono_regstate_alloc_float (rs
, src2_mask
);
1958 val
= get_float_register_spilling (cfg
, tmp
, ins
, src2_mask
, ins
->sreg2
);
1959 rs
->fassign
[ins
->sreg2
] = val
;
1960 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val
), ins
->sreg2
));
1962 create_spilled_store_float (cfg
, spill
, val
, prev_sreg2
, ins
);
1964 rs
->fsymbolic
[val
] = prev_sreg2
;
1969 } else if (ins
->sreg2
>= MONO_MAX_IREGS
) {
1970 val
= rs
->iassign
[ins
->sreg2
];
1971 prev_sreg2
= ins
->sreg2
;
1975 /* the register gets spilled after this inst */
1978 val
= mono_regstate_alloc_int (rs
, src2_mask
);
1980 val
= get_register_spilling (cfg
, tmp
, ins
, src2_mask
, ins
->sreg2
);
1981 rs
->iassign
[ins
->sreg2
] = val
;
1982 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val
), ins
->sreg2
));
1984 create_spilled_store (cfg
, spill
, val
, prev_sreg2
, ins
);
1986 rs
->isymbolic
[val
] = prev_sreg2
;
1992 if (spec
[MONO_INST_CLOB
] == 'c') {
1994 guint32 clob_mask
= PPC_CALLER_REGS
;
1995 for (j
= 0; j
< MONO_MAX_IREGS
; ++j
) {
1997 if ((clob_mask
& s
) && !(rs
->ifree_mask
& s
) && j
!= ins
->sreg1
) {
1998 //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
2002 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
2003 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2004 mono_regstate_free_int (rs, ins->sreg1);
2006 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2007 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2008 mono_regstate_free_int (rs, ins->sreg2);
2011 //DEBUG (print_ins (i, ins));
2014 cfg
->max_ireg
= MAX (cfg
->max_ireg
, rs
->max_ireg
);
2018 emit_float_to_int (MonoCompile
*cfg
, guchar
*code
, int dreg
, int sreg
, int size
, gboolean is_signed
)
2020 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2021 ppc_fctiwz (code
, ppc_f0
, sreg
);
2022 ppc_stfd (code
, ppc_f0
, -8, ppc_sp
);
2023 ppc_lwz (code
, dreg
, -4, ppc_sp
);
2026 ppc_andid (code
, dreg
, dreg
, 0xff);
2028 ppc_andid (code
, dreg
, dreg
, 0xffff);
2031 ppc_extsb (code
, dreg
, dreg
);
2033 ppc_extsh (code
, dreg
, dreg
);
2038 static unsigned char*
2039 mono_emit_stack_alloc (guchar
*code
, MonoInst
* tree
)
2042 int sreg
= tree
->sreg1
;
2043 x86_alu_reg_reg (code
, X86_SUB
, X86_ESP
, tree
->sreg1
);
2044 if (tree
->flags
& MONO_INST_INIT
) {
2046 if (tree
->dreg
!= X86_EAX
&& sreg
!= X86_EAX
) {
2047 x86_push_reg (code
, X86_EAX
);
2050 if (tree
->dreg
!= X86_ECX
&& sreg
!= X86_ECX
) {
2051 x86_push_reg (code
, X86_ECX
);
2054 if (tree
->dreg
!= X86_EDI
&& sreg
!= X86_EDI
) {
2055 x86_push_reg (code
, X86_EDI
);
2059 x86_shift_reg_imm (code
, X86_SHR
, sreg
, 2);
2060 if (sreg
!= X86_ECX
)
2061 x86_mov_reg_reg (code
, X86_ECX
, sreg
, 4);
2062 x86_alu_reg_reg (code
, X86_XOR
, X86_EAX
, X86_EAX
);
2064 x86_lea_membase (code
, X86_EDI
, X86_ESP
, offset
);
2066 x86_prefix (code
, X86_REP_PREFIX
);
2069 if (tree
->dreg
!= X86_EDI
&& sreg
!= X86_EDI
)
2070 x86_pop_reg (code
, X86_EDI
);
2071 if (tree
->dreg
!= X86_ECX
&& sreg
!= X86_ECX
)
2072 x86_pop_reg (code
, X86_ECX
);
2073 if (tree
->dreg
!= X86_EAX
&& sreg
!= X86_EAX
)
2074 x86_pop_reg (code
, X86_EAX
);
2087 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2090 search_thunk_slot (void *data
, int csize
, int bsize
, void *user_data
) {
2091 PatchData
*pdata
= (PatchData
*)user_data
;
2092 guchar
*code
= data
;
2093 guint32
*thunks
= data
;
2094 guint32
*endthunks
= (guint32
*)(code
+ bsize
);
2098 int difflow
, diffhigh
;
2100 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2101 difflow
= (char*)pdata
->code
- (char*)thunks
;
2102 diffhigh
= (char*)pdata
->code
- (char*)endthunks
;
2103 if (!((is_call_imm (thunks
) && is_call_imm (endthunks
)) || (is_call_imm (difflow
) && is_call_imm (diffhigh
))))
2106 templ
= (guchar
*)load
;
2107 ppc_lis (templ
, ppc_r0
, (guint32
)(pdata
->target
) >> 16);
2108 ppc_ori (templ
, ppc_r0
, ppc_r0
, (guint32
)(pdata
->target
) & 0xffff);
2110 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2111 if ((pdata
->found
== 2) || (pdata
->code
>= code
&& pdata
->code
<= code
+ csize
)) {
2112 while (thunks
< endthunks
) {
2113 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2114 if ((thunks
[0] == load
[0]) && (thunks
[1] == load
[1])) {
2115 ppc_patch (pdata
->code
, (guchar
*)thunks
);
2116 mono_arch_flush_icache (pdata
->code
, 4);
2119 } else if ((thunks
[0] == 0) && (thunks
[1] == 0)) {
2120 /* found a free slot instead: emit thunk */
2121 code
= (guchar
*)thunks
;
2122 ppc_lis (code
, ppc_r0
, (guint32
)(pdata
->target
) >> 16);
2123 ppc_ori (code
, ppc_r0
, ppc_r0
, (guint32
)(pdata
->target
) & 0xffff);
2124 ppc_mtctr (code
, ppc_r0
);
2125 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
2126 mono_arch_flush_icache ((guchar
*)thunks
, 16);
2128 ppc_patch (pdata
->code
, (guchar
*)thunks
);
2129 mono_arch_flush_icache (pdata
->code
, 4);
2133 /* skip 16 bytes, the size of the thunk */
2137 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2143 handle_thunk (int absolute
, guchar
*code
, guchar
*target
) {
2144 MonoDomain
*domain
= mono_domain_get ();
2148 pdata
.target
= target
;
2149 pdata
.absolute
= absolute
;
2152 mono_domain_lock (domain
);
2153 mono_code_manager_foreach (domain
->code_mp
, search_thunk_slot
, &pdata
);
2156 /* this uses the first available slot */
2158 mono_code_manager_foreach (domain
->code_mp
, search_thunk_slot
, &pdata
);
2160 mono_domain_unlock (domain
);
2162 if (pdata
.found
!= 1)
2163 g_print ("thunk failed for %p from %p\n", target
, code
);
2164 g_assert (pdata
.found
== 1);
2168 ppc_patch (guchar
*code
, guchar
*target
)
2170 guint32 ins
= *(guint32
*)code
;
2171 guint32 prim
= ins
>> 26;
2174 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2176 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2177 gint diff
= target
- code
;
2179 if (diff
<= 33554431){
2180 ins
= (18 << 26) | (diff
) | (ins
& 1);
2181 *(guint32
*)code
= ins
;
2185 /* diff between 0 and -33554432 */
2186 if (diff
>= -33554432){
2187 ins
= (18 << 26) | (diff
& ~0xfc000000) | (ins
& 1);
2188 *(guint32
*)code
= ins
;
2193 if ((glong
)target
>= 0){
2194 if ((glong
)target
<= 33554431){
2195 ins
= (18 << 26) | ((guint32
) target
) | (ins
& 1) | 2;
2196 *(guint32
*)code
= ins
;
2200 if ((glong
)target
>= -33554432){
2201 ins
= (18 << 26) | (((guint32
)target
) & ~0xfc000000) | (ins
& 1) | 2;
2202 *(guint32
*)code
= ins
;
2207 handle_thunk (TRUE
, code
, target
);
2210 g_assert_not_reached ();
2217 guint32 li
= (guint32
)target
;
2218 ins
= (ins
& 0xffff0000) | (ins
& 3);
2219 ovf
= li
& 0xffff0000;
2220 if (ovf
!= 0 && ovf
!= 0xffff0000)
2221 g_assert_not_reached ();
2224 // FIXME: assert the top bits of li are 0
2226 gint diff
= target
- code
;
2227 ins
= (ins
& 0xffff0000) | (ins
& 3);
2228 ovf
= diff
& 0xffff0000;
2229 if (ovf
!= 0 && ovf
!= 0xffff0000)
2230 g_assert_not_reached ();
2234 *(guint32
*)code
= ins
;
2236 g_assert_not_reached ();
2238 // g_print ("patched with 0x%08x\n", ins);
2242 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2247 guint8
*code
= cfg
->native_code
+ cfg
->code_len
;
2248 MonoInst
*last_ins
= NULL
;
2249 guint last_offset
= 0;
2252 if (cfg
->opt
& MONO_OPT_PEEPHOLE
)
2253 peephole_pass (cfg
, bb
);
2255 /* we don't align basic blocks of loops on ppc */
2257 if (cfg
->verbose_level
> 2)
2258 g_print ("Basic block %d starting at offset 0x%x\n", bb
->block_num
, bb
->native_offset
);
2260 cpos
= bb
->max_offset
;
2262 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
) {
2263 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2264 //g_assert (!mono_compile_aot);
2267 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2268 /* this is not thread save, but good enough */
2269 /* fixme: howto handle overflows? */
2270 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2275 offset
= code
- cfg
->native_code
;
2277 max_len
= ((guint8
*)ins_spec
[ins
->opcode
])[MONO_INST_LEN
];
2279 if (offset
> (cfg
->code_size
- max_len
- 16)) {
2280 cfg
->code_size
*= 2;
2281 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
2282 code
= cfg
->native_code
+ offset
;
2284 // if (ins->cil_code)
2285 // g_print ("cil code\n");
2286 mono_debug_record_line_number (cfg
, ins
, offset
);
2288 switch (ins
->opcode
) {
2290 ppc_mullw (code
, ppc_r4
, ins
->sreg1
, ins
->sreg2
);
2291 ppc_mulhw (code
, ppc_r3
, ins
->sreg1
, ins
->sreg2
);
2294 ppc_mullw (code
, ppc_r4
, ins
->sreg1
, ins
->sreg2
);
2295 ppc_mulhwu (code
, ppc_r3
, ins
->sreg1
, ins
->sreg2
);
2297 case OP_STOREI1_MEMBASE_IMM
:
2298 ppc_li (code
, ppc_r0
, ins
->inst_imm
);
2299 if (ppc_is_imm16 (ins
->inst_offset
)) {
2300 ppc_stb (code
, ppc_r0
, ins
->inst_offset
, ins
->inst_destbasereg
);
2302 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2303 ppc_stbx (code
, ppc_r0
, ppc_r11
, ins
->inst_destbasereg
);
2306 case OP_STOREI2_MEMBASE_IMM
:
2307 ppc_li (code
, ppc_r0
, ins
->inst_imm
);
2308 if (ppc_is_imm16 (ins
->inst_offset
)) {
2309 ppc_sth (code
, ppc_r0
, ins
->inst_offset
, ins
->inst_destbasereg
);
2311 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2312 ppc_sthx (code
, ppc_r0
, ppc_r11
, ins
->inst_destbasereg
);
2315 case OP_STORE_MEMBASE_IMM
:
2316 case OP_STOREI4_MEMBASE_IMM
:
2317 ppc_load (code
, ppc_r0
, ins
->inst_imm
);
2318 if (ppc_is_imm16 (ins
->inst_offset
)) {
2319 ppc_stw (code
, ppc_r0
, ins
->inst_offset
, ins
->inst_destbasereg
);
2321 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2322 ppc_stwx (code
, ppc_r0
, ppc_r11
, ins
->inst_destbasereg
);
2325 case OP_STOREI1_MEMBASE_REG
:
2326 if (ppc_is_imm16 (ins
->inst_offset
)) {
2327 ppc_stb (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
2329 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2330 ppc_stbx (code
, ins
->sreg1
, ppc_r11
, ins
->inst_destbasereg
);
2333 case OP_STOREI2_MEMBASE_REG
:
2334 if (ppc_is_imm16 (ins
->inst_offset
)) {
2335 ppc_sth (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
2337 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2338 ppc_sthx (code
, ins
->sreg1
, ppc_r11
, ins
->inst_destbasereg
);
2341 case OP_STORE_MEMBASE_REG
:
2342 case OP_STOREI4_MEMBASE_REG
:
2343 if (ppc_is_imm16 (ins
->inst_offset
)) {
2344 ppc_stw (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
2346 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2347 ppc_stwx (code
, ins
->sreg1
, ppc_r11
, ins
->inst_destbasereg
);
2353 g_assert_not_reached ();
2354 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2357 g_assert_not_reached ();
2358 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
2359 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
2361 case OP_LOAD_MEMBASE
:
2362 case OP_LOADI4_MEMBASE
:
2363 case OP_LOADU4_MEMBASE
:
2364 if (ppc_is_imm16 (ins
->inst_offset
)) {
2365 ppc_lwz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
2367 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2368 ppc_lwzx (code
, ins
->dreg
, ppc_r11
, ins
->inst_basereg
);
2371 case OP_LOADI1_MEMBASE
:
2372 case OP_LOADU1_MEMBASE
:
2373 if (ppc_is_imm16 (ins
->inst_offset
)) {
2374 ppc_lbz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
2376 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2377 ppc_lbzx (code
, ins
->dreg
, ppc_r11
, ins
->inst_basereg
);
2379 if (ins
->opcode
== OP_LOADI1_MEMBASE
)
2380 ppc_extsb (code
, ins
->dreg
, ins
->dreg
);
2382 case OP_LOADU2_MEMBASE
:
2383 if (ppc_is_imm16 (ins
->inst_offset
)) {
2384 ppc_lhz (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
2386 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2387 ppc_lhzx (code
, ins
->dreg
, ppc_r11
, ins
->inst_basereg
);
2390 case OP_LOADI2_MEMBASE
:
2391 if (ppc_is_imm16 (ins
->inst_offset
)) {
2392 ppc_lha (code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2394 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2395 ppc_lhax (code
, ins
->dreg
, ppc_r11
, ins
->inst_basereg
);
2399 ppc_extsb (code
, ins
->dreg
, ins
->sreg1
);
2402 ppc_extsh (code
, ins
->dreg
, ins
->sreg1
);
2405 ppc_rlwinm (code
, ins
->dreg
, ins
->sreg1
, 0, 24, 31);
2408 ppc_rlwinm (code
, ins
->dreg
, ins
->sreg1
, 0, 16, 31);
2412 ((ins
->next
->opcode
>= CEE_BNE_UN
&& ins
->next
->opcode
<= CEE_BLT_UN
) ||
2413 (ins
->next
->opcode
>= OP_COND_EXC_NE_UN
&& ins
->next
->opcode
<= OP_COND_EXC_LT_UN
) ||
2414 (ins
->next
->opcode
== OP_CLT_UN
|| ins
->next
->opcode
== OP_CGT_UN
)))
2415 ppc_cmpl (code
, 0, 0, ins
->sreg1
, ins
->sreg2
);
2417 ppc_cmp (code
, 0, 0, ins
->sreg1
, ins
->sreg2
);
2419 case OP_COMPARE_IMM
:
2421 ((ins
->next
->opcode
>= CEE_BNE_UN
&& ins
->next
->opcode
<= CEE_BLT_UN
) ||
2422 (ins
->next
->opcode
>= OP_COND_EXC_NE_UN
&& ins
->next
->opcode
<= OP_COND_EXC_LT_UN
) ||
2423 (ins
->next
->opcode
== OP_CLT_UN
|| ins
->next
->opcode
== OP_CGT_UN
))) {
2424 if (ppc_is_uimm16 (ins
->inst_imm
)) {
2425 ppc_cmpli (code
, 0, 0, ins
->sreg1
, (ins
->inst_imm
& 0xffff));
2427 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2428 ppc_cmpl (code
, 0, 0, ins
->sreg1
, ppc_r11
);
2431 if (ppc_is_imm16 (ins
->inst_imm
)) {
2432 ppc_cmpi (code
, 0, 0, ins
->sreg1
, (ins
->inst_imm
& 0xffff));
2434 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2435 ppc_cmp (code
, 0, 0, ins
->sreg1
, ppc_r11
);
2439 case OP_X86_TEST_NULL
:
2440 ppc_cmpi (code
, 0, 0, ins
->sreg1
, 0);
2446 ppc_addc (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2449 ppc_add (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2452 ppc_adde (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2455 if (ppc_is_imm16 (ins
->inst_imm
)) {
2456 ppc_addic (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2458 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2459 ppc_addc (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
2463 if (ppc_is_imm16 (ins
->inst_imm
)) {
2464 ppc_addi (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2466 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2467 ppc_add (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
2471 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2472 ppc_adde (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
2475 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2477 ppc_addo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2478 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2479 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2480 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
2482 case CEE_ADD_OVF_UN
:
2483 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2485 ppc_addco (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2486 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2487 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
2488 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
2491 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2493 ppc_subfo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
2494 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2495 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2496 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
2498 case CEE_SUB_OVF_UN
:
2499 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2501 ppc_subfc (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
2502 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2503 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
2504 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
2506 case OP_ADD_OVF_CARRY
:
2507 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2509 ppc_addeo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2510 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2511 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2512 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
2514 case OP_ADD_OVF_UN_CARRY
:
2515 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2517 ppc_addeo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2518 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2519 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
2520 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
2522 case OP_SUB_OVF_CARRY
:
2523 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2525 ppc_subfeo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
2526 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2527 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2528 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
2530 case OP_SUB_OVF_UN_CARRY
:
2531 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2533 ppc_subfeo (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
2534 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2535 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<13));
2536 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE
, PPC_BR_EQ
, "OverflowException");
2539 ppc_subfc (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
2542 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2543 ppc_subfc (code
, ins
->dreg
, ppc_r11
, ins
->sreg1
);
2546 ppc_subf (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
2549 ppc_subfe (code
, ins
->dreg
, ins
->sreg2
, ins
->sreg1
);
2552 // we add the negated value
2553 if (ppc_is_imm16 (-ins
->inst_imm
))
2554 ppc_addi (code
, ins
->dreg
, ins
->sreg1
, -ins
->inst_imm
);
2556 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2557 ppc_sub (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
2561 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2562 ppc_subfe (code
, ins
->dreg
, ppc_r11
, ins
->sreg1
);
2565 g_assert (ppc_is_imm16 (ins
->inst_imm
));
2566 ppc_subfic (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2569 ppc_subfze (code
, ins
->dreg
, ins
->sreg1
);
2572 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2573 ppc_and (code
, ins
->sreg1
, ins
->dreg
, ins
->sreg2
);
2576 if (!(ins
->inst_imm
& 0xffff0000)) {
2577 ppc_andid (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
2578 } else if (!(ins
->inst_imm
& 0xffff)) {
2579 ppc_andisd (code
, ins
->sreg1
, ins
->dreg
, ((guint32
)ins
->inst_imm
>> 16));
2581 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2582 ppc_and (code
, ins
->sreg1
, ins
->dreg
, ppc_r11
);
2586 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2588 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2589 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2590 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2591 /* FIXME: use OverflowException for 0x80000000/-1 */
2592 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
2595 ppc_divwuod (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2596 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2597 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2598 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
2601 g_assert_not_reached ();
2603 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2604 ppc_divwod (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
2605 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2606 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2607 /* FIXME: use OverflowException for 0x80000000/-1 */
2608 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
2612 ppc_divwod (code
, ppc_r11
, ins
->sreg1
, ins
->sreg2
);
2613 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2614 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2615 /* FIXME: use OverflowException for 0x80000000/-1 */
2616 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
2617 ppc_mullw (code
, ppc_r11
, ppc_r11
, ins
->sreg2
);
2618 ppc_subf (code
, ins
->dreg
, ppc_r11
, ins
->sreg1
);
2621 ppc_divwuod (code
, ppc_r11
, ins
->sreg1
, ins
->sreg2
);
2622 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2623 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2624 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "DivideByZeroException");
2625 ppc_mullw (code
, ppc_r11
, ppc_r11
, ins
->sreg2
);
2626 ppc_subf (code
, ins
->dreg
, ppc_r11
, ins
->sreg1
);
2629 g_assert_not_reached ();
2631 ppc_or (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2634 if (!(ins
->inst_imm
& 0xffff0000)) {
2635 ppc_ori (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
2636 } else if (!(ins
->inst_imm
& 0xffff)) {
2637 ppc_oris (code
, ins
->sreg1
, ins
->dreg
, ((guint32
)(ins
->inst_imm
) >> 16));
2639 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2640 ppc_or (code
, ins
->sreg1
, ins
->dreg
, ppc_r11
);
2644 ppc_xor (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2647 if (!(ins
->inst_imm
& 0xffff0000)) {
2648 ppc_xori (code
, ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
2649 } else if (!(ins
->inst_imm
& 0xffff)) {
2650 ppc_xoris (code
, ins
->sreg1
, ins
->dreg
, ((guint32
)(ins
->inst_imm
) >> 16));
2652 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2653 ppc_xor (code
, ins
->sreg1
, ins
->dreg
, ppc_r11
);
2657 ppc_slw (code
, ins
->sreg1
, ins
->dreg
, ins
->sreg2
);
2660 ppc_rlwinm (code
, ins
->dreg
, ins
->sreg1
, (ins
->inst_imm
& 0x1f), 0, (31 - (ins
->inst_imm
& 0x1f)));
2661 //ppc_load (code, ppc_r11, ins->inst_imm);
2662 //ppc_slw (code, ins->sreg1, ins->dreg, ppc_r11);
2665 ppc_sraw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2668 // there is also ppc_srawi
2669 //ppc_load (code, ppc_r11, ins->inst_imm);
2670 //ppc_sraw (code, ins->dreg, ins->sreg1, ppc_r11);
2671 ppc_srawi (code
, ins
->dreg
, ins
->sreg1
, (ins
->inst_imm
& 0x1f));
2674 /*ppc_load (code, ppc_r11, ins->inst_imm);
2675 ppc_srw (code, ins->dreg, ins->sreg1, ppc_r11);*/
2676 ppc_rlwinm (code
, ins
->dreg
, ins
->sreg1
, (32 - (ins
->inst_imm
& 0x1f)), (ins
->inst_imm
& 0x1f), 31);
2679 ppc_srw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2682 ppc_not (code
, ins
->dreg
, ins
->sreg1
);
2685 ppc_neg (code
, ins
->dreg
, ins
->sreg1
);
2688 ppc_mullw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2691 if (ppc_is_imm16 (ins
->inst_imm
)) {
2692 ppc_mulli (code
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2694 ppc_load (code
, ppc_r11
, ins
->inst_imm
);
2695 ppc_mullw (code
, ins
->dreg
, ins
->sreg1
, ppc_r11
);
2699 /* we annot use mcrxr, since it's not implemented on some processors
2700 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2702 ppc_mullwo (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2703 ppc_mfspr (code
, ppc_r0
, ppc_xer
);
2704 ppc_andisd (code
, ppc_r0
, ppc_r0
, (1<<14));
2705 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE
, PPC_BR_EQ
, "OverflowException");
2707 case CEE_MUL_OVF_UN
:
2708 /* we first multiply to get the high word and compare to 0
2709 * to set the flags, then the result is discarded and then
2710 * we multiply to get the lower * bits result
2712 ppc_mulhwu (code
, ppc_r0
, ins
->sreg1
, ins
->sreg2
);
2713 ppc_cmpi (code
, 0, 0, ppc_r0
, 0);
2714 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN
- CEE_BEQ
, "OverflowException");
2715 ppc_mullw (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2719 ppc_load (code
, ins
->dreg
, ins
->inst_c0
);
2722 mono_add_patch_info (cfg
, offset
, (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
2723 ppc_lis (code
, ins
->dreg
, 0);
2724 ppc_ori (code
, ins
->dreg
, ins
->dreg
, 0);
2730 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
2733 int saved
= ins
->sreg1
;
2734 if (ins
->sreg1
== ppc_r3
) {
2735 ppc_mr (code
, ppc_r0
, ins
->sreg1
);
2738 if (ins
->sreg2
!= ppc_r3
)
2739 ppc_mr (code
, ppc_r3
, ins
->sreg2
);
2740 if (saved
!= ppc_r4
)
2741 ppc_mr (code
, ppc_r4
, saved
);
2746 ppc_fmr (code
, ins
->dreg
, ins
->sreg1
);
2748 case OP_FCONV_TO_R4
:
2749 ppc_frsp (code
, ins
->dreg
, ins
->sreg1
);
2755 * Keep in sync with mono_arch_emit_epilog
2757 g_assert (!cfg
->method
->save_lmf
);
2758 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
2759 if (ppc_is_imm16 (cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
)) {
2760 ppc_lwz (code
, ppc_r0
, cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
, cfg
->frame_reg
);
2762 ppc_load (code
, ppc_r11
, cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
);
2763 ppc_lwzx (code
, ppc_r0
, cfg
->frame_reg
, ppc_r11
);
2765 ppc_mtlr (code
, ppc_r0
);
2767 if (ppc_is_imm16 (cfg
->stack_usage
)) {
2768 ppc_addic (code
, ppc_sp
, cfg
->frame_reg
, cfg
->stack_usage
);
2770 ppc_load (code
, ppc_r11
, cfg
->stack_usage
);
2771 ppc_add (code
, ppc_sp
, cfg
->frame_reg
, ppc_r11
);
2773 if (!cfg
->method
->save_lmf
) {
2774 /*for (i = 31; i >= 14; --i) {
2775 if (cfg->used_float_regs & (1 << i)) {
2776 pos += sizeof (double);
2777 ppc_lfd (code, i, -pos, cfg->frame_reg);
2780 for (i
= 31; i
>= 13; --i
) {
2781 if (cfg
->used_int_regs
& (1 << i
)) {
2782 pos
+= sizeof (gulong
);
2783 ppc_lwz (code
, i
, -pos
, cfg
->frame_reg
);
2787 /* FIXME restore from MonoLMF: though this can't happen yet */
2789 mono_add_patch_info (cfg
, (guint8
*) code
- cfg
->native_code
, MONO_PATCH_INFO_METHOD_JUMP
, ins
->inst_p0
);
2794 /* ensure ins->sreg1 is not NULL */
2795 ppc_lwz (code
, ppc_r0
, 0, ins
->sreg1
);
2798 /* FIXME: implement */
2805 call
= (MonoCallInst
*)ins
;
2806 if (ins
->flags
& MONO_INST_HAS_METHOD
)
2807 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_METHOD
, call
->method
);
2809 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_ABS
, call
->fptr
);
2815 case OP_VOIDCALL_REG
:
2817 ppc_mtlr (code
, ins
->sreg1
);
2820 case OP_FCALL_MEMBASE
:
2821 case OP_LCALL_MEMBASE
:
2822 case OP_VCALL_MEMBASE
:
2823 case OP_VOIDCALL_MEMBASE
:
2824 case OP_CALL_MEMBASE
:
2825 ppc_lwz (code
, ppc_r0
, ins
->inst_offset
, ins
->sreg1
);
2826 ppc_mtlr (code
, ppc_r0
);
2830 g_assert_not_reached ();
2833 /* keep alignment */
2834 int alloca_waste
= PPC_STACK_PARAM_OFFSET
+ cfg
->param_area
+ 31;
2835 int area_offset
= alloca_waste
;
2837 ppc_addi (code
, ppc_r11
, ins
->sreg1
, alloca_waste
+ 31);
2838 ppc_rlwinm (code
, ppc_r11
, ppc_r11
, 0, 0, 27);
2839 ppc_lwz (code
, ppc_r0
, 0, ppc_sp
);
2840 ppc_neg (code
, ppc_r11
, ppc_r11
);
2841 ppc_stwux (code
, ppc_r0
, ppc_sp
, ppc_r11
);
2842 ppc_addi (code
, ins
->dreg
, ppc_sp
, area_offset
);
2850 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
2851 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
2852 (gpointer
)"mono_arch_throw_exception");
2856 case OP_START_HANDLER
:
2857 ppc_mflr (code
, ppc_r0
);
2858 if (ppc_is_imm16 (ins
->inst_left
->inst_offset
)) {
2859 ppc_stw (code
, ppc_r0
, ins
->inst_left
->inst_offset
, ins
->inst_left
->inst_basereg
);
2861 ppc_load (code
, ppc_r11
, ins
->inst_left
->inst_offset
);
2862 ppc_stwx (code
, ppc_r0
, ppc_r11
, ins
->inst_left
->inst_basereg
);
2866 if (ins
->sreg1
!= ppc_r3
)
2867 ppc_mr (code
, ppc_r3
, ins
->sreg1
);
2868 if (ppc_is_imm16 (ins
->inst_left
->inst_offset
)) {
2869 ppc_lwz (code
, ppc_r0
, ins
->inst_left
->inst_offset
, ins
->inst_left
->inst_basereg
);
2871 ppc_load (code
, ppc_r11
, ins
->inst_left
->inst_offset
);
2872 ppc_lwzx (code
, ppc_r0
, ins
->inst_left
->inst_basereg
, ppc_r11
);
2874 ppc_mtlr (code
, ppc_r0
);
2877 case CEE_ENDFINALLY
:
2878 ppc_lwz (code
, ppc_r0
, ins
->inst_left
->inst_offset
, ins
->inst_left
->inst_basereg
);
2879 ppc_mtlr (code
, ppc_r0
);
2882 case OP_CALL_HANDLER
:
2883 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
2887 ins
->inst_c0
= code
- cfg
->native_code
;
2890 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2891 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2893 if (ins
->flags
& MONO_INST_BRLABEL
) {
2894 /*if (ins->inst_i0->inst_c0) {
2896 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2898 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
2902 /*if (ins->inst_target_bb->native_offset) {
2904 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2906 mono_add_patch_info (cfg
, offset
, MONO_PATCH_INFO_BB
, ins
->inst_target_bb
);
2912 ppc_mtctr (code
, ins
->sreg1
);
2913 ppc_bcctr (code
, PPC_BR_ALWAYS
, 0);
2916 ppc_li (code
, ins
->dreg
, 0);
2917 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 2);
2918 ppc_li (code
, ins
->dreg
, 1);
2922 ppc_li (code
, ins
->dreg
, 1);
2923 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
2924 ppc_li (code
, ins
->dreg
, 0);
2928 ppc_li (code
, ins
->dreg
, 1);
2929 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
2930 ppc_li (code
, ins
->dreg
, 0);
2932 case OP_COND_EXC_EQ
:
2933 case OP_COND_EXC_NE_UN
:
2934 case OP_COND_EXC_LT
:
2935 case OP_COND_EXC_LT_UN
:
2936 case OP_COND_EXC_GT
:
2937 case OP_COND_EXC_GT_UN
:
2938 case OP_COND_EXC_GE
:
2939 case OP_COND_EXC_GE_UN
:
2940 case OP_COND_EXC_LE
:
2941 case OP_COND_EXC_LE_UN
:
2942 EMIT_COND_SYSTEM_EXCEPTION (ins
->opcode
- OP_COND_EXC_EQ
, ins
->inst_p1
);
2945 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2947 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2948 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2949 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2951 case OP_COND_EXC_OV
:
2952 /*ppc_mcrxr (code, 0);
2953 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2955 case OP_COND_EXC_NC
:
2956 case OP_COND_EXC_NO
:
2957 g_assert_not_reached ();
2969 EMIT_COND_BRANCH (ins
, ins
->opcode
- CEE_BEQ
);
2972 /* floating point opcodes */
2974 ppc_load (code
, ppc_r11
, ins
->inst_p0
);
2975 ppc_lfd (code
, ins
->dreg
, 0, ppc_r11
);
2978 ppc_load (code
, ppc_r11
, ins
->inst_p0
);
2979 ppc_lfs (code
, ins
->dreg
, 0, ppc_r11
);
2981 case OP_STORER8_MEMBASE_REG
:
2982 if (ppc_is_imm16 (ins
->inst_offset
)) {
2983 ppc_stfd (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
2985 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2986 ppc_stfdx (code
, ins
->sreg1
, ppc_r11
, ins
->inst_destbasereg
);
2989 case OP_LOADR8_MEMBASE
:
2990 if (ppc_is_imm16 (ins
->inst_offset
)) {
2991 ppc_lfd (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
2993 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
2994 ppc_lfdx (code
, ins
->dreg
, ppc_r11
, ins
->inst_basereg
);
2997 case OP_STORER4_MEMBASE_REG
:
2998 if (ppc_is_imm16 (ins
->inst_offset
)) {
2999 ppc_stfs (code
, ins
->sreg1
, ins
->inst_offset
, ins
->inst_destbasereg
);
3001 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
3002 ppc_stfsx (code
, ins
->sreg1
, ppc_r11
, ins
->inst_destbasereg
);
3005 case OP_LOADR4_MEMBASE
:
3006 if (ppc_is_imm16 (ins
->inst_offset
)) {
3007 ppc_lfs (code
, ins
->dreg
, ins
->inst_offset
, ins
->inst_basereg
);
3009 ppc_load (code
, ppc_r11
, ins
->inst_offset
);
3010 ppc_lfsx (code
, ins
->dreg
, ppc_r11
, ins
->inst_basereg
);
3013 case CEE_CONV_R_UN
: {
3014 static const guint64 adjust_val
= 0x4330000000000000ULL
;
3015 ppc_addis (code
, ppc_r0
, ppc_r0
, 0x4330);
3016 ppc_stw (code
, ppc_r0
, -8, ppc_sp
);
3017 ppc_stw (code
, ins
->sreg1
, -4, ppc_sp
);
3018 ppc_load (code
, ppc_r11
, &adjust_val
);
3019 ppc_lfd (code
, ins
->dreg
, -8, ppc_sp
);
3020 ppc_lfd (code
, ppc_f0
, 0, ppc_r11
);
3021 ppc_fsub (code
, ins
->dreg
, ins
->dreg
, ppc_f0
);
3024 case CEE_CONV_R4
: /* FIXME: change precision */
3026 static const guint64 adjust_val
= 0x4330000080000000ULL
;
3027 // addis is special for ppc_r0
3028 ppc_addis (code
, ppc_r0
, ppc_r0
, 0x4330);
3029 ppc_stw (code
, ppc_r0
, -8, ppc_sp
);
3030 ppc_xoris (code
, ins
->sreg1
, ppc_r11
, 0x8000);
3031 ppc_stw (code
, ppc_r11
, -4, ppc_sp
);
3032 ppc_lfd (code
, ins
->dreg
, -8, ppc_sp
);
3033 ppc_load (code
, ppc_r11
, &adjust_val
);
3034 ppc_lfd (code
, ppc_f0
, 0, ppc_r11
);
3035 ppc_fsub (code
, ins
->dreg
, ins
->dreg
, ppc_f0
);
3038 case OP_X86_FP_LOAD_I8
:
3039 g_assert_not_reached ();
3040 /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);*/
3042 case OP_X86_FP_LOAD_I4
:
3043 g_assert_not_reached ();
3044 /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);*/
3046 case OP_FCONV_TO_I1
:
3047 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, TRUE
);
3049 case OP_FCONV_TO_U1
:
3050 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 1, FALSE
);
3052 case OP_FCONV_TO_I2
:
3053 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, TRUE
);
3055 case OP_FCONV_TO_U2
:
3056 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 2, FALSE
);
3058 case OP_FCONV_TO_I4
:
3060 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, TRUE
);
3062 case OP_FCONV_TO_U4
:
3064 code
= emit_float_to_int (cfg
, code
, ins
->dreg
, ins
->sreg1
, 4, FALSE
);
3066 case OP_FCONV_TO_I8
:
3067 case OP_FCONV_TO_U8
:
3068 g_assert_not_reached ();
3069 /* Implemented as helper calls */
3071 case OP_LCONV_TO_R_UN
:
3072 g_assert_not_reached ();
3073 /* Implemented as helper calls */
3075 case OP_LCONV_TO_OVF_I
: {
3076 ppc_mr (code
, ins
->dreg
, ins
->sreg1
);
3077 /* FIXME: emit exception if needed */
3081 ppc_fsqrtd (code
, ins
->dreg
, ins
->sreg1
);
3084 ppc_fadd (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3087 ppc_fsub (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3090 ppc_fmul (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3093 ppc_fdiv (code
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3096 ppc_fneg (code
, ins
->dreg
, ins
->sreg1
);
3100 g_assert_not_reached ();
3103 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
3106 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
3107 ppc_li (code
, ins
->dreg
, 0);
3108 ppc_bc (code
, PPC_BR_FALSE
, PPC_BR_EQ
, 2);
3109 ppc_li (code
, ins
->dreg
, 1);
3112 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
3113 ppc_li (code
, ins
->dreg
, 1);
3114 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
3115 ppc_li (code
, ins
->dreg
, 0);
3118 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
3119 ppc_li (code
, ins
->dreg
, 1);
3120 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 3);
3121 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_LT
, 2);
3122 ppc_li (code
, ins
->dreg
, 0);
3125 ppc_fcmpo (code
, 0, ins
->sreg1
, ins
->sreg2
);
3126 ppc_li (code
, ins
->dreg
, 1);
3127 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
3128 ppc_li (code
, ins
->dreg
, 0);
3131 ppc_fcmpu (code
, 0, ins
->sreg1
, ins
->sreg2
);
3132 ppc_li (code
, ins
->dreg
, 1);
3133 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_SO
, 3);
3134 ppc_bc (code
, PPC_BR_TRUE
, PPC_BR_GT
, 2);
3135 ppc_li (code
, ins
->dreg
, 0);
3138 EMIT_COND_BRANCH (ins
, CEE_BEQ
- CEE_BEQ
);
3141 EMIT_COND_BRANCH (ins
, CEE_BNE_UN
- CEE_BEQ
);
3144 EMIT_COND_BRANCH (ins
, CEE_BLT
- CEE_BEQ
);
3147 EMIT_COND_BRANCH_FLAGS (ins
, PPC_BR_TRUE
, PPC_BR_SO
);
3148 EMIT_COND_BRANCH (ins
, CEE_BLT_UN
- CEE_BEQ
);
3151 EMIT_COND_BRANCH (ins
, CEE_BGT
- CEE_BEQ
);
3154 EMIT_COND_BRANCH_FLAGS (ins
, PPC_BR_TRUE
, PPC_BR_SO
);
3155 EMIT_COND_BRANCH (ins
, CEE_BGT_UN
- CEE_BEQ
);
3158 EMIT_COND_BRANCH (ins
, CEE_BGE
- CEE_BEQ
);
3161 EMIT_COND_BRANCH (ins
, CEE_BGE_UN
- CEE_BEQ
);
3164 EMIT_COND_BRANCH (ins
, CEE_BLE
- CEE_BEQ
);
3167 EMIT_COND_BRANCH (ins
, CEE_BLE_UN
- CEE_BEQ
);
3169 case CEE_CKFINITE
: {
3170 ppc_stfd (code
, ins
->sreg1
, -8, ppc_sp
);
3171 ppc_lwz (code
, ppc_r11
, -8, ppc_sp
);
3172 ppc_rlwinm (code
, ppc_r11
, ppc_r11
, 0, 1, 31);
3173 ppc_addis (code
, ppc_r11
, ppc_r11
, -32752);
3174 ppc_rlwinmd (code
, ppc_r11
, ppc_r11
, 1, 31, 31);
3175 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ
- CEE_BEQ
, "ArithmeticException");
3179 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins
->opcode
), __FUNCTION__
);
3180 g_assert_not_reached ();
3183 if ((cfg
->opt
& MONO_OPT_BRANCH
) && ((code
- cfg
->native_code
- offset
) > max_len
)) {
3184 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3185 mono_inst_name (ins
->opcode
), max_len
, code
- cfg
->native_code
- offset
);
3186 g_assert_not_reached ();
3192 last_offset
= offset
;
3197 cfg
->code_len
= code
- cfg
->native_code
;
3201 mono_arch_register_lowlevel_calls (void)
3205 #define patch_lis_ori(ip,val) do {\
3206 guint16 *__lis_ori = (guint16*)(ip); \
3207 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3208 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3212 mono_arch_patch_code (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
)
3214 MonoJumpInfo
*patch_info
;
3216 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
) {
3217 unsigned char *ip
= patch_info
->ip
.i
+ code
;
3218 const unsigned char *target
;
3220 target
= mono_resolve_patch_target (method
, domain
, code
, patch_info
, run_cctors
);
3222 switch (patch_info
->type
) {
3223 case MONO_PATCH_INFO_IP
:
3224 patch_lis_ori (ip
, ip
);
3226 case MONO_PATCH_INFO_METHOD_REL
:
3227 g_assert_not_reached ();
3228 *((gpointer
*)(ip
)) = code
+ patch_info
->data
.offset
;
3230 case MONO_PATCH_INFO_SWITCH
: {
3231 gpointer
*table
= (gpointer
*)patch_info
->data
.target
;
3234 // FIXME: inspect code to get the register
3235 ppc_load (ip
, ppc_r11
, patch_info
->data
.target
);
3236 //*((gconstpointer *)(ip + 2)) = patch_info->data.target;
3238 for (i
= 0; i
< patch_info
->table_size
; i
++) {
3239 table
[i
] = (int)patch_info
->data
.table
[i
] + code
;
3241 /* we put into the table the absolute address, no need for ppc_patch in this case */
3244 case MONO_PATCH_INFO_METHODCONST
:
3245 case MONO_PATCH_INFO_CLASS
:
3246 case MONO_PATCH_INFO_IMAGE
:
3247 case MONO_PATCH_INFO_FIELD
:
3248 case MONO_PATCH_INFO_VTABLE
:
3249 case MONO_PATCH_INFO_IID
:
3250 case MONO_PATCH_INFO_SFLDA
:
3251 case MONO_PATCH_INFO_LDSTR
:
3252 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
3253 case MONO_PATCH_INFO_LDTOKEN
:
3254 /* from OP_AOTCONST : lis + ori */
3255 patch_lis_ori (ip
, target
);
3257 case MONO_PATCH_INFO_R4
:
3258 case MONO_PATCH_INFO_R8
:
3259 g_assert_not_reached ();
3260 *((gconstpointer
*)(ip
+ 2)) = patch_info
->data
.target
;
3262 case MONO_PATCH_INFO_EXC_NAME
:
3263 g_assert_not_reached ();
3264 *((gconstpointer
*)(ip
+ 1)) = patch_info
->data
.name
;
3266 case MONO_PATCH_INFO_BB_OVF
:
3267 case MONO_PATCH_INFO_EXC_OVF
:
3268 /* everything is dealt with at epilog output time */
3273 ppc_patch (ip
, target
);
3278 mono_arch_max_epilog_size (MonoCompile
*cfg
)
3280 int max_epilog_size
= 16 + 20*4;
3281 MonoJumpInfo
*patch_info
;
3283 if (cfg
->method
->save_lmf
)
3284 max_epilog_size
+= 128;
3286 if (mono_jit_trace_calls
!= NULL
)
3287 max_epilog_size
+= 50;
3289 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
3290 max_epilog_size
+= 50;
3292 /* count the number of exception infos */
3295 * make sure we have enough space for exceptions
3296 * 24 is the simulated call to throw_exception_by_name
3298 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
3299 if (patch_info
->type
== MONO_PATCH_INFO_EXC
)
3300 max_epilog_size
+= 24;
3301 else if (patch_info
->type
== MONO_PATCH_INFO_BB_OVF
)
3302 max_epilog_size
+= 12;
3303 else if (patch_info
->type
== MONO_PATCH_INFO_EXC_OVF
)
3304 max_epilog_size
+= 12;
3307 return max_epilog_size
;
3311 * Stack frame layout:
3313 * ------------------- sp
3314 * MonoLMF structure or saved registers
3315 * -------------------
3317 * -------------------
3319 * -------------------
3320 * optional 8 bytes for tracing
3321 * -------------------
3322 * param area size is cfg->param_area
3323 * -------------------
3324 * linkage area size is PPC_STACK_PARAM_OFFSET
3325 * ------------------- sp
3329 mono_arch_emit_prolog (MonoCompile
*cfg
)
3331 MonoMethod
*method
= cfg
->method
;
3333 MonoMethodSignature
*sig
;
3335 int alloc_size
, pos
, max_offset
, i
;
3341 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
3344 cfg
->code_size
= 256;
3345 code
= cfg
->native_code
= g_malloc (cfg
->code_size
);
3347 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
3348 ppc_mflr (code
, ppc_r0
);
3349 ppc_stw (code
, ppc_r0
, PPC_RET_ADDR_OFFSET
, ppc_sp
);
3351 if (cfg
->max_ireg
>= 29)
3352 cfg
->used_int_regs
|= USE_EXTRA_TEMPS
;
3354 alloc_size
= cfg
->stack_offset
;
3357 if (!method
->save_lmf
) {
3358 /*for (i = 31; i >= 14; --i) {
3359 if (cfg->used_float_regs & (1 << i)) {
3360 pos += sizeof (gdouble);
3361 ppc_stfd (code, i, -pos, ppc_sp);
3364 for (i
= 31; i
>= 13; --i
) {
3365 if (cfg
->used_int_regs
& (1 << i
)) {
3366 pos
+= sizeof (gulong
);
3367 ppc_stw (code
, i
, -pos
, ppc_sp
);
3372 pos
+= sizeof (MonoLMF
);
3374 ofs
= -pos
+ G_STRUCT_OFFSET(MonoLMF
, iregs
);
3375 ppc_stmw (code
, ppc_r13
, ppc_r1
, ofs
);
3376 for (i
= 14; i
< 32; i
++) {
3377 ppc_stfd (code
, i
, (-pos
+ G_STRUCT_OFFSET(MonoLMF
, fregs
) + ((i
-14) * sizeof (gdouble
))), ppc_r1
);
3381 // align to PPC_STACK_ALIGNMENT bytes
3382 if (alloc_size
& (PPC_STACK_ALIGNMENT
- 1)) {
3383 alloc_size
+= PPC_STACK_ALIGNMENT
- 1;
3384 alloc_size
&= ~(PPC_STACK_ALIGNMENT
- 1);
3387 cfg
->stack_usage
= alloc_size
;
3388 g_assert ((alloc_size
& (PPC_STACK_ALIGNMENT
-1)) == 0);
3390 if (ppc_is_imm16 (-alloc_size
)) {
3391 ppc_stwu (code
, ppc_sp
, -alloc_size
, ppc_sp
);
3393 ppc_load (code
, ppc_r11
, -alloc_size
);
3394 ppc_stwux (code
, ppc_sp
, ppc_sp
, ppc_r11
);
3397 if (cfg
->frame_reg
!= ppc_sp
)
3398 ppc_mr (code
, cfg
->frame_reg
, ppc_sp
);
3400 /* compute max_offset in order to use short forward jumps
3401 * we always do it on ppc because the immediate displacement
3402 * for jumps is too small
3405 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
3406 MonoInst
*ins
= bb
->code
;
3407 bb
->max_offset
= max_offset
;
3409 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
)
3413 max_offset
+= ((guint8
*)ins_spec
[ins
->opcode
])[MONO_INST_LEN
];
3418 /* load arguments allocated to register from the stack */
3419 sig
= method
->signature
;
3422 cinfo
= calculate_sizes (sig
, sig
->pinvoke
);
3424 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
3425 ArgInfo
*ainfo
= &cinfo
->ret
;
3427 if (ppc_is_imm16 (inst
->inst_offset
)) {
3428 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
3430 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3431 ppc_stwx (code
, ainfo
->reg
, ppc_r11
, inst
->inst_basereg
);
3434 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
3435 ArgInfo
*ainfo
= cinfo
->args
+ i
;
3436 inst
= cfg
->varinfo
[pos
];
3438 if (cfg
->verbose_level
> 2)
3439 g_print ("Saving argument %d (type: %d)\n", i
, ainfo
->regtype
);
3440 if (inst
->opcode
== OP_REGVAR
) {
3441 if (ainfo
->regtype
== RegTypeGeneral
)
3442 ppc_mr (code
, inst
->dreg
, ainfo
->reg
);
3443 else if (ainfo
->regtype
== RegTypeFP
)
3444 ppc_fmr (code
, inst
->dreg
, ainfo
->reg
);
3445 else if (ainfo
->regtype
== RegTypeBase
) {
3446 ppc_lwz (code
, ppc_r11
, 0, ppc_sp
);
3447 ppc_lwz (code
, inst
->dreg
, ainfo
->offset
, ppc_r11
);
3449 g_assert_not_reached ();
3451 if (cfg
->verbose_level
> 2)
3452 g_print ("Argument %d assigned to register %s\n", pos
, mono_arch_regname (inst
->dreg
));
3454 /* the argument should be put on the stack: FIXME handle size != word */
3455 if (ainfo
->regtype
== RegTypeGeneral
) {
3456 switch (ainfo
->size
) {
3458 if (ppc_is_imm16 (inst
->inst_offset
)) {
3459 ppc_stb (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
3461 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3462 ppc_stbx (code
, ainfo
->reg
, ppc_r11
, inst
->inst_basereg
);
3466 if (ppc_is_imm16 (inst
->inst_offset
)) {
3467 ppc_sth (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
3469 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3470 ppc_sthx (code
, ainfo
->reg
, ppc_r11
, inst
->inst_basereg
);
3474 if (ppc_is_imm16 (inst
->inst_offset
+ 4)) {
3475 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
3476 ppc_stw (code
, ainfo
->reg
+ 1, inst
->inst_offset
+ 4, inst
->inst_basereg
);
3478 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3479 ppc_add (code
, ppc_r11
, ppc_r11
, inst
->inst_basereg
);
3480 ppc_stw (code
, ainfo
->reg
, 0, ppc_r11
);
3481 ppc_stw (code
, ainfo
->reg
+ 1, 4, ppc_r11
);
3485 if (ppc_is_imm16 (inst
->inst_offset
)) {
3486 ppc_stw (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
3488 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3489 ppc_stwx (code
, ainfo
->reg
, ppc_r11
, inst
->inst_basereg
);
3493 } else if (ainfo
->regtype
== RegTypeBase
) {
3494 /* load the previous stack pointer in r11 */
3495 ppc_lwz (code
, ppc_r11
, 0, ppc_sp
);
3496 ppc_lwz (code
, ppc_r0
, ainfo
->offset
, ppc_r11
);
3497 switch (ainfo
->size
) {
3499 if (ppc_is_imm16 (inst
->inst_offset
)) {
3500 ppc_stb (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
3502 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3503 ppc_stbx (code
, ppc_r0
, ppc_r11
, inst
->inst_basereg
);
3507 if (ppc_is_imm16 (inst
->inst_offset
)) {
3508 ppc_sth (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
3510 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3511 ppc_sthx (code
, ppc_r0
, ppc_r11
, inst
->inst_basereg
);
3515 if (ppc_is_imm16 (inst
->inst_offset
+ 4)) {
3516 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
3517 ppc_lwz (code
, ppc_r0
, ainfo
->offset
+ 4, ppc_r11
);
3518 ppc_stw (code
, ppc_r0
, inst
->inst_offset
+ 4, inst
->inst_basereg
);
3521 g_assert_not_reached ();
3525 if (ppc_is_imm16 (inst
->inst_offset
)) {
3526 ppc_stw (code
, ppc_r0
, inst
->inst_offset
, inst
->inst_basereg
);
3528 ppc_load (code
, ppc_r11
, inst
->inst_offset
);
3529 ppc_stwx (code
, ppc_r0
, ppc_r11
, inst
->inst_basereg
);
3533 } else if (ainfo
->regtype
== RegTypeFP
) {
3534 g_assert (ppc_is_imm16 (inst
->inst_offset
));
3535 if (ainfo
->size
== 8)
3536 ppc_stfd (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
3537 else if (ainfo
->size
== 4)
3538 ppc_stfs (code
, ainfo
->reg
, inst
->inst_offset
, inst
->inst_basereg
);
3540 g_assert_not_reached ();
3541 } else if (ainfo
->regtype
== RegTypeStructByVal
) {
3542 int doffset
= inst
->inst_offset
;
3546 g_assert (ppc_is_imm16 (inst
->inst_offset
));
3547 g_assert (ppc_is_imm16 (inst
->inst_offset
+ ainfo
->size
* sizeof (gpointer
)));
3548 if (inst
->inst_vtype
->data
.klass
)
3549 size
= mono_class_native_size (inst
->inst_vtype
->data
.klass
, NULL
);
3550 for (cur_reg
= 0; cur_reg
< ainfo
->size
; ++cur_reg
) {
3552 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3553 register. Should this case include linux/ppc?
3557 ppc_sth (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
3559 ppc_stb (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
3562 ppc_stw (code
, ainfo
->reg
+ cur_reg
, doffset
, inst
->inst_basereg
);
3563 soffset
+= sizeof (gpointer
);
3564 doffset
+= sizeof (gpointer
);
3566 if (ainfo
->vtsize
) {
3567 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3568 ppc_lwz (code
, ppc_r11
, 0, ppc_sp
);
3569 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3570 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (gpointer
), inst
->inst_basereg
, doffset
, ppc_r11
, ainfo
->offset
+ soffset
);
3572 } else if (ainfo
->regtype
== RegTypeStructByAddr
) {
3573 g_assert (ppc_is_imm16 (inst
->inst_offset
));
3574 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3575 code
= emit_memcpy (code
, ainfo
->vtsize
* sizeof (gpointer
), inst
->inst_basereg
, inst
->inst_offset
, ainfo
->reg
, 0);
3577 g_assert_not_reached ();
3582 if (method
->save_lmf
) {
3584 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3585 (gpointer
)"mono_get_lmf_addr");
3587 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3588 /* lmf_offset is the offset from the previous stack pointer,
3589 * alloc_size is the total stack space allocated, so the offset
3590 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3591 * The pointer to the struct is put in ppc_r11 (new_lmf).
3592 * The callee-saved registers are already in the MonoLMF structure
3594 ppc_addi (code
, ppc_r11
, ppc_sp
, alloc_size
- lmf_offset
);
3595 /* ppc_r3 is the result from mono_get_lmf_addr () */
3596 ppc_stw (code
, ppc_r3
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
), ppc_r11
);
3597 /* new_lmf->previous_lmf = *lmf_addr */
3598 ppc_lwz (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r3
);
3599 ppc_stw (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r11
);
3600 /* *(lmf_addr) = r11 */
3601 ppc_stw (code
, ppc_r11
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r3
);
3602 /* save method info */
3603 ppc_load (code
, ppc_r0
, method
);
3604 ppc_stw (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, method
), ppc_r11
);
3605 ppc_stw (code
, ppc_sp
, G_STRUCT_OFFSET(MonoLMF
, ebp
), ppc_r11
);
3606 /* save the current IP */
3607 mono_add_patch_info (cfg
, code
- cfg
->native_code
, MONO_PATCH_INFO_IP
, NULL
);
3608 ppc_load (code
, ppc_r0
, 0x01010101);
3609 ppc_stw (code
, ppc_r0
, G_STRUCT_OFFSET(MonoLMF
, eip
), ppc_r11
);
3613 code
= mono_arch_instrument_prolog (cfg
, mono_trace_enter_method
, code
, TRUE
);
3615 cfg
->code_len
= code
- cfg
->native_code
;
3622 mono_arch_emit_epilog (MonoCompile
*cfg
)
3624 MonoJumpInfo
*patch_info
;
3625 MonoMethod
*method
= cfg
->method
;
3630 * Keep in sync with CEE_JMP
3632 code
= cfg
->native_code
+ cfg
->code_len
;
3634 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
)) {
3635 code
= mono_arch_instrument_epilog (cfg
, mono_trace_leave_method
, code
, TRUE
);
3639 if (method
->save_lmf
) {
3641 pos
+= sizeof (MonoLMF
);
3643 /* save the frame reg in r8 */
3644 ppc_mr (code
, ppc_r8
, cfg
->frame_reg
);
3645 ppc_addi (code
, ppc_r11
, cfg
->frame_reg
, cfg
->stack_usage
- lmf_offset
);
3646 /* r5 = previous_lmf */
3647 ppc_lwz (code
, ppc_r5
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r11
);
3649 ppc_lwz (code
, ppc_r6
, G_STRUCT_OFFSET(MonoLMF
, lmf_addr
), ppc_r11
);
3650 /* *(lmf_addr) = previous_lmf */
3651 ppc_stw (code
, ppc_r5
, G_STRUCT_OFFSET(MonoLMF
, previous_lmf
), ppc_r6
);
3652 /* FIXME: speedup: there is no actual need to restore the registers if
3653 * we didn't actually change them (idea from Zoltan).
3656 ppc_lmw (code
, ppc_r13
, ppc_r11
, G_STRUCT_OFFSET(MonoLMF
, iregs
));
3658 /*for (i = 14; i < 32; i++) {
3659 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3661 g_assert (ppc_is_imm16 (cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
));
3662 /* use the saved copy of the frame reg in r8 */
3663 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
3664 ppc_lwz (code
, ppc_r0
, cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
, ppc_r8
);
3665 ppc_mtlr (code
, ppc_r0
);
3667 ppc_addic (code
, ppc_sp
, ppc_r8
, cfg
->stack_usage
);
3669 if (1 || cfg
->flags
& MONO_CFG_HAS_CALLS
) {
3670 if (ppc_is_imm16 (cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
)) {
3671 ppc_lwz (code
, ppc_r0
, cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
, cfg
->frame_reg
);
3673 ppc_load (code
, ppc_r11
, cfg
->stack_usage
+ PPC_RET_ADDR_OFFSET
);
3674 ppc_lwzx (code
, ppc_r0
, cfg
->frame_reg
, ppc_r11
);
3676 ppc_mtlr (code
, ppc_r0
);
3678 if (ppc_is_imm16 (cfg
->stack_usage
)) {
3679 ppc_addic (code
, ppc_sp
, cfg
->frame_reg
, cfg
->stack_usage
);
3681 ppc_load (code
, ppc_r11
, cfg
->stack_usage
);
3682 ppc_add (code
, ppc_sp
, cfg
->frame_reg
, ppc_r11
);
3685 /*for (i = 31; i >= 14; --i) {
3686 if (cfg->used_float_regs & (1 << i)) {
3687 pos += sizeof (double);
3688 ppc_lfd (code, i, -pos, ppc_sp);
3691 for (i
= 31; i
>= 13; --i
) {
3692 if (cfg
->used_int_regs
& (1 << i
)) {
3693 pos
+= sizeof (gulong
);
3694 ppc_lwz (code
, i
, -pos
, ppc_sp
);
3700 /* add code to raise exceptions */
3701 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
3702 switch (patch_info
->type
) {
3703 case MONO_PATCH_INFO_BB_OVF
: {
3704 MonoOvfJump
*ovfj
= patch_info
->data
.target
;
3705 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
3706 /* patch the initial jump */
3707 ppc_patch (ip
, code
);
3708 ppc_bc (code
, ovfj
->b0_cond
, ovfj
->b1_cond
, 2);
3710 ppc_patch (code
- 4, ip
+ 4); /* jump back after the initiali branch */
3711 /* jump back to the true target */
3713 ip
= ovfj
->bb
->native_offset
+ cfg
->native_code
;
3714 ppc_patch (code
- 4, ip
);
3717 case MONO_PATCH_INFO_EXC_OVF
: {
3718 MonoOvfJump
*ovfj
= patch_info
->data
.target
;
3719 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
3720 /* patch the initial jump */
3721 ppc_patch (ip
, code
);
3722 ppc_bc (code
, ovfj
->b0_cond
, ovfj
->b1_cond
, 2);
3724 ppc_patch (code
- 4, ip
+ 4); /* jump back after the initiali branch */
3725 /* jump back to the true target */
3727 ip
= (char*)ovfj
->ip
+ 4;
3728 ppc_patch (code
- 4, ip
);
3731 case MONO_PATCH_INFO_EXC
: {
3732 unsigned char *ip
= patch_info
->ip
.i
+ cfg
->native_code
;
3733 ppc_patch (ip
, code
);
3734 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3735 ppc_load (code
, ppc_r3
, patch_info
->data
.target
);
3736 /* simulate a call from ip */
3737 ppc_load (code
, ppc_r0
, ip
+ 4);
3738 ppc_mtlr (code
, ppc_r0
);
3739 patch_info
->type
= MONO_PATCH_INFO_INTERNAL_METHOD
;
3740 patch_info
->data
.name
= "mono_arch_throw_exception_by_name";
3741 patch_info
->ip
.i
= code
- cfg
->native_code
;
3751 cfg
->code_len
= code
- cfg
->native_code
;
3753 g_assert (cfg
->code_len
< cfg
->code_size
);
3758 mono_arch_setup_jit_tls_data (MonoJitTlsData
*tls
)
3763 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
3768 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
, int this_reg
, int this_type
, int vt_reg
)
3770 int this_dreg
= ppc_r3
;
3775 /* add the this argument */
3776 if (this_reg
!= -1) {
3778 MONO_INST_NEW (cfg
, this, OP_SETREG
);
3779 this->type
= this_type
;
3780 this->sreg1
= this_reg
;
3781 this->dreg
= this_dreg
;
3782 mono_bblock_add_inst (cfg
->cbb
, this);
3787 MONO_INST_NEW (cfg
, vtarg
, OP_SETREG
);
3788 vtarg
->type
= STACK_MP
;
3789 vtarg
->sreg1
= vt_reg
;
3790 vtarg
->dreg
= ppc_r3
;
3791 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
3796 mono_arch_get_opcode_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
3798 /* optional instruction, need to detect it
3799 if (cmethod->klass == mono_defaults.math_class) {
3800 if (strcmp (cmethod->name, "Sqrt") == 0)
3808 mono_arch_print_tree (MonoInst
*tree
, int arity
)
3813 MonoInst
* mono_arch_get_domain_intrinsic (MonoCompile
* cfg
)
3818 MonoInst
* mono_arch_get_thread_intrinsic (MonoCompile
* cfg
)