2 * mini-ia64.c: IA64 backend for the Mono code generator
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2003 Ximian, Inc.
15 #ifdef __INTEL_COMPILER
16 #include <ia64intrin.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/utils/mono-math.h>
26 #include "mini-ia64.h"
30 static gint appdomain_tls_offset = -1;
31 static gint thread_tls_offset = -1;
33 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
35 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
38 * IA64 register usage:
39 * - local registers are used for global register allocation
40 * - r8..r11, r14..r30 is used for local register allocation
41 * - r31 is a scratch register used within opcode implementations
42 * - FIXME: Use out registers as well
43 * - the first three locals are used for saving ar.pfst, b0, and sp
44 * - compare instructions allways set p6 and p7
48 * There are a lot of places where generated code is disassembled/patched.
49 * The automatic bundling of instructions done by the code generation macros
50 * could complicate things, so it is best to call
51 * ia64_codegen_set_one_ins_per_bundle () at those places.
54 #define ARGS_OFFSET 16
56 #define GP_SCRATCH_REG 31
57 #define GP_SCRATCH_REG2 30
58 #define FP_SCRATCH_REG 32
59 #define FP_SCRATCH_REG2 33
61 #define LOOP_ALIGNMENT 8
62 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
64 #define NOT_IMPLEMENTED g_assert_not_reached ()
66 static const char* gregs [] = {
67 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
68 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
69 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
70 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
71 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
72 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
73 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
74 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
75 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
76 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
77 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
78 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
79 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
83 mono_arch_regname (int reg)
91 static const char* fregs [] = {
92 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
93 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
94 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
95 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
96 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
97 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
98 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
99 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
100 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
101 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
102 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
103 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
104 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
108 mono_arch_fregname (int reg)
116 G_GNUC_UNUSED static void
121 G_GNUC_UNUSED static gboolean
124 static int count = 0;
127 if (count == atoi (getenv ("COUNT"))) {
131 if (count > atoi (getenv ("COUNT"))) {
139 debug_ins_sched (void)
142 return debug_count ();
152 return debug_count ();
159 ia64_patch (unsigned char* code, gpointer target);
165 ArgValuetypeAddrInIReg,
183 /* Only if storage == ArgAggregate */
193 gboolean need_stack_align;
199 #define DEBUG(a) if (cfg->verbose_level > 1) a
201 #define NEW_ICONST(cfg,dest,val) do { \
202 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
203 (dest)->opcode = OP_ICONST; \
204 (dest)->inst_c0 = (val); \
205 (dest)->type = STACK_I4; \
211 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
213 ainfo->offset = *stack_size;
215 if (*gr >= PARAM_REGS) {
216 ainfo->storage = ArgOnStack;
217 (*stack_size) += sizeof (gpointer);
220 ainfo->storage = ArgInIReg;
226 #define FLOAT_PARAM_REGS 8
229 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
231 ainfo->offset = *stack_size;
233 if (*gr >= PARAM_REGS) {
234 ainfo->storage = ArgOnStack;
235 (*stack_size) += sizeof (gpointer);
238 ainfo->storage = ArgInFloatReg;
239 ainfo->reg = 8 + *fr;
246 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
248 guint32 *gr, guint32 *fr, guint32 *stack_size)
252 MonoMarshalType *info;
253 gboolean is_hfa = TRUE;
254 guint32 hfa_type = 0;
256 klass = mono_class_from_mono_type (type);
257 if (type->type == MONO_TYPE_TYPEDBYREF)
258 size = 3 * sizeof (gpointer);
259 else if (sig->pinvoke)
260 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
262 size = mono_type_stack_size (&klass->byval_arg, NULL);
264 if (!sig->pinvoke || (size == 0)) {
265 /* Allways pass in memory */
266 ainfo->offset = *stack_size;
267 *stack_size += ALIGN_TO (size, 8);
268 ainfo->storage = ArgOnStack;
273 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
274 info = mono_marshal_load_type_info (klass);
276 for (i = 0; i < info->num_fields; ++i) {
277 guint32 ftype = info->fields [i].field->type->type;
278 if (!(info->fields [i].field->type->byref) &&
279 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
282 else if (hfa_type != ftype)
291 ainfo->storage = ArgAggregate;
292 ainfo->atype = AggregateNormal;
295 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
297 if (info->num_fields <= 8) {
299 ainfo->nregs = info->num_fields;
300 ainfo->nslots = ainfo->nregs;
306 if ((*fr) + info->num_fields > 8)
309 ainfo->reg = 8 + (*fr);
310 ainfo->nregs = info->num_fields;
311 ainfo->nslots = ainfo->nregs;
312 (*fr) += info->num_fields;
317 /* This also handles returning of TypedByRef used by some icalls */
320 ainfo->reg = IA64_R8;
321 ainfo->nregs = (size + 7) / 8;
322 ainfo->nslots = ainfo->nregs;
329 ainfo->offset = *stack_size;
330 ainfo->nslots = (size + 7) / 8;
332 if (((*gr) + ainfo->nslots) <= 8) {
333 /* Fits entirely in registers */
334 ainfo->nregs = ainfo->nslots;
335 (*gr) += ainfo->nregs;
339 ainfo->nregs = 8 - (*gr);
341 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
347 * Obtain information about a call according to the calling convention.
348 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
349 * Gude" document for more information.
352 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
356 int n = sig->hasthis + sig->param_count;
357 guint32 stack_size = 0;
360 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
367 ret_type = mono_type_get_underlying_type (sig->ret);
368 switch (ret_type->type) {
369 case MONO_TYPE_BOOLEAN:
380 case MONO_TYPE_FNPTR:
381 case MONO_TYPE_CLASS:
382 case MONO_TYPE_OBJECT:
383 case MONO_TYPE_SZARRAY:
384 case MONO_TYPE_ARRAY:
385 case MONO_TYPE_STRING:
386 cinfo->ret.storage = ArgInIReg;
387 cinfo->ret.reg = IA64_R8;
391 cinfo->ret.storage = ArgInIReg;
392 cinfo->ret.reg = IA64_R8;
396 cinfo->ret.storage = ArgInFloatReg;
399 case MONO_TYPE_GENERICINST:
400 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
401 cinfo->ret.storage = ArgInIReg;
402 cinfo->ret.reg = IA64_R8;
406 case MONO_TYPE_VALUETYPE:
407 case MONO_TYPE_TYPEDBYREF: {
408 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
410 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
411 if (cinfo->ret.storage == ArgOnStack)
412 /* The caller passes the address where the value is stored */
413 add_general (&gr, &stack_size, &cinfo->ret);
414 if (cinfo->ret.storage == ArgInIReg)
415 cinfo->ret.storage = ArgValuetypeAddrInIReg;
419 cinfo->ret.storage = ArgNone;
422 g_error ("Can't handle as return value 0x%x", sig->ret->type);
428 add_general (&gr, &stack_size, cinfo->args + 0);
430 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
432 fr = FLOAT_PARAM_REGS;
434 /* Emit the signature cookie just before the implicit arguments */
435 add_general (&gr, &stack_size, &cinfo->sig_cookie);
438 for (i = 0; i < sig->param_count; ++i) {
439 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
442 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
443 /* We allways pass the sig cookie on the stack for simplicity */
445 * Prevent implicit arguments + the sig cookie from being passed
449 fr = FLOAT_PARAM_REGS;
451 /* Emit the signature cookie just before the implicit arguments */
452 add_general (&gr, &stack_size, &cinfo->sig_cookie);
455 if (sig->params [i]->byref) {
456 add_general (&gr, &stack_size, ainfo);
459 ptype = mono_type_get_underlying_type (sig->params [i]);
460 switch (ptype->type) {
461 case MONO_TYPE_BOOLEAN:
464 add_general (&gr, &stack_size, ainfo);
469 add_general (&gr, &stack_size, ainfo);
473 add_general (&gr, &stack_size, ainfo);
478 case MONO_TYPE_FNPTR:
479 case MONO_TYPE_CLASS:
480 case MONO_TYPE_OBJECT:
481 case MONO_TYPE_STRING:
482 case MONO_TYPE_SZARRAY:
483 case MONO_TYPE_ARRAY:
484 add_general (&gr, &stack_size, ainfo);
486 case MONO_TYPE_GENERICINST:
487 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
488 add_general (&gr, &stack_size, ainfo);
492 case MONO_TYPE_VALUETYPE:
493 case MONO_TYPE_TYPEDBYREF:
495 /* We allways pass valuetypes on the stack */
496 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
500 add_general (&gr, &stack_size, ainfo);
503 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
506 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
509 g_assert_not_reached ();
513 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
515 fr = FLOAT_PARAM_REGS;
517 /* Emit the signature cookie just before the implicit arguments */
518 add_general (&gr, &stack_size, &cinfo->sig_cookie);
521 cinfo->stack_usage = stack_size;
522 cinfo->reg_usage = gr;
523 cinfo->freg_usage = fr;
528 * mono_arch_get_argument_info:
529 * @csig: a method signature
530 * @param_count: the number of parameters to consider
531 * @arg_info: an array to store the result infos
533 * Gathers information on parameters such as size, alignment and
534 * padding. arg_info should be large enought to hold param_count + 1 entries.
536 * Returns the size of the argument area on the stack.
539 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
542 CallInfo *cinfo = get_call_info (csig, FALSE);
543 guint32 args_size = cinfo->stack_usage;
545 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
547 arg_info [0].offset = 0;
550 for (k = 0; k < param_count; k++) {
551 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
553 arg_info [k + 1].size = 0;
562 * Initialize the cpu to execute managed code.
565 mono_arch_cpu_init (void)
570 * This function returns the optimizations supported on this cpu.
573 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
581 mono_arch_break (void)
586 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
590 MonoMethodSignature *sig;
591 MonoMethodHeader *header;
594 header = mono_method_get_header (cfg->method);
596 sig = mono_method_signature (cfg->method);
598 cinfo = get_call_info (sig, FALSE);
600 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
601 MonoInst *ins = cfg->args [i];
603 ArgInfo *ainfo = &cinfo->args [i];
605 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
608 if (ainfo->storage == ArgInIReg) {
609 /* The input registers are non-volatile */
610 ins->opcode = OP_REGVAR;
611 ins->dreg = 32 + ainfo->reg;
615 for (i = 0; i < cfg->num_varinfo; i++) {
616 MonoInst *ins = cfg->varinfo [i];
617 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
620 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
623 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
624 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
627 if (mono_is_regsize_var (ins->inst_vtype)) {
628 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
629 g_assert (i == vmv->idx);
630 vars = g_list_prepend (vars, vmv);
634 vars = mono_varlist_sort (cfg, vars, 0);
640 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
643 guint32 reserved_regs;
644 MonoMethodHeader *header;
646 if (cfg->arch.reg_local0 > 0)
650 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
652 header = mono_method_get_header (cfg->method);
654 /* Some registers are reserved for use by the prolog/epilog */
655 reserved_regs = header->num_clauses ? 4 : 3;
657 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
658 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
659 /* One registers is needed by instrument_epilog to save the return value */
661 if (cinfo->reg_usage < 2)
662 /* Number of arguments passed to function call in instrument_prolog */
663 cinfo->reg_usage = 2;
666 cfg->arch.reg_in0 = 32;
667 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
668 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
670 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
671 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
672 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
675 * Frames without handlers save sp to fp, frames with handlers save it into
676 * a dedicated register.
678 if (header->num_clauses)
679 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
681 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
683 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
684 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
685 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
689 * Need to allocate at least 2 out register for use by OP_THROW / the system
690 * exception throwing code.
692 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
698 mono_arch_get_global_int_regs (MonoCompile *cfg)
703 mono_ia64_alloc_stacked_registers (cfg);
705 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
708 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
715 * mono_arch_regalloc_cost:
717 * Return the cost, in number of memory references, of the action of
718 * allocating the variable VMV into a register during global register
722 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
724 /* FIXME: Increase costs linearly to avoid using all local registers */
730 mono_arch_allocate_vars (MonoCompile *cfg)
732 MonoMethodSignature *sig;
733 MonoMethodHeader *header;
736 guint32 locals_stack_size, locals_stack_align;
740 header = mono_method_get_header (cfg->method);
742 sig = mono_method_signature (cfg->method);
744 cinfo = get_call_info (sig, FALSE);
747 * Determine whenever the frame pointer can be eliminated.
748 * FIXME: Remove some of the restrictions.
750 cfg->arch.omit_fp = TRUE;
752 if (!debug_omit_fp ())
753 cfg->arch.omit_fp = FALSE;
755 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
756 cfg->arch.omit_fp = FALSE;
757 if (header->num_clauses)
758 cfg->arch.omit_fp = FALSE;
760 cfg->arch.omit_fp = FALSE;
761 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
762 ArgInfo *ainfo = &cinfo->args [i];
764 if (ainfo->storage == ArgOnStack) {
766 * The stack offset can only be determined when the frame
769 cfg->arch.omit_fp = FALSE;
773 mono_ia64_alloc_stacked_registers (cfg);
776 * We use the ABI calling conventions for managed code as well.
777 * Exception: valuetypes are never passed or returned in registers.
780 if (cfg->arch.omit_fp) {
781 cfg->frame_reg = IA64_SP;
782 offset = ARGS_OFFSET;
785 /* Locals are allocated backwards from %fp */
786 cfg->frame_reg = cfg->arch.reg_fp;
790 if (cfg->method->save_lmf) {
794 if (sig->ret->type != MONO_TYPE_VOID) {
795 switch (cinfo->ret.storage) {
797 cfg->ret->opcode = OP_REGVAR;
798 cfg->ret->inst_c0 = cinfo->ret.reg;
801 cfg->ret->opcode = OP_REGVAR;
802 cfg->ret->inst_c0 = cinfo->ret.reg;
804 case ArgValuetypeAddrInIReg:
805 cfg->ret->opcode = OP_REGVAR;
806 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
809 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
810 if (cfg->arch.omit_fp)
811 g_assert_not_reached ();
812 offset = ALIGN_TO (offset, 8);
813 offset += cinfo->ret.nslots * 8;
814 cfg->ret->opcode = OP_REGOFFSET;
815 cfg->ret->inst_basereg = cfg->frame_reg;
816 cfg->ret->inst_offset = - offset;
819 g_assert_not_reached ();
821 cfg->ret->dreg = cfg->ret->inst_c0;
824 /* Allocate locals */
825 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
826 if (locals_stack_align) {
827 offset = ALIGN_TO (offset, locals_stack_align);
829 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
830 if (offsets [i] != -1) {
831 MonoInst *inst = cfg->varinfo [i];
832 inst->opcode = OP_REGOFFSET;
833 inst->inst_basereg = cfg->frame_reg;
834 if (cfg->arch.omit_fp)
835 inst->inst_offset = (offset + offsets [i]);
837 inst->inst_offset = - (offset + offsets [i]);
838 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
841 offset += locals_stack_size;
843 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
844 if (cfg->arch.omit_fp)
845 g_assert_not_reached ();
846 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
847 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
850 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
851 inst = cfg->args [i];
852 if (inst->opcode != OP_REGVAR) {
853 ArgInfo *ainfo = &cinfo->args [i];
854 gboolean inreg = TRUE;
857 if (sig->hasthis && (i == 0))
858 arg_type = &mono_defaults.object_class->byval_arg;
860 arg_type = sig->params [i - sig->hasthis];
862 /* FIXME: VOLATILE is only set if the liveness pass runs */
863 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
866 inst->opcode = OP_REGOFFSET;
868 switch (ainfo->storage) {
870 inst->opcode = OP_REGVAR;
871 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
875 * Since float regs are volatile, we save the arguments to
876 * the stack in the prolog.
881 if (cfg->arch.omit_fp)
882 g_assert_not_reached ();
883 inst->opcode = OP_REGOFFSET;
884 inst->inst_basereg = cfg->frame_reg;
885 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
894 if (!inreg && (ainfo->storage != ArgOnStack)) {
895 inst->opcode = OP_REGOFFSET;
896 inst->inst_basereg = cfg->frame_reg;
897 /* These arguments are saved to the stack in the prolog */
898 switch (ainfo->storage) {
900 if (ainfo->atype == AggregateSingleHFA)
901 offset += ainfo->nslots * 4;
903 offset += ainfo->nslots * 8;
906 offset += sizeof (gpointer);
909 offset = ALIGN_TO (offset, sizeof (gpointer));
910 if (cfg->arch.omit_fp)
911 inst->inst_offset = offset;
913 inst->inst_offset = - offset;
918 if (cfg->arch.omit_fp && offset == 16)
921 cfg->stack_offset = offset;
927 mono_arch_create_vars (MonoCompile *cfg)
929 MonoMethodSignature *sig;
932 sig = mono_method_signature (cfg->method);
934 cinfo = get_call_info (sig, FALSE);
936 if (cinfo->ret.storage == ArgAggregate)
937 cfg->ret_var_is_local = TRUE;
943 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
947 arg->opcode = OP_OUTARG_REG;
948 arg->inst_left = tree;
949 arg->inst_right = (MonoInst*)call;
950 arg->backend.reg3 = reg;
951 call->used_iregs |= 1 << reg;
954 arg->opcode = OP_OUTARG_FREG;
955 arg->inst_left = tree;
956 arg->inst_right = (MonoInst*)call;
957 arg->backend.reg3 = reg;
958 call->used_fregs |= 1 << reg;
961 g_assert_not_reached ();
966 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
969 MonoMethodSignature *tmp_sig;
972 /* FIXME: Add support for signature tokens to AOT */
973 cfg->disable_aot = TRUE;
975 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
978 * mono_ArgIterator_Setup assumes the signature cookie is
979 * passed first and all the arguments which were before it are
980 * passed on the stack after the signature. So compensate by
981 * passing a different signature.
983 tmp_sig = mono_metadata_signature_dup (call->signature);
984 tmp_sig->param_count -= call->signature->sentinelpos;
985 tmp_sig->sentinelpos = 0;
986 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
988 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
989 sig_arg->inst_p0 = tmp_sig;
991 MONO_INST_NEW (cfg, arg, OP_OUTARG);
992 arg->inst_left = sig_arg;
993 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
994 arg->type = STACK_PTR;
996 /* prepend, so they get reversed */
997 arg->next = call->out_args;
998 call->out_args = arg;
1002 * take the arguments and generate the arch-specific
1003 * instructions to properly call the function in call.
1004 * This includes pushing, moving arguments to the right register
1008 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1011 MonoMethodSignature *sig;
1012 int i, n, stack_size;
1018 mono_ia64_alloc_stacked_registers (cfg);
1020 sig = call->signature;
1021 n = sig->param_count + sig->hasthis;
1023 cinfo = get_call_info (sig, sig->pinvoke);
1025 if (cinfo->ret.storage == ArgAggregate) {
1026 /* The code in emit_this_vret_arg needs a local */
1027 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1028 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1031 for (i = 0; i < n; ++i) {
1032 ainfo = cinfo->args + i;
1034 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1035 /* Emit the signature cookie just before the implicit arguments */
1036 emit_sig_cookie (cfg, call, cinfo);
1039 if (is_virtual && i == 0) {
1040 /* the argument will be attached to the call instruction */
1041 in = call->args [i];
1045 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1046 in = call->args [i];
1047 arg->cil_code = in->cil_code;
1048 arg->inst_left = in;
1049 arg->type = in->type;
1050 /* prepend, so they get reversed */
1051 arg->next = call->out_args;
1052 call->out_args = arg;
1054 if (sig->hasthis && (i == 0))
1055 arg_type = &mono_defaults.object_class->byval_arg;
1057 arg_type = sig->params [i - sig->hasthis];
1059 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1060 MonoInst *stack_addr;
1064 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1065 size = sizeof (MonoTypedRef);
1066 align = sizeof (gpointer);
1070 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1073 * Other backends use mono_type_stack_size (), but that
1074 * aligns the size to 8, which is larger than the size of
1075 * the source, leading to reads of invalid memory if the
1076 * source is at the end of address space.
1078 size = mono_class_value_size (in->klass, &align);
1081 if (ainfo->storage == ArgAggregate) {
1082 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1085 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1088 * Part of the structure is passed in registers.
1090 for (j = 0; j < ainfo->nregs; ++j) {
1091 int offset, load_op, dest_reg, arg_storage;
1093 slot = ainfo->reg + j;
1095 if (ainfo->atype == AggregateSingleHFA) {
1096 load_op = CEE_LDIND_R4;
1098 dest_reg = ainfo->reg + j;
1099 arg_storage = ArgInFloatReg;
1100 } else if (ainfo->atype == AggregateDoubleHFA) {
1101 load_op = CEE_LDIND_R8;
1103 dest_reg = ainfo->reg + j;
1104 arg_storage = ArgInFloatReg;
1106 load_op = CEE_LDIND_I;
1108 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1109 arg_storage = ArgInIReg;
1112 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1113 load->ssa_op = MONO_SSA_LOAD;
1114 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1116 NEW_ICONST (cfg, offset_ins, offset);
1117 MONO_INST_NEW (cfg, load2, CEE_ADD);
1118 load2->inst_left = load;
1119 load2->inst_right = offset_ins;
1121 MONO_INST_NEW (cfg, load, load_op);
1122 load->inst_left = load2;
1127 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1128 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1129 if (set_reg != call->out_args) {
1130 set_reg->next = call->out_args;
1131 call->out_args = set_reg;
1136 * Part of the structure is passed on the stack.
1138 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1141 slot = ainfo->reg + j;
1143 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1144 load->ssa_op = MONO_SSA_LOAD;
1145 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1147 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1148 MONO_INST_NEW (cfg, load2, CEE_ADD);
1149 load2->inst_left = load;
1150 load2->inst_right = offset_ins;
1152 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1153 load->inst_left = load2;
1158 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1159 outarg->inst_left = load;
1160 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1162 if (outarg != call->out_args) {
1163 outarg->next = call->out_args;
1164 call->out_args = outarg;
1168 /* Trees can't be shared so make a copy */
1169 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1170 arg->cil_code = in->cil_code;
1171 arg->ssa_op = MONO_SSA_STORE;
1172 arg->inst_left = vtaddr;
1173 arg->inst_right = in;
1174 arg->type = in->type;
1176 /* prepend, so they get reversed */
1177 arg->next = call->out_args;
1178 call->out_args = arg;
1181 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1182 stack_addr->inst_basereg = IA64_SP;
1183 stack_addr->inst_offset = 16 + ainfo->offset;
1184 stack_addr->inst_imm = size;
1186 arg->opcode = OP_OUTARG_VT;
1187 arg->inst_right = stack_addr;
1191 switch (ainfo->storage) {
1193 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1196 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1199 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1200 arg->opcode = OP_OUTARG_R4;
1203 arg->opcode = OP_OUTARG;
1204 arg->inst_imm = 16 + ainfo->offset;
1207 g_assert_not_reached ();
1213 /* Handle the case where there are no implicit arguments */
1214 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1215 emit_sig_cookie (cfg, call, cinfo);
1218 call->stack_usage = cinfo->stack_usage;
1219 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1220 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1221 cfg->flags |= MONO_CFG_HAS_CALLS;
1229 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1231 MonoInst *ins, *last_ins = NULL;
1235 switch (ins->opcode) {
1243 if (ins->dreg == ins->sreg1) {
1245 last_ins->next = ins->next;
1252 * OP_MOVE sreg, dreg
1253 * OP_MOVE dreg, sreg
1255 if (last_ins && last_ins->opcode == OP_MOVE &&
1256 ins->sreg1 == last_ins->dreg &&
1257 ins->dreg == last_ins->sreg1) {
1258 last_ins->next = ins->next;
1265 /* remove unnecessary multiplication with 1 */
1266 if (ins->inst_imm == 1) {
1267 if (ins->dreg != ins->sreg1) {
1268 ins->opcode = OP_MOVE;
1270 last_ins->next = ins->next;
1281 bb->last_ins = last_ins;
1284 int cond_to_ia64_cmp [][3] = {
1285 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1286 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1287 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1288 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1289 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1290 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1291 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1292 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1293 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1294 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1298 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1300 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1303 int cond_to_ia64_cmp_imm [][3] = {
1304 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1305 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1306 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1307 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1308 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1309 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1310 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1311 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1312 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1313 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1317 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1319 /* The condition needs to be reversed */
1320 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1324 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1328 bb->code = to_insert;
1329 to_insert->next = ins;
1332 to_insert->next = ins->next;
1333 ins->next = to_insert;
1337 #define NEW_INS(cfg,dest,op) do { \
1338 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1339 (dest)->opcode = (op); \
1340 insert_after_ins (bb, last_ins, (dest)); \
1341 last_ins = (dest); \
1345 * mono_arch_lowering_pass:
1347 * Converts complex opcodes into simpler ones so that each IR instruction
1348 * corresponds to one machine instruction.
1351 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1353 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1356 if (bb->max_vreg > cfg->rs->next_vreg)
1357 cfg->rs->next_vreg = bb->max_vreg;
1360 switch (ins->opcode) {
1361 case OP_STOREI1_MEMBASE_IMM:
1362 case OP_STOREI2_MEMBASE_IMM:
1363 case OP_STOREI4_MEMBASE_IMM:
1364 case OP_STOREI8_MEMBASE_IMM:
1365 case OP_STORE_MEMBASE_IMM:
1366 /* There are no store_membase instructions on ia64 */
1367 if (ins->inst_offset == 0) {
1369 } else if (ia64_is_imm14 (ins->inst_offset)) {
1370 NEW_INS (cfg, temp2, OP_ADD_IMM);
1371 temp2->sreg1 = ins->inst_destbasereg;
1372 temp2->inst_imm = ins->inst_offset;
1373 temp2->dreg = mono_regstate_next_int (cfg->rs);
1376 NEW_INS (cfg, temp, OP_I8CONST);
1377 temp->inst_c0 = ins->inst_offset;
1378 temp->dreg = mono_regstate_next_int (cfg->rs);
1379 NEW_INS (cfg, temp2, CEE_ADD);
1380 temp2->sreg1 = ins->inst_destbasereg;
1381 temp2->sreg2 = temp->dreg;
1382 temp2->dreg = mono_regstate_next_int (cfg->rs);
1385 switch (ins->opcode) {
1386 case OP_STOREI1_MEMBASE_IMM:
1387 ins->opcode = OP_STOREI1_MEMBASE_REG;
1389 case OP_STOREI2_MEMBASE_IMM:
1390 ins->opcode = OP_STOREI2_MEMBASE_REG;
1392 case OP_STOREI4_MEMBASE_IMM:
1393 ins->opcode = OP_STOREI4_MEMBASE_REG;
1395 case OP_STOREI8_MEMBASE_IMM:
1396 case OP_STORE_MEMBASE_IMM:
1397 ins->opcode = OP_STOREI8_MEMBASE_REG;
1400 g_assert_not_reached ();
1403 if (ins->inst_imm == 0)
1404 ins->sreg1 = IA64_R0;
1406 NEW_INS (cfg, temp3, OP_I8CONST);
1407 temp3->inst_c0 = ins->inst_imm;
1408 temp3->dreg = mono_regstate_next_int (cfg->rs);
1409 ins->sreg1 = temp3->dreg;
1412 ins->inst_offset = 0;
1414 ins->inst_destbasereg = temp2->dreg;
1416 case OP_STOREI1_MEMBASE_REG:
1417 case OP_STOREI2_MEMBASE_REG:
1418 case OP_STOREI4_MEMBASE_REG:
1419 case OP_STOREI8_MEMBASE_REG:
1420 case OP_STORER4_MEMBASE_REG:
1421 case OP_STORER8_MEMBASE_REG:
1422 case OP_STORE_MEMBASE_REG:
1423 /* There are no store_membase instructions on ia64 */
1424 if (ins->inst_offset == 0) {
1427 else if (ia64_is_imm14 (ins->inst_offset)) {
1428 NEW_INS (cfg, temp2, OP_ADD_IMM);
1429 temp2->sreg1 = ins->inst_destbasereg;
1430 temp2->inst_imm = ins->inst_offset;
1431 temp2->dreg = mono_regstate_next_int (cfg->rs);
1434 NEW_INS (cfg, temp, OP_I8CONST);
1435 temp->inst_c0 = ins->inst_offset;
1436 temp->dreg = mono_regstate_next_int (cfg->rs);
1437 NEW_INS (cfg, temp2, CEE_ADD);
1438 temp2->sreg1 = ins->inst_destbasereg;
1439 temp2->sreg2 = temp->dreg;
1440 temp2->dreg = mono_regstate_next_int (cfg->rs);
1443 ins->inst_offset = 0;
1444 ins->inst_destbasereg = temp2->dreg;
1446 case OP_LOADI1_MEMBASE:
1447 case OP_LOADU1_MEMBASE:
1448 case OP_LOADI2_MEMBASE:
1449 case OP_LOADU2_MEMBASE:
1450 case OP_LOADI4_MEMBASE:
1451 case OP_LOADU4_MEMBASE:
1452 case OP_LOADI8_MEMBASE:
1453 case OP_LOAD_MEMBASE:
1454 case OP_LOADR4_MEMBASE:
1455 case OP_LOADR8_MEMBASE:
1456 case OP_ATOMIC_EXCHANGE_I4:
1457 case OP_ATOMIC_EXCHANGE_I8:
1458 case OP_ATOMIC_ADD_NEW_I4:
1459 case OP_ATOMIC_ADD_NEW_I8:
1460 case OP_ATOMIC_ADD_IMM_NEW_I4:
1461 case OP_ATOMIC_ADD_IMM_NEW_I8:
1462 /* There are no membase instructions on ia64 */
1463 if (ins->inst_offset == 0) {
1466 else if (ia64_is_imm14 (ins->inst_offset)) {
1467 NEW_INS (cfg, temp2, OP_ADD_IMM);
1468 temp2->sreg1 = ins->inst_basereg;
1469 temp2->inst_imm = ins->inst_offset;
1470 temp2->dreg = mono_regstate_next_int (cfg->rs);
1473 NEW_INS (cfg, temp, OP_I8CONST);
1474 temp->inst_c0 = ins->inst_offset;
1475 temp->dreg = mono_regstate_next_int (cfg->rs);
1476 NEW_INS (cfg, temp2, CEE_ADD);
1477 temp2->sreg1 = ins->inst_basereg;
1478 temp2->sreg2 = temp->dreg;
1479 temp2->dreg = mono_regstate_next_int (cfg->rs);
1482 ins->inst_offset = 0;
1483 ins->inst_basereg = temp2->dreg;
1498 case OP_ISHR_UN_IMM:
1499 case OP_LSHR_UN_IMM: {
1500 gboolean is_imm = FALSE;
1501 gboolean switched = FALSE;
1503 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1504 ins->opcode = OP_ZEXT_I1;
1508 switch (ins->opcode) {
1511 is_imm = ia64_is_imm14 (ins->inst_imm);
1515 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1517 /* A = B - IMM -> A = B + (-IMM) */
1518 ins->inst_imm = - ins->inst_imm;
1519 ins->opcode = OP_IADD_IMM;
1527 is_imm = ia64_is_imm8 (ins->inst_imm);
1536 case OP_ISHR_UN_IMM:
1537 case OP_LSHR_UN_IMM:
1538 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1546 ins->sreg2 = ins->sreg1;
1550 switch (ins->opcode) {
1552 ins->opcode = CEE_ADD;
1555 ins->opcode = OP_IADD;
1558 ins->opcode = OP_ISUB;
1561 ins->opcode = OP_IAND;
1564 ins->opcode = OP_IOR;
1567 ins->opcode = OP_IXOR;
1570 ins->opcode = OP_ISHL;
1573 ins->opcode = OP_ISHR;
1575 case OP_ISHR_UN_IMM:
1576 ins->opcode = OP_ISHR_UN;
1579 ins->opcode = CEE_AND;
1582 ins->opcode = OP_LSHL;
1585 ins->opcode = OP_LSHR;
1588 ins->opcode = OP_LSHL;
1591 ins->opcode = OP_LSHR;
1593 case OP_LSHR_UN_IMM:
1594 ins->opcode = OP_LSHR_UN;
1597 g_assert_not_reached ();
1600 if (ins->inst_imm == 0)
1601 ins->sreg2 = IA64_R0;
1603 NEW_INS (cfg, temp, OP_I8CONST);
1604 temp->inst_c0 = ins->inst_imm;
1605 temp->dreg = mono_regstate_next_int (cfg->rs);
1606 ins->sreg2 = temp->dreg;
1610 case OP_COMPARE_IMM:
1611 case OP_ICOMPARE_IMM: {
1612 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1617 * The compare_imm instructions have switched up arguments, and
1618 * some of them take an imm between -127 and 128.
1621 cond = mono_opcode_to_cond (next->opcode);
1622 if ((cond == CMP_LT) || (cond == CMP_GE))
1623 imm = ia64_is_imm8 (ins->inst_imm - 1);
1624 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1625 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1627 imm = ia64_is_imm8 (ins->inst_imm);
1630 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1631 ins->sreg2 = ins->sreg1;
1634 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1636 if (ins->inst_imm == 0)
1637 ins->sreg2 = IA64_R0;
1639 NEW_INS (cfg, temp, OP_I8CONST);
1640 temp->inst_c0 = ins->inst_imm;
1641 temp->dreg = mono_regstate_next_int (cfg->rs);
1642 ins->sreg2 = temp->dreg;
1646 switch (next->opcode) {
1667 next->opcode = OP_IA64_BR_COND;
1668 if (! (next->flags & MONO_INST_BRLABEL))
1669 next->inst_target_bb = next->inst_true_bb;
1671 case OP_COND_EXC_EQ:
1672 case OP_COND_EXC_GT:
1673 case OP_COND_EXC_LT:
1674 case OP_COND_EXC_GT_UN:
1675 case OP_COND_EXC_LE_UN:
1676 case OP_COND_EXC_NE_UN:
1677 case OP_COND_EXC_LT_UN:
1678 next->opcode = OP_IA64_COND_EXC;
1690 next->opcode = OP_IA64_CSET;
1693 printf ("%s\n", mono_inst_name (next->opcode));
1703 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1707 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1708 switch (next->opcode) {
1739 next->opcode = OP_IA64_BR_COND;
1740 if (! (next->flags & MONO_INST_BRLABEL))
1741 next->inst_target_bb = next->inst_true_bb;
1743 case OP_COND_EXC_LT:
1744 case OP_COND_EXC_GT:
1745 case OP_COND_EXC_GT_UN:
1746 case OP_COND_EXC_LE_UN:
1747 next->opcode = OP_IA64_COND_EXC;
1764 next->opcode = OP_IA64_CSET;
1767 printf ("%s\n", mono_inst_name (next->opcode));
1776 gboolean found = FALSE;
1777 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1779 /* First the easy cases */
1780 if (ins->inst_imm == 1) {
1781 ins->opcode = OP_MOVE;
1784 for (i = 1; i < 64; ++i)
1785 if (ins->inst_imm == (((gint64)1) << i)) {
1786 ins->opcode = shl_op;
1792 /* This could be optimized */
1795 for (i = 0; i < 64; ++i) {
1796 if (ins->inst_imm & (((gint64)1) << i)) {
1797 NEW_INS (cfg, temp, shl_op);
1798 temp->dreg = mono_regstate_next_int (cfg->rs);
1799 temp->sreg1 = ins->sreg1;
1803 sum_reg = temp->dreg;
1805 NEW_INS (cfg, temp2, CEE_ADD);
1806 temp2->dreg = mono_regstate_next_int (cfg->rs);
1807 temp2->sreg1 = sum_reg;
1808 temp2->sreg2 = temp->dreg;
1809 sum_reg = temp2->dreg;
1813 ins->opcode = OP_MOVE;
1814 ins->sreg1 = sum_reg;
1818 case CEE_CONV_OVF_U4:
1819 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1820 temp->sreg1 = ins->sreg1;
1821 temp->sreg2 = IA64_R0;
1823 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1824 temp->inst_p1 = (char*)"OverflowException";
1826 ins->opcode = OP_MOVE;
1828 case CEE_CONV_OVF_I4_UN:
1829 NEW_INS (cfg, temp, OP_ICONST);
1830 temp->inst_c0 = 0x7fffffff;
1831 temp->dreg = mono_regstate_next_int (cfg->rs);
1833 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1834 temp2->sreg1 = ins->sreg1;
1835 temp2->sreg2 = temp->dreg;
1837 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1838 temp->inst_p1 = (char*)"OverflowException";
1840 ins->opcode = OP_MOVE;
1842 case OP_FCONV_TO_I4:
1843 case OP_FCONV_TO_I2:
1844 case OP_FCONV_TO_U2:
1845 case OP_FCONV_TO_I1:
1846 case OP_FCONV_TO_U1:
1847 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1848 temp->sreg1 = ins->sreg1;
1849 temp->dreg = ins->dreg;
1851 switch (ins->opcode) {
1852 case OP_FCONV_TO_I4:
1853 ins->opcode = OP_SEXT_I4;
1855 case OP_FCONV_TO_I2:
1856 ins->opcode = OP_SEXT_I2;
1858 case OP_FCONV_TO_U2:
1859 ins->opcode = OP_ZEXT_I4;
1861 case OP_FCONV_TO_I1:
1862 ins->opcode = OP_SEXT_I1;
1864 case OP_FCONV_TO_U1:
1865 ins->opcode = OP_ZEXT_I1;
1868 g_assert_not_reached ();
1870 ins->sreg1 = ins->dreg;
1878 bb->last_ins = last_ins;
1880 bb->max_vreg = cfg->rs->next_vreg;
1884 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1889 mono_arch_lowering_pass (cfg, bb);
1891 mono_local_regalloc (cfg, bb);
1895 * emit_load_volatile_arguments:
1897 * Load volatile arguments from the stack to the original input registers.
1898 * Required before a tail call.
1900 static Ia64CodegenState
1901 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1903 MonoMethod *method = cfg->method;
1904 MonoMethodSignature *sig;
1909 /* FIXME: Generate intermediate code instead */
1911 sig = mono_method_signature (method);
1913 cinfo = get_call_info (sig, FALSE);
1915 /* This is the opposite of the code in emit_prolog */
1916 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1917 ArgInfo *ainfo = cinfo->args + i;
1918 gint32 stack_offset;
1920 ins = cfg->args [i];
1922 if (sig->hasthis && (i == 0))
1923 arg_type = &mono_defaults.object_class->byval_arg;
1925 arg_type = sig->params [i - sig->hasthis];
1927 arg_type = mono_type_get_underlying_type (arg_type);
1929 stack_offset = ainfo->offset + ARGS_OFFSET;
1931 /* Save volatile arguments to the stack */
1932 if (ins->opcode != OP_REGVAR) {
1933 switch (ainfo->storage) {
1936 /* FIXME: big offsets */
1937 g_assert (ins->opcode == OP_REGOFFSET);
1938 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1939 if (arg_type->byref)
1940 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1942 switch (arg_type->type) {
1944 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1947 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1950 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1962 if (ins->opcode == OP_REGVAR) {
1963 /* Argument allocated to (non-volatile) register */
1964 switch (ainfo->storage) {
1966 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1967 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1970 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1971 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1984 static Ia64CodegenState
1985 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1990 /* Move return value to the target register */
1991 switch (ins->opcode) {
1993 case OP_VOIDCALL_REG:
1994 case OP_VOIDCALL_MEMBASE:
1998 case OP_CALL_MEMBASE:
2001 case OP_LCALL_MEMBASE:
2002 g_assert (ins->dreg == IA64_R8);
2006 case OP_FCALL_MEMBASE:
2007 g_assert (ins->dreg == 8);
2011 case OP_VCALL_MEMBASE: {
2014 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
2015 storage = cinfo->ret.storage;
2017 if (storage == ArgAggregate) {
2018 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2020 /* Load address of stack space allocated for the return value */
2021 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2022 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2023 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2025 for (i = 0; i < cinfo->ret.nregs; ++i) {
2026 switch (cinfo->ret.atype) {
2027 case AggregateNormal:
2028 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2030 case AggregateSingleHFA:
2031 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2033 case AggregateDoubleHFA:
2034 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2037 g_assert_not_reached ();
2045 g_assert_not_reached ();
2051 #define add_patch_info(cfg,code,patch_type,data) do { \
2052 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2055 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2056 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2058 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2060 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2061 ia64_br_cond_pred (code, (predicate), 0); \
2064 static Ia64CodegenState
2065 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2067 add_patch_info (cfg, code, patch_type, data);
2069 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2071 /* mono_arch_patch_callsite will patch this */
2072 /* mono_arch_nullify_class_init_trampoline will patch this */
2073 ia64_movl (code, GP_SCRATCH_REG, 0);
2074 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2075 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2076 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2077 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2080 /* Can't use a direct call since the displacement might be too small */
2081 /* mono_arch_patch_callsite will patch this */
2082 ia64_movl (code, GP_SCRATCH_REG, 0);
2083 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2084 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2090 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2093 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2098 Ia64CodegenState code;
2099 guint8 *code_start = cfg->native_code + cfg->code_len;
2100 MonoInst *last_ins = NULL;
2101 guint last_offset = 0;
2104 if (cfg->opt & MONO_OPT_PEEPHOLE)
2105 peephole_pass (cfg, bb);
2107 if (cfg->opt & MONO_OPT_LOOP) {
2111 if (cfg->verbose_level > 2)
2112 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2114 cpos = bb->max_offset;
2116 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2120 offset = code_start - cfg->native_code;
2122 ia64_codegen_init (code, code_start);
2125 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2131 offset = code.buf - cfg->native_code;
2133 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2135 while (offset + max_len + 16 > cfg->code_size) {
2136 ia64_codegen_close (code);
2138 offset = code.buf - cfg->native_code;
2140 cfg->code_size *= 2;
2141 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2142 code_start = cfg->native_code + offset;
2143 mono_jit_stats.code_reallocs++;
2145 ia64_codegen_init (code, code_start);
2148 mono_debug_record_line_number (cfg, ins, offset);
2150 switch (ins->opcode) {
2153 if (ia64_is_imm14 (ins->inst_c0))
2154 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2156 ia64_movl (code, ins->dreg, ins->inst_c0);
2159 ia64_mov (code, ins->dreg, ins->sreg1);
2162 case OP_IA64_BR_COND: {
2164 if (ins->opcode == OP_IA64_BR_COND)
2166 if (ins->flags & MONO_INST_BRLABEL) {
2167 if (ins->inst_i0->inst_c0) {
2170 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2171 ia64_br_cond_pred (code, pred, 0);
2174 if (ins->inst_target_bb->native_offset) {
2175 guint8 *pos = code.buf + code.nins;
2177 ia64_br_cond_pred (code, pred, 0);
2178 ia64_begin_bundle (code);
2179 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2181 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2182 ia64_br_cond_pred (code, pred, 0);
2188 ia64_begin_bundle (code);
2189 ins->inst_c0 = code.buf - cfg->native_code;
2194 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2195 ia64_br_cond_reg (code, IA64_B6);
2199 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2203 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2207 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2211 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2215 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2219 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2222 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2226 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2229 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2230 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2234 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2237 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2241 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2244 /* p6 and p7 is set if there is signed/unsigned overflow */
2246 /* Set p8-p9 == (sreg2 > 0) */
2247 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2249 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2251 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2252 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2253 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2254 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2256 /* res <u sreg1 => unsigned overflow */
2257 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2259 /* FIXME: Predicate this since this is a side effect */
2260 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2263 /* p6 and p7 is set if there is signed/unsigned overflow */
2265 /* Set p8-p9 == (sreg2 > 0) */
2266 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2268 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2270 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2271 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2272 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2273 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2275 /* sreg1 <u sreg2 => unsigned overflow */
2276 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2278 /* FIXME: Predicate this since this is a side effect */
2279 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2282 /* Same as OP_IADDCC */
2283 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2285 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2287 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2288 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2290 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2292 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2295 /* Same as OP_ISUBCC */
2297 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2299 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2301 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2302 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2304 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2306 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2310 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2314 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2317 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2320 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2325 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2330 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2332 case OP_ISHR_UN_IMM:
2333 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2334 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2336 case OP_LSHR_UN_IMM:
2337 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2340 /* Based on gcc code */
2341 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2342 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2343 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2344 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2347 case OP_STOREI1_MEMBASE_REG:
2348 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2350 case OP_STOREI2_MEMBASE_REG:
2351 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2353 case OP_STOREI4_MEMBASE_REG:
2354 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2356 case OP_STOREI8_MEMBASE_REG:
2357 case OP_STORE_MEMBASE_REG:
2358 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2361 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2362 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2364 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2365 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2367 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2368 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2370 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2371 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2374 case OP_LOADU1_MEMBASE:
2375 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2377 case OP_LOADU2_MEMBASE:
2378 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2380 case OP_LOADU4_MEMBASE:
2381 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2383 case OP_LOADI1_MEMBASE:
2384 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2385 ia64_sxt1 (code, ins->dreg, ins->dreg);
2387 case OP_LOADI2_MEMBASE:
2388 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2389 ia64_sxt2 (code, ins->dreg, ins->dreg);
2391 case OP_LOADI4_MEMBASE:
2392 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2393 ia64_sxt4 (code, ins->dreg, ins->dreg);
2395 case OP_LOAD_MEMBASE:
2396 case OP_LOADI8_MEMBASE:
2397 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2400 case OP_IA64_LOADU1_MEMBASE_INC:
2401 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2403 case OP_IA64_LOADU2_MEMBASE_INC:
2404 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2406 case OP_IA64_LOADU4_MEMBASE_INC:
2407 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2409 case OP_IA64_LOADI8_MEMBASE_INC:
2410 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2414 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2417 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2420 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2423 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2426 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2429 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2432 /* Compare opcodes */
2433 case OP_IA64_CMP4_EQ:
2434 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2436 case OP_IA64_CMP4_NE:
2437 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2439 case OP_IA64_CMP4_LE:
2440 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2442 case OP_IA64_CMP4_LT:
2443 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2445 case OP_IA64_CMP4_GE:
2446 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2448 case OP_IA64_CMP4_GT:
2449 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2451 case OP_IA64_CMP4_LT_UN:
2452 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2454 case OP_IA64_CMP4_LE_UN:
2455 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2457 case OP_IA64_CMP4_GT_UN:
2458 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2460 case OP_IA64_CMP4_GE_UN:
2461 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2463 case OP_IA64_CMP_EQ:
2464 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2466 case OP_IA64_CMP_NE:
2467 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2469 case OP_IA64_CMP_LE:
2470 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2472 case OP_IA64_CMP_LT:
2473 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2475 case OP_IA64_CMP_GE:
2476 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2478 case OP_IA64_CMP_GT:
2479 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2481 case OP_IA64_CMP_GT_UN:
2482 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2484 case OP_IA64_CMP_LT_UN:
2485 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2487 case OP_IA64_CMP_GE_UN:
2488 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2490 case OP_IA64_CMP_LE_UN:
2491 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2493 case OP_IA64_CMP4_EQ_IMM:
2494 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2496 case OP_IA64_CMP4_NE_IMM:
2497 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2499 case OP_IA64_CMP4_LE_IMM:
2500 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2502 case OP_IA64_CMP4_LT_IMM:
2503 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2505 case OP_IA64_CMP4_GE_IMM:
2506 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2508 case OP_IA64_CMP4_GT_IMM:
2509 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2511 case OP_IA64_CMP4_LT_UN_IMM:
2512 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2514 case OP_IA64_CMP4_LE_UN_IMM:
2515 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2517 case OP_IA64_CMP4_GT_UN_IMM:
2518 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2520 case OP_IA64_CMP4_GE_UN_IMM:
2521 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2523 case OP_IA64_CMP_EQ_IMM:
2524 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2526 case OP_IA64_CMP_NE_IMM:
2527 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2529 case OP_IA64_CMP_LE_IMM:
2530 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2532 case OP_IA64_CMP_LT_IMM:
2533 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2535 case OP_IA64_CMP_GE_IMM:
2536 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2538 case OP_IA64_CMP_GT_IMM:
2539 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2541 case OP_IA64_CMP_GT_UN_IMM:
2542 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2544 case OP_IA64_CMP_LT_UN_IMM:
2545 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2547 case OP_IA64_CMP_GE_UN_IMM:
2548 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2550 case OP_IA64_CMP_LE_UN_IMM:
2551 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2553 case OP_IA64_FCMP_EQ:
2554 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2556 case OP_IA64_FCMP_NE:
2557 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2559 case OP_IA64_FCMP_LT:
2560 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2562 case OP_IA64_FCMP_GT:
2563 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2565 case OP_IA64_FCMP_LE:
2566 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2568 case OP_IA64_FCMP_GE:
2569 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2571 case OP_IA64_FCMP_GT_UN:
2572 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2573 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2575 case OP_IA64_FCMP_LT_UN:
2576 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2577 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2579 case OP_IA64_FCMP_GE_UN:
2580 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2581 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2583 case OP_IA64_FCMP_LE_UN:
2584 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2585 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2588 case OP_COND_EXC_IOV:
2589 case OP_COND_EXC_OV:
2590 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2592 case OP_COND_EXC_IC:
2594 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2596 case OP_IA64_COND_EXC:
2597 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2600 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2601 ia64_no_stop (code);
2602 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2605 /* FIXME: Is this needed ? */
2606 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2609 /* FIXME: Is this needed ? */
2610 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2613 /* FIXME: Is this needed ? */
2614 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2617 /* FIXME: Is this needed */
2618 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2621 /* FIXME: Is this needed */
2622 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2625 /* FIXME: Is this needed */
2626 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2630 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2634 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2641 double d = *(double *)ins->inst_p0;
2643 if ((d == 0.0) && (mono_signbit (d) == 0))
2644 ia64_fmov (code, ins->dreg, 0);
2646 ia64_fmov (code, ins->dreg, 1);
2648 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2649 ia64_movl (code, GP_SCRATCH_REG, 0);
2650 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2655 float f = *(float *)ins->inst_p0;
2657 if ((f == 0.0) && (mono_signbit (f) == 0))
2658 ia64_fmov (code, ins->dreg, 0);
2660 ia64_fmov (code, ins->dreg, 1);
2662 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2663 ia64_movl (code, GP_SCRATCH_REG, 0);
2664 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2669 ia64_fmov (code, ins->dreg, ins->sreg1);
2671 case OP_STORER8_MEMBASE_REG:
2672 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2674 case OP_STORER4_MEMBASE_REG:
2675 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2676 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2678 case OP_LOADR8_MEMBASE:
2679 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2681 case OP_LOADR4_MEMBASE:
2682 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2683 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2686 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2687 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2688 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2691 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2692 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2693 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2695 case OP_LCONV_TO_R8:
2696 /* FIXME: Difference with CEE_CONV_R8 ? */
2697 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2698 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2699 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2701 case OP_LCONV_TO_R4:
2702 /* FIXME: Difference with CEE_CONV_R4 ? */
2703 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2704 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2705 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2707 case OP_FCONV_TO_R4:
2708 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2710 case OP_FCONV_TO_I8:
2711 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2712 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2715 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2718 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2721 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2724 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2728 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2729 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2731 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2732 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2733 /* Positive infinity */
2734 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2735 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2736 /* Negative infinity */
2737 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2738 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2743 /* ensure ins->sreg1 is not NULL */
2744 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2747 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2748 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2755 call = (MonoCallInst*)ins;
2757 if (ins->flags & MONO_INST_HAS_METHOD)
2758 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2760 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2762 code = emit_move_return_value (cfg, ins, code);
2769 case OP_VOIDCALL_REG:
2770 call = (MonoCallInst*)ins;
2774 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2777 ia64_mov (code, IA64_R8, ins->sreg1);
2778 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2779 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2780 ia64_ld8 (code, IA64_GP, IA64_R8);
2781 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2783 code = emit_move_return_value (cfg, ins, code);
2786 case OP_FCALL_MEMBASE:
2787 case OP_LCALL_MEMBASE:
2788 case OP_VCALL_MEMBASE:
2789 case OP_VOIDCALL_MEMBASE:
2790 case OP_CALL_MEMBASE:
2792 * There are no membase instructions on ia64, but we can't
2793 * lower this since get_vcall_slot_addr () needs to decode it.
2796 /* Keep this in synch with get_vcall_slot_addr */
2797 if (ia64_is_imm14 (ins->inst_offset))
2798 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2800 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2801 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2804 ia64_begin_bundle (code);
2805 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2807 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2809 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2812 * This nop will tell get_vcall_slot_addr that this is a virtual
2815 ia64_nop_i (code, 0x12345);
2817 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2819 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2821 code = emit_move_return_value (cfg, ins, code);
2825 * Keep in sync with the code in emit_epilog.
2828 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2831 g_assert (!cfg->method->save_lmf);
2833 /* Load arguments into their original registers */
2834 code = emit_load_volatile_arguments (cfg, code);
2836 if (cfg->arch.stack_alloc_size) {
2837 if (cfg->arch.omit_fp) {
2838 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2839 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2841 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2842 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2846 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2848 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2849 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2851 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2852 ia64_movl (code, GP_SCRATCH_REG, 0);
2853 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2854 ia64_br_cond_reg (code, IA64_B6);
2859 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2865 /* FIXME: Sigaltstack support */
2867 /* keep alignment */
2868 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2869 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2870 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2872 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2874 ia64_mov (code, ins->dreg, IA64_SP);
2876 /* An area at sp is reserved by the ABI for parameter passing */
2877 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2878 if (ia64_is_adds_imm (abi_offset))
2879 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2881 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2882 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2885 if (ins->flags & MONO_INST_INIT) {
2887 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2889 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2892 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2893 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2894 ia64_br_cond_pred (code, 8, -2);
2896 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2898 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2904 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2905 ia64_ld8 (code, ins->dreg, ins->dreg);
2908 /* Synchronization */
2909 case OP_MEMORY_BARRIER:
2912 case OP_ATOMIC_ADD_IMM_NEW_I4:
2913 g_assert (ins->inst_offset == 0);
2914 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2915 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2917 case OP_ATOMIC_ADD_IMM_NEW_I8:
2918 g_assert (ins->inst_offset == 0);
2919 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2920 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2922 case OP_ATOMIC_EXCHANGE_I4:
2923 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2924 ia64_sxt4 (code, ins->dreg, ins->dreg);
2926 case OP_ATOMIC_EXCHANGE_I8:
2927 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2929 case OP_ATOMIC_ADD_NEW_I4: {
2930 guint8 *label, *buf;
2932 /* From libatomic_ops */
2935 ia64_begin_bundle (code);
2936 label = code.buf + code.nins;
2937 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2938 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2939 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2940 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2941 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2942 buf = code.buf + code.nins;
2943 ia64_br_cond_pred (code, 7, 0);
2944 ia64_begin_bundle (code);
2945 ia64_patch (buf, label);
2946 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2949 case OP_ATOMIC_ADD_NEW_I8: {
2950 guint8 *label, *buf;
2952 /* From libatomic_ops */
2955 ia64_begin_bundle (code);
2956 label = code.buf + code.nins;
2957 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2958 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2959 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2960 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2961 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2962 buf = code.buf + code.nins;
2963 ia64_br_cond_pred (code, 7, 0);
2964 ia64_begin_bundle (code);
2965 ia64_patch (buf, label);
2966 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2970 /* Exception handling */
2971 case OP_CALL_HANDLER:
2973 * Using a call instruction would mess up the register stack, so
2974 * save the return address to a register and use a
2977 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2978 ia64_mov (code, IA64_R15, IA64_R0);
2979 ia64_mov_from_ip (code, GP_SCRATCH_REG);
2980 /* Add the length of OP_CALL_HANDLER */
2981 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
2982 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2983 ia64_movl (code, GP_SCRATCH_REG2, 0);
2984 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2985 ia64_br_cond_reg (code, IA64_B6);
2986 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2988 case OP_START_HANDLER: {
2990 * We receive the return address in GP_SCRATCH_REG.
2992 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2995 * R15 determines our caller. It is used since it is writable using
2997 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
2998 * R15 != 0 means we are called by call_filter ().
3000 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3001 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3003 ia64_br_cond_pred (code, 6, 6);
3006 * Called by call_filter:
3007 * Allocate a new stack frame, and set the fp register from the
3008 * value passed in by the caller.
3009 * We allocate a similar frame as is done by the prolog, so
3010 * if an exception is thrown while executing the filter, the
3011 * unwinder can unwind through the filter frame using the unwind
3012 * info for the prolog.
3014 ia64_alloc (code, cfg->arch.reg_saved_ar_pfs, cfg->arch.reg_local0 - cfg->arch.reg_in0, cfg->arch.reg_out0 - cfg->arch.reg_local0, cfg->arch.n_out_regs, 0);
3015 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3016 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3017 ia64_mov (code, cfg->frame_reg, IA64_R15);
3018 /* Signal to endfilter that we are called by call_filter */
3019 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3021 /* Save the return address */
3022 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3023 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3024 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3029 case OP_ENDFILTER: {
3030 /* FIXME: Return the value in ENDFILTER */
3031 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3033 /* Load the return address */
3034 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3035 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3038 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3039 ia64_br_cond_pred (code, 7, 4);
3041 /* Called by call_filter */
3043 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3044 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3045 ia64_br_ret_reg (code, IA64_B0);
3047 /* Called by CALL_HANDLER */
3048 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3049 ia64_br_cond_reg (code, IA64_B6);
3053 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3054 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3055 (gpointer)"mono_arch_throw_exception");
3058 * This might be the last instruction in the method, so add a dummy
3059 * instruction so the unwinder will work.
3061 ia64_break_i (code, 0);
3064 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3065 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3066 (gpointer)"mono_arch_rethrow_exception");
3068 ia64_break_i (code, 0);
3072 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3073 g_assert_not_reached ();
3076 if ((code.buf - cfg->native_code - offset) > max_len) {
3077 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3078 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3079 g_assert_not_reached ();
3085 last_offset = offset;
3090 ia64_codegen_close (code);
3092 cfg->code_len = code.buf - cfg->native_code;
3096 mono_arch_register_lowlevel_calls (void)
3098 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3101 static Ia64InsType ins_types_in_template [32][3] = {
3102 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3103 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3104 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3105 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3106 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3107 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3110 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3111 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3112 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3113 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3114 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3115 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3116 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3117 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3118 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3119 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3120 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3121 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3124 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3125 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3126 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3127 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3130 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3131 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3136 static gboolean stops_in_template [32][3] = {
3137 { FALSE, FALSE, FALSE },
3138 { FALSE, FALSE, TRUE },
3139 { FALSE, TRUE, FALSE },
3140 { FALSE, TRUE, TRUE },
3141 { FALSE, FALSE, FALSE },
3142 { FALSE, FALSE, TRUE },
3143 { FALSE, FALSE, FALSE },
3144 { FALSE, FALSE, FALSE },
3146 { FALSE, FALSE, FALSE },
3147 { FALSE, FALSE, TRUE },
3148 { TRUE, FALSE, FALSE },
3149 { TRUE, FALSE, TRUE },
3150 { FALSE, FALSE, FALSE },
3151 { FALSE, FALSE, TRUE },
3152 { FALSE, FALSE, FALSE },
3153 { FALSE, FALSE, TRUE },
3155 { FALSE, FALSE, FALSE },
3156 { FALSE, FALSE, TRUE },
3157 { FALSE, FALSE, FALSE },
3158 { FALSE, FALSE, TRUE },
3159 { FALSE, FALSE, FALSE },
3160 { FALSE, FALSE, FALSE },
3161 { FALSE, FALSE, FALSE },
3162 { FALSE, FALSE, TRUE },
3164 { FALSE, FALSE, FALSE },
3165 { FALSE, FALSE, TRUE },
3166 { FALSE, FALSE, FALSE },
3167 { FALSE, FALSE, FALSE },
3168 { FALSE, FALSE, FALSE },
3169 { FALSE, FALSE, TRUE },
3170 { FALSE, FALSE, FALSE },
3171 { FALSE, FALSE, FALSE }
3174 static int last_stop_in_template [32] = {
3175 -1, 2, 1, 2, -1, 2, -1, -1,
3176 -1, 2, 0, 2, -1, 2, -1, 2,
3177 -1, 2, -1, 2, -1, -1, -1, 2,
3178 -1, 2, -1, -1, -1, 2, -1, -1
3181 static guint64 nops_for_ins_types [6] = {
3190 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3197 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3199 #define DEBUG_INS_SCHED(a)
3203 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3205 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3206 guint8 *deps = code->dep_info;
3207 gboolean need_stop, no_stop;
3209 for (i = 0; i < code->nins; ++i)
3213 current_deps_start = 0;
3214 current_ins_start = 0;
3215 deps_start [ins_index] = current_ins_start;
3218 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3219 while (pos < code->dep_info_pos) {
3221 switch (deps [pos]) {
3222 case IA64_END_OF_INS:
3224 current_ins_start = pos + 2;
3225 deps_start [ins_index] = current_ins_start;
3227 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3232 reg = deps [pos + 1];
3234 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3235 for (i = current_deps_start; i < current_ins_start; i += 2)
3236 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3240 reg = code->dep_info [pos + 1];
3242 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3243 for (i = current_deps_start; i < current_ins_start; i += 2)
3244 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3248 reg = deps [pos + 1];
3250 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3251 for (i = current_deps_start; i < current_ins_start; i += 2)
3252 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3255 case IA64_READ_PR_BRANCH:
3256 reg = deps [pos + 1];
3258 /* Writes to prs by non-float instructions are visible to branches */
3259 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3260 for (i = current_deps_start; i < current_ins_start; i += 2)
3261 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3265 reg = code->dep_info [pos + 1];
3267 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3268 for (i = current_deps_start; i < current_ins_start; i += 2)
3269 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3272 case IA64_WRITE_PR_FLOAT:
3273 reg = code->dep_info [pos + 1];
3275 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3276 for (i = current_deps_start; i < current_ins_start; i += 2)
3277 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3281 reg = deps [pos + 1];
3283 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3284 for (i = current_deps_start; i < current_ins_start; i += 2)
3285 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3289 reg = code->dep_info [pos + 1];
3291 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3292 for (i = current_deps_start; i < current_ins_start; i += 2)
3293 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3296 case IA64_READ_BR_BRANCH:
3297 reg = deps [pos + 1];
3299 /* Writes to brs are visible to branches */
3300 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3303 reg = deps [pos + 1];
3305 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3306 for (i = current_deps_start; i < current_ins_start; i += 2)
3307 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3311 reg = code->dep_info [pos + 1];
3313 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3314 for (i = current_deps_start; i < current_ins_start; i += 2)
3315 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3319 reg = deps [pos + 1];
3321 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3322 for (i = current_deps_start; i < current_ins_start; i += 2)
3323 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3327 reg = code->dep_info [pos + 1];
3329 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3330 for (i = current_deps_start; i < current_ins_start; i += 2)
3331 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3336 * Explicitly indicate that a stop is not required. Useful for
3337 * example when two predicated instructions with negated predicates
3338 * write the same registers.
3343 g_assert_not_reached ();
3347 if (need_stop && !no_stop) {
3348 g_assert (ins_index > 0);
3349 stops [ins_index - 1] = 1;
3351 DEBUG_INS_SCHED (printf ("STOP\n"));
3352 current_deps_start = current_ins_start;
3354 /* Skip remaining deps for this instruction */
3355 while (deps [pos] != IA64_END_OF_INS)
3360 if (code->nins > 0) {
3361 /* No dependency info for the last instruction */
3362 stops [code->nins - 1] = 1;
3365 deps_start [code->nins] = code->dep_info_pos;
3369 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3371 int stop_pos, i, deps_to_shift, dep_shift;
3373 g_assert (n <= code->nins);
3375 // if (n > 1) printf ("FOUND: %ld.\n", template);
3377 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3379 stop_pos = last_stop_in_template [template] + 1;
3383 /* Compute the number of 'real' instructions before the stop */
3384 deps_to_shift = stop_pos;
3385 if (stop_pos >= 3 && (nops & (1 << 2)))
3387 if (stop_pos >= 2 && (nops & (1 << 1)))
3389 if (stop_pos >= 1 && (nops & (1 << 0)))
3393 * We have to keep some dependencies whose instructions have been shifted
3394 * out of the buffer. So nullify the end_of_ins markers in the dependency
3397 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3398 if (code->dep_info [i] == IA64_END_OF_INS)
3399 code->dep_info [i] = IA64_NONE;
3401 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3402 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3403 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3405 dep_shift = deps_start [deps_to_shift];
3406 for (i = 0; i < code->nins + 1 - n; ++i)
3407 deps_start [i] = deps_start [n + i] - dep_shift;
3409 /* Determine the exact positions of instructions with unwind ops */
3410 if (code->unw_op_count) {
3412 int curr_ins, curr_ins_pos;
3415 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3416 for (i = 0; i < 3; ++i) {
3417 if (! (nops & (1 << i))) {
3418 ins_pos [curr_ins] = curr_ins_pos + i;
3423 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3424 if (code->unw_ops_pos [i] < n) {
3425 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3426 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3429 if (code->unw_op_pos < code->unw_op_count)
3430 code->unw_op_pos += n;
3433 if (n == code->nins) {
3438 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3439 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3440 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3446 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3448 int i, ins_type, template, nins_to_emit;
3449 int deps_start [16];
3454 * We implement a simple scheduler which tries to put three instructions
3455 * per bundle, then two, then one.
3457 ia64_analyze_deps (code, deps_start, stops);
3459 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3460 /* Find a suitable template */
3461 for (template = 0; template < 32; ++template) {
3462 if (stops_in_template [template][0] != stops [0] ||
3463 stops_in_template [template][1] != stops [1] ||
3464 stops_in_template [template][2] != stops [2])
3468 for (i = 0; i < 3; ++i) {
3469 ins_type = ins_types_in_template [template][i];
3470 switch (code->itypes [i]) {
3471 case IA64_INS_TYPE_A:
3472 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3475 found &= (ins_type == code->itypes [i]);
3481 found = debug_ins_sched ();
3484 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3490 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3491 /* Wait for more instructions */
3494 /* If it didn't work out, try putting two instructions into one bundle */
3495 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3496 /* Try a nop at the end */
3497 for (template = 0; template < 32; ++template) {
3498 if (stops_in_template [template][0] != stops [0] ||
3499 ((stops_in_template [template][1] != stops [1]) &&
3500 (stops_in_template [template][2] != stops [1])))
3504 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3505 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3508 if (!debug_ins_sched ())
3511 ia64_real_emit_bundle (code, deps_start, stops, 2, template, code->instructions [0], code->instructions [1], nops_for_ins_types [ins_types_in_template [template][2]], 1 << 2);
3516 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3517 /* Wait for more instructions */
3520 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3521 /* Try a nop in the middle */
3522 for (template = 0; template < 32; ++template) {
3523 if (((stops_in_template [template][0] != stops [0]) &&
3524 (stops_in_template [template][1] != stops [0])) ||
3525 stops_in_template [template][2] != stops [1])
3528 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3529 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3532 if (!debug_ins_sched ())
3535 ia64_real_emit_bundle (code, deps_start, stops, 2, template, code->instructions [0], nops_for_ins_types [ins_types_in_template [template][1]], code->instructions [1], 1 << 1);
3540 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3541 /* Try a nop at the beginning */
3542 for (template = 0; template < 32; ++template) {
3543 if ((stops_in_template [template][1] != stops [0]) ||
3544 (stops_in_template [template][2] != stops [1]))
3547 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3548 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3551 if (!debug_ins_sched ())
3554 ia64_real_emit_bundle (code, deps_start, stops, 2, template, nops_for_ins_types [ins_types_in_template [template][0]], code->instructions [0], code->instructions [1], 1 << 0);
3559 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3560 /* Wait for more instructions */
3564 nins_to_emit = code->nins;
3568 while (nins_to_emit > 0) {
3569 if (!debug_ins_sched ())
3571 switch (code->itypes [0]) {
3572 case IA64_INS_TYPE_A:
3574 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3576 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3578 case IA64_INS_TYPE_I:
3580 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3582 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3584 case IA64_INS_TYPE_M:
3586 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3588 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3590 case IA64_INS_TYPE_B:
3592 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3594 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3596 case IA64_INS_TYPE_F:
3598 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3600 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3602 case IA64_INS_TYPE_LX:
3603 if (stops [0] || stops [1])
3604 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3606 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3610 g_assert_not_reached ();
3616 unw_dyn_region_info_t*
3617 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3619 unw_dyn_region_info_t *r;
3621 g_assert (code->nins == 0);
3622 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3623 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3624 r->op_count = code->unw_op_count;
3625 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3626 code->unw_op_count = 0;
3627 code->unw_op_pos = 0;
3628 code->region_start = code->buf;
3634 ia64_patch (unsigned char* code, gpointer target)
3637 guint64 instructions [3];
3638 guint8 gen_buf [16];
3639 Ia64CodegenState gen;
3644 * code encodes both the position inside the buffer and code.nins when
3645 * the instruction was emitted.
3647 ins_to_skip = (guint64)code % 16;
3648 code = (unsigned char*)((guint64)code & ~15);
3651 * Search for the first instruction which is 'patchable', skipping
3652 * ins_to_skip instructions.
3657 template = ia64_bundle_template (code);
3658 instructions [0] = ia64_bundle_ins1 (code);
3659 instructions [1] = ia64_bundle_ins2 (code);
3660 instructions [2] = ia64_bundle_ins3 (code);
3662 ia64_codegen_init (gen, gen_buf);
3665 for (i = 0; i < 3; ++i) {
3666 guint64 ins = instructions [i];
3667 int opcode = ia64_ins_opcode (ins);
3669 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3677 switch (ins_types_in_template [template][i]) {
3678 case IA64_INS_TYPE_A:
3679 case IA64_INS_TYPE_M:
3680 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3682 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3683 instructions [i] = gen.instructions [0];
3689 case IA64_INS_TYPE_B:
3690 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3692 gint64 disp = ((guint8*)target - code) >> 4;
3695 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3697 instructions [i] = gen.instructions [0];
3700 else if (opcode == 5) {
3702 gint64 disp = ((guint8*)target - code) >> 4;
3705 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3706 instructions [i] = gen.instructions [0];
3712 case IA64_INS_TYPE_LX:
3716 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3718 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3719 instructions [1] = gen.instructions [0];
3720 instructions [2] = gen.instructions [1];
3733 ia64_codegen_init (gen, code);
3734 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3744 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3746 MonoJumpInfo *patch_info;
3748 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3749 unsigned char *ip = patch_info->ip.i + code;
3750 const unsigned char *target;
3752 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3754 if (patch_info->type == MONO_PATCH_INFO_NONE)
3756 if (mono_compile_aot) {
3760 ia64_patch (ip, (gpointer)target);
3765 mono_arch_emit_prolog (MonoCompile *cfg)
3767 MonoMethod *method = cfg->method;
3768 MonoMethodSignature *sig;
3770 int alloc_size, pos, i;
3771 Ia64CodegenState code;
3774 sig = mono_method_signature (method);
3777 cinfo = get_call_info (sig, FALSE);
3779 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3781 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3782 cfg->code_size += 1024;
3783 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3784 cfg->code_size += 1024;
3786 cfg->native_code = g_malloc (cfg->code_size);
3788 ia64_codegen_init (code, cfg->native_code);
3790 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3791 if (cfg->param_area)
3792 alloc_size += cfg->param_area;
3796 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3798 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3799 /* Force sp to be saved/restored */
3800 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3802 cfg->arch.stack_alloc_size = alloc_size;
3806 if (method->save_lmf) {
3807 /* No LMF on IA64 */
3812 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3813 ia64_alloc (code, cfg->arch.reg_saved_ar_pfs, cfg->arch.reg_local0 - cfg->arch.reg_in0, cfg->arch.reg_out0 - cfg->arch.reg_local0, cfg->arch.n_out_regs, 0);
3814 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3815 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3817 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3818 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3819 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3820 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3821 ia64_mov (code, cfg->frame_reg, IA64_SP);
3825 int pagesize = getpagesize ();
3827 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3828 if (alloc_size >= pagesize) {
3829 gint32 remaining_size = alloc_size;
3831 /* Generate stack touching code */
3832 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3833 while (remaining_size >= pagesize) {
3834 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3835 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3836 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3837 remaining_size -= pagesize;
3841 if (ia64_is_imm14 (-alloc_size)) {
3842 if (cfg->arch.omit_fp)
3843 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3844 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3847 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3848 if (cfg->arch.omit_fp)
3849 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3850 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3854 ia64_begin_bundle (code);
3856 /* Initialize unwind info */
3857 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3859 if (sig->ret->type != MONO_TYPE_VOID) {
3860 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3861 /* Save volatile arguments to the stack */
3866 /* Keep this in sync with emit_load_volatile_arguments */
3867 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3868 ArgInfo *ainfo = cinfo->args + i;
3869 gint32 stack_offset;
3871 inst = cfg->args [i];
3873 if (sig->hasthis && (i == 0))
3874 arg_type = &mono_defaults.object_class->byval_arg;
3876 arg_type = sig->params [i - sig->hasthis];
3878 arg_type = mono_type_get_underlying_type (arg_type);
3880 stack_offset = ainfo->offset + ARGS_OFFSET;
3882 /* Save volatile arguments to the stack */
3883 if (inst->opcode != OP_REGVAR) {
3884 switch (ainfo->storage) {
3887 g_assert (inst->opcode == OP_REGOFFSET);
3888 if (ia64_is_adds_imm (inst->inst_offset))
3889 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3891 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3892 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3894 if (arg_type->byref)
3895 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3897 switch (arg_type->type) {
3899 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3902 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3905 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3913 if (ainfo->nslots != ainfo->nregs)
3916 g_assert (inst->opcode == OP_REGOFFSET);
3917 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3918 for (i = 0; i < ainfo->nregs; ++i) {
3919 switch (ainfo->atype) {
3920 case AggregateNormal:
3921 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3923 case AggregateSingleHFA:
3924 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3926 case AggregateDoubleHFA:
3927 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3935 g_assert_not_reached ();
3939 if (inst->opcode == OP_REGVAR) {
3940 /* Argument allocated to (non-volatile) register */
3941 switch (ainfo->storage) {
3943 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3944 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3947 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3948 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3956 if (method->save_lmf) {
3957 /* No LMF on IA64 */
3960 ia64_codegen_close (code);
3964 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3965 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
3967 cfg->code_len = code.buf - cfg->native_code;
3969 g_assert (cfg->code_len < cfg->code_size);
3971 cfg->arch.prolog_end_offset = cfg->code_len;
3977 mono_arch_emit_epilog (MonoCompile *cfg)
3979 MonoMethod *method = cfg->method;
3981 int max_epilog_size = 16 * 4;
3982 Ia64CodegenState code;
3987 if (mono_jit_trace_calls != NULL)
3988 max_epilog_size += 1024;
3990 cfg->arch.epilog_begin_offset = cfg->code_len;
3992 while (cfg->code_len + max_epilog_size > cfg->code_size) {
3993 cfg->code_size *= 2;
3994 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3995 mono_jit_stats.code_reallocs++;
3998 /* FIXME: Emit unwind info */
4000 buf = cfg->native_code + cfg->code_len;
4002 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4003 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4005 ia64_codegen_init (code, buf);
4007 /* the code restoring the registers must be kept in sync with OP_JMP */
4010 if (method->save_lmf) {
4011 /* No LMF on IA64 */
4014 /* Load returned vtypes into registers if needed */
4015 cinfo = get_call_info (mono_method_signature (method), FALSE);
4016 ainfo = &cinfo->ret;
4017 switch (ainfo->storage) {
4019 if (ainfo->nslots != ainfo->nregs)
4022 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4023 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4024 for (i = 0; i < ainfo->nregs; ++i) {
4025 switch (ainfo->atype) {
4026 case AggregateNormal:
4027 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4029 case AggregateSingleHFA:
4030 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4032 case AggregateDoubleHFA:
4033 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4036 g_assert_not_reached ();
4045 ia64_begin_bundle (code);
4047 code.region_start = cfg->native_code;
4049 /* Label the unwind state at the start of the exception throwing region */
4050 //ia64_unw_label_state (code, 1234);
4052 if (cfg->arch.stack_alloc_size) {
4053 if (cfg->arch.omit_fp) {
4054 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4055 ia64_unw_pop_frames (code, 1);
4056 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4058 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4059 ia64_unw_pop_frames (code, 1);
4060 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4064 ia64_unw_pop_frames (code, 1);
4065 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4068 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4069 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4070 ia64_br_ret_reg (code, IA64_B0);
4072 ia64_codegen_close (code);
4074 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4075 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4077 cfg->code_len = code.buf - cfg->native_code;
4079 g_assert (cfg->code_len < cfg->code_size);
4083 mono_arch_emit_exceptions (MonoCompile *cfg)
4085 MonoJumpInfo *patch_info;
4087 Ia64CodegenState code;
4088 gboolean empty = TRUE;
4089 //unw_dyn_region_info_t *r_exceptions;
4090 MonoClass *exc_classes [16];
4091 guint8 *exc_throw_start [16], *exc_throw_end [16];
4092 guint32 code_size = 0;
4094 /* Compute needed space */
4095 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4096 if (patch_info->type == MONO_PATCH_INFO_EXC)
4098 if (patch_info->type == MONO_PATCH_INFO_R8)
4099 code_size += 8 + 7; /* sizeof (double) + alignment */
4100 if (patch_info->type == MONO_PATCH_INFO_R4)
4101 code_size += 4 + 7; /* sizeof (float) + alignment */
4107 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4108 cfg->code_size *= 2;
4109 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4110 mono_jit_stats.code_reallocs++;
4113 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4115 /* The unwind state here is the same as before the epilog */
4116 //ia64_unw_copy_state (code, 1234);
4118 /* add code to raise exceptions */
4119 /* FIXME: Optimize this */
4121 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4122 switch (patch_info->type) {
4123 case MONO_PATCH_INFO_EXC: {
4124 MonoClass *exc_class;
4127 guint64 exc_token_index;
4129 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4130 g_assert (exc_class);
4131 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4132 throw_ip = cfg->native_code + patch_info->ip.i;
4134 ia64_begin_bundle (code);
4136 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4138 /* Find a throw sequence for the same exception class */
4139 for (i = 0; i < nthrows; ++i)
4140 if (exc_classes [i] == exc_class)
4144 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4146 if (ia64_is_adds_imm (offset))
4147 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4149 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4151 buf = code.buf + code.nins;
4152 ia64_br_cond_pred (code, 0, 0);
4153 ia64_begin_bundle (code);
4154 ia64_patch (buf, exc_throw_start [i]);
4156 patch_info->type = MONO_PATCH_INFO_NONE;
4161 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4163 ia64_begin_bundle (code);
4166 exc_classes [nthrows] = exc_class;
4167 exc_throw_start [nthrows] = code.buf;
4171 if (ia64_is_adds_imm (exc_token_index))
4172 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4174 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4176 patch_info->data.name = "mono_arch_throw_corlib_exception";
4177 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4178 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4181 ia64_movl (code, GP_SCRATCH_REG, 0);
4182 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4183 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4184 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4186 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4188 /* Patch up the throw offset */
4189 ia64_begin_bundle (code);
4191 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4194 exc_throw_end [nthrows] = code.buf;
4208 /* The unwinder needs this to work */
4209 ia64_break_i (code, 0);
4211 ia64_codegen_close (code);
4214 //r_exceptions = mono_ia64_create_unwind_region (&code);
4215 //cfg->arch.r_epilog = r_exceptions;
4217 cfg->code_len = code.buf - cfg->native_code;
4219 g_assert (cfg->code_len < cfg->code_size);
4223 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4225 Ia64CodegenState code;
4226 CallInfo *cinfo = NULL;
4227 MonoMethodSignature *sig;
4229 int i, n, stack_area = 0;
4231 ia64_codegen_init (code, p);
4233 /* Keep this in sync with mono_arch_get_argument_info */
4235 if (enable_arguments) {
4236 /* Allocate a new area on the stack and save arguments there */
4237 sig = mono_method_signature (cfg->method);
4239 cinfo = get_call_info (sig, FALSE);
4241 n = sig->param_count + sig->hasthis;
4243 stack_area = ALIGN_TO (n * 8, 16);
4246 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4248 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4250 /* FIXME: Allocate out registers */
4252 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4254 /* Required by the ABI */
4255 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4257 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4258 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4260 /* Save arguments to the stack */
4261 for (i = 0; i < n; ++i) {
4262 ins = cfg->args [i];
4264 if (ins->opcode == OP_REGVAR) {
4265 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4266 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4267 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4270 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4271 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4272 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4273 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4274 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4275 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4280 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4283 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4285 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4286 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4288 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4290 if (enable_arguments && stack_area) {
4291 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4293 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4295 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4300 ia64_codegen_close (code);
4306 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4308 Ia64CodegenState code;
4309 CallInfo *cinfo = NULL;
4310 MonoMethod *method = cfg->method;
4311 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4313 ia64_codegen_init (code, p);
4315 cinfo = get_call_info (sig, FALSE);
4317 /* Save return value + pass it to func */
4318 switch (cinfo->ret.storage) {
4322 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4323 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4326 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4327 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4328 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4329 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4331 case ArgValuetypeAddrInIReg:
4332 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4343 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4344 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4345 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4347 /* Restore return value */
4348 switch (cinfo->ret.storage) {
4352 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4355 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4356 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4358 case ArgValuetypeAddrInIReg:
4366 ia64_codegen_close (code);
4372 mono_arch_save_unwind_info (MonoCompile *cfg)
4376 /* FIXME: Unregister this for dynamic methods */
4378 di = g_malloc0 (sizeof (unw_dyn_info_t));
4379 di->start_ip = (unw_word_t) cfg->native_code;
4380 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4382 di->format = UNW_INFO_FORMAT_DYNAMIC;
4383 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4384 di->u.pi.regions = cfg->arch.r_pro;
4386 _U_dyn_register (di);
4390 unw_dyn_region_info_t *region = di->u.pi.regions;
4392 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4394 printf (" [Region: %d]\n", region->insn_count);
4395 region = region->next;
4402 mono_arch_flush_icache (guint8 *code, gint size)
4404 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4405 guint8* end = (guint8*)((guint64)code + size);
4407 #ifdef __INTEL_COMPILER
4408 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4415 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4416 /* FIXME: This could be increased to 128 on some cpus */
4423 mono_arch_flush_register_windows (void)
4425 /* Not needed because of libunwind */
4429 mono_arch_is_inst_imm (gint64 imm)
4431 /* The lowering pass will take care of it */
4437 * Determine whenever the trap whose info is in SIGINFO is caused by
4441 mono_arch_is_int_overflow (void *sigctx, void *info)
4443 /* Division is emulated with explicit overflow checks */
4448 mono_arch_get_patch_offset (guint8 *code)
4456 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4458 guint8 *bundle2 = code - 48;
4459 guint8 *bundle3 = code - 32;
4460 guint8 *bundle4 = code - 16;
4461 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4462 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4463 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4464 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4465 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4466 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4467 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4468 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4469 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4473 * Virtual calls are made with:
4475 * [MII] ld8 r31=[r8]
4479 * mov.sptk b6=r31,0x2000000000f32a80
4486 * br.call.sptk.few b0=b6;;
4489 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4490 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4491 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4492 (ins31 == IA64_NOP_M) &&
4493 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4494 (ins33 == IA64_NOP_I) &&
4495 (ins41 == IA64_NOP_M) &&
4496 (ins42 == IA64_NOP_I) &&
4497 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4498 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4499 g_assert (ins21 == IA64_NOP_M);
4500 g_assert (ins23 == IA64_NOP_I);
4501 g_assert (ia64_ins_opcode (ins22) == 0);
4502 g_assert (ia64_ins_x3 (ins22) == 7);
4503 g_assert (ia64_ins_x (ins22) == 0);
4504 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4509 * Must be a scratch register, since only those are saved by the trampoline
4511 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4513 g_assert (regs [reg]);
4522 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4529 static gboolean tls_offset_inited = FALSE;
4532 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4534 if (!tls_offset_inited) {
4535 tls_offset_inited = TRUE;
4537 appdomain_tls_offset = mono_domain_get_tls_offset ();
4538 thread_tls_offset = mono_thread_get_tls_offset ();
4543 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4548 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4550 MonoCallInst *call = (MonoCallInst*)inst;
4551 int out_reg = cfg->arch.reg_out0;
4554 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4557 if (cinfo->ret.storage == ArgAggregate) {
4558 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4561 * The valuetype is in registers after the call, need to be copied
4562 * to the stack. Save the address to a local here, so the call
4563 * instruction can access it.
4565 g_assert (local->opcode == OP_REGOFFSET);
4566 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4569 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4570 vtarg->sreg1 = vt_reg;
4571 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4572 mono_bblock_add_inst (cfg->cbb, vtarg);
4574 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4582 /* add the this argument */
4583 if (this_reg != -1) {
4585 MONO_INST_NEW (cfg, this, OP_MOVE);
4586 this->type = this_type;
4587 this->sreg1 = this_reg;
4588 this->dreg = mono_regstate_next_int (cfg->rs);
4589 mono_bblock_add_inst (cfg->cbb, this);
4591 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4596 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4598 MonoInst *ins = NULL;
4600 if (cmethod->klass == mono_defaults.thread_class &&
4601 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4602 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4603 } else if(cmethod->klass->image == mono_defaults.corlib &&
4604 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4605 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4607 if (strcmp (cmethod->name, "Increment") == 0) {
4610 if (fsig->params [0]->type == MONO_TYPE_I4)
4611 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4612 else if (fsig->params [0]->type == MONO_TYPE_I8)
4613 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4615 g_assert_not_reached ();
4616 MONO_INST_NEW (cfg, ins, opcode);
4618 ins->inst_i0 = args [0];
4619 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4622 if (fsig->params [0]->type == MONO_TYPE_I4)
4623 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4624 else if (fsig->params [0]->type == MONO_TYPE_I8)
4625 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4627 g_assert_not_reached ();
4628 MONO_INST_NEW (cfg, ins, opcode);
4630 ins->inst_i0 = args [0];
4631 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4634 if (fsig->params [0]->type == MONO_TYPE_I4)
4635 opcode = OP_ATOMIC_EXCHANGE_I4;
4636 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4637 (fsig->params [0]->type == MONO_TYPE_I) ||
4638 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4639 opcode = OP_ATOMIC_EXCHANGE_I8;
4643 MONO_INST_NEW (cfg, ins, opcode);
4645 ins->inst_i0 = args [0];
4646 ins->inst_i1 = args [1];
4647 } else if (strcmp (cmethod->name, "Add") == 0) {
4650 if (fsig->params [0]->type == MONO_TYPE_I4)
4651 opcode = OP_ATOMIC_ADD_NEW_I4;
4652 else if (fsig->params [0]->type == MONO_TYPE_I8)
4653 opcode = OP_ATOMIC_ADD_NEW_I8;
4655 g_assert_not_reached ();
4657 MONO_INST_NEW (cfg, ins, opcode);
4659 ins->inst_i0 = args [0];
4660 ins->inst_i1 = args [1];
4661 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4662 /* 64 bit reads are already atomic */
4663 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4664 ins->inst_i0 = args [0];
4672 mono_arch_print_tree (MonoInst *tree, int arity)
4677 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4681 if (appdomain_tls_offset == -1)
4684 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4685 ins->inst_offset = appdomain_tls_offset;
4689 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4693 if (thread_tls_offset == -1)
4696 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4697 ins->inst_offset = thread_tls_offset;