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 const char * const ia64_desc [OP_LAST];
34 static const char*const * ins_spec = ia64_desc;
36 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
38 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
41 * IA64 register usage:
42 * - local registers are used for global register allocation
43 * - r8..r11, r14..r30 is used for local register allocation
44 * - r31 is a scratch register used within opcode implementations
45 * - FIXME: Use out registers as well
46 * - the first three locals are used for saving ar.pfst, b0, and sp
47 * - compare instructions allways set p6 and p7
51 * There are a lot of places where generated code is disassembled/patched.
52 * The automatic bundling of instructions done by the code generation macros
53 * could complicate things, so it is best to call
54 * ia64_codegen_set_one_ins_per_bundle () at those places.
57 #define ARGS_OFFSET 16
59 #define GP_SCRATCH_REG 31
60 #define GP_SCRATCH_REG2 30
61 #define FP_SCRATCH_REG 32
62 #define FP_SCRATCH_REG2 33
64 #define LOOP_ALIGNMENT 8
65 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
67 #define NOT_IMPLEMENTED g_assert_not_reached ()
69 static const char* gregs [] = {
70 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
71 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
72 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
73 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
74 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
75 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
76 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
77 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
78 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
79 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
80 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
81 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
82 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
86 mono_arch_regname (int reg)
94 static const char* fregs [] = {
95 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
96 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
97 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
98 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
99 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
100 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
101 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
102 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
103 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
104 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
105 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
106 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
107 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
111 mono_arch_fregname (int reg)
119 G_GNUC_UNUSED static void
124 G_GNUC_UNUSED static gboolean
127 static int count = 0;
130 if (count == atoi (getenv ("COUNT"))) {
134 if (count > atoi (getenv ("COUNT"))) {
142 debug_ins_sched (void)
145 return debug_count ();
155 return debug_count ();
162 ia64_patch (unsigned char* code, gpointer target);
168 ArgValuetypeAddrInIReg,
186 /* Only if storage == ArgAggregate */
196 gboolean need_stack_align;
202 #define DEBUG(a) if (cfg->verbose_level > 1) a
204 #define NEW_ICONST(cfg,dest,val) do { \
205 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
206 (dest)->opcode = OP_ICONST; \
207 (dest)->inst_c0 = (val); \
208 (dest)->type = STACK_I4; \
214 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
216 ainfo->offset = *stack_size;
218 if (*gr >= PARAM_REGS) {
219 ainfo->storage = ArgOnStack;
220 (*stack_size) += sizeof (gpointer);
223 ainfo->storage = ArgInIReg;
229 #define FLOAT_PARAM_REGS 8
232 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
234 ainfo->offset = *stack_size;
236 if (*gr >= PARAM_REGS) {
237 ainfo->storage = ArgOnStack;
238 (*stack_size) += sizeof (gpointer);
241 ainfo->storage = ArgInFloatReg;
242 ainfo->reg = 8 + *fr;
249 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
251 guint32 *gr, guint32 *fr, guint32 *stack_size)
255 MonoMarshalType *info;
256 gboolean is_hfa = TRUE;
257 guint32 hfa_type = 0;
259 klass = mono_class_from_mono_type (type);
260 if (type->type == MONO_TYPE_TYPEDBYREF)
261 size = 3 * sizeof (gpointer);
262 else if (sig->pinvoke)
263 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
265 size = mono_type_stack_size (&klass->byval_arg, NULL);
267 if (!sig->pinvoke || (size == 0)) {
268 /* Allways pass in memory */
269 ainfo->offset = *stack_size;
270 *stack_size += ALIGN_TO (size, 8);
271 ainfo->storage = ArgOnStack;
276 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
277 info = mono_marshal_load_type_info (klass);
279 for (i = 0; i < info->num_fields; ++i) {
280 guint32 ftype = info->fields [i].field->type->type;
281 if (!(info->fields [i].field->type->byref) &&
282 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
285 else if (hfa_type != ftype)
294 ainfo->storage = ArgAggregate;
295 ainfo->atype = AggregateNormal;
298 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
300 if (info->num_fields <= 8) {
302 ainfo->nregs = info->num_fields;
303 ainfo->nslots = ainfo->nregs;
309 if ((*fr) + info->num_fields > 8)
312 ainfo->reg = 8 + (*fr);
313 ainfo->nregs = info->num_fields;
314 ainfo->nslots = ainfo->nregs;
315 (*fr) += info->num_fields;
320 /* This also handles returning of TypedByRef used by some icalls */
323 ainfo->reg = IA64_R8;
324 ainfo->nregs = (size + 7) / 8;
325 ainfo->nslots = ainfo->nregs;
332 ainfo->offset = *stack_size;
333 ainfo->nslots = (size + 7) / 8;
335 if (((*gr) + ainfo->nslots) <= 8) {
336 /* Fits entirely in registers */
337 ainfo->nregs = ainfo->nslots;
338 (*gr) += ainfo->nregs;
342 ainfo->nregs = 8 - (*gr);
344 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
350 * Obtain information about a call according to the calling convention.
351 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
352 * Gude" document for more information.
355 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
359 int n = sig->hasthis + sig->param_count;
360 guint32 stack_size = 0;
363 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
370 ret_type = mono_type_get_underlying_type (sig->ret);
371 switch (ret_type->type) {
372 case MONO_TYPE_BOOLEAN:
383 case MONO_TYPE_FNPTR:
384 case MONO_TYPE_CLASS:
385 case MONO_TYPE_OBJECT:
386 case MONO_TYPE_SZARRAY:
387 case MONO_TYPE_ARRAY:
388 case MONO_TYPE_STRING:
389 cinfo->ret.storage = ArgInIReg;
390 cinfo->ret.reg = IA64_R8;
394 cinfo->ret.storage = ArgInIReg;
395 cinfo->ret.reg = IA64_R8;
399 cinfo->ret.storage = ArgInFloatReg;
402 case MONO_TYPE_GENERICINST:
403 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
404 cinfo->ret.storage = ArgInIReg;
405 cinfo->ret.reg = IA64_R8;
409 case MONO_TYPE_VALUETYPE:
410 case MONO_TYPE_TYPEDBYREF: {
411 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
413 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
414 if (cinfo->ret.storage == ArgOnStack)
415 /* The caller passes the address where the value is stored */
416 add_general (&gr, &stack_size, &cinfo->ret);
417 if (cinfo->ret.storage == ArgInIReg)
418 cinfo->ret.storage = ArgValuetypeAddrInIReg;
422 cinfo->ret.storage = ArgNone;
425 g_error ("Can't handle as return value 0x%x", sig->ret->type);
431 add_general (&gr, &stack_size, cinfo->args + 0);
433 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
435 fr = FLOAT_PARAM_REGS;
437 /* Emit the signature cookie just before the implicit arguments */
438 add_general (&gr, &stack_size, &cinfo->sig_cookie);
441 for (i = 0; i < sig->param_count; ++i) {
442 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
445 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
446 /* We allways pass the sig cookie on the stack for simplicity */
448 * Prevent implicit arguments + the sig cookie from being passed
452 fr = FLOAT_PARAM_REGS;
454 /* Emit the signature cookie just before the implicit arguments */
455 add_general (&gr, &stack_size, &cinfo->sig_cookie);
458 if (sig->params [i]->byref) {
459 add_general (&gr, &stack_size, ainfo);
462 ptype = mono_type_get_underlying_type (sig->params [i]);
463 switch (ptype->type) {
464 case MONO_TYPE_BOOLEAN:
467 add_general (&gr, &stack_size, ainfo);
472 add_general (&gr, &stack_size, ainfo);
476 add_general (&gr, &stack_size, ainfo);
481 case MONO_TYPE_FNPTR:
482 case MONO_TYPE_CLASS:
483 case MONO_TYPE_OBJECT:
484 case MONO_TYPE_STRING:
485 case MONO_TYPE_SZARRAY:
486 case MONO_TYPE_ARRAY:
487 add_general (&gr, &stack_size, ainfo);
489 case MONO_TYPE_GENERICINST:
490 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
491 add_general (&gr, &stack_size, ainfo);
495 case MONO_TYPE_VALUETYPE:
496 case MONO_TYPE_TYPEDBYREF:
498 /* We allways pass valuetypes on the stack */
499 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
503 add_general (&gr, &stack_size, ainfo);
506 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
509 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
512 g_assert_not_reached ();
516 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
518 fr = FLOAT_PARAM_REGS;
520 /* Emit the signature cookie just before the implicit arguments */
521 add_general (&gr, &stack_size, &cinfo->sig_cookie);
524 cinfo->stack_usage = stack_size;
525 cinfo->reg_usage = gr;
526 cinfo->freg_usage = fr;
531 * mono_arch_get_argument_info:
532 * @csig: a method signature
533 * @param_count: the number of parameters to consider
534 * @arg_info: an array to store the result infos
536 * Gathers information on parameters such as size, alignment and
537 * padding. arg_info should be large enought to hold param_count + 1 entries.
539 * Returns the size of the argument area on the stack.
542 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
545 CallInfo *cinfo = get_call_info (csig, FALSE);
546 guint32 args_size = cinfo->stack_usage;
548 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
550 arg_info [0].offset = 0;
553 for (k = 0; k < param_count; k++) {
554 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
556 arg_info [k + 1].size = 0;
565 * Initialize the cpu to execute managed code.
568 mono_arch_cpu_init (void)
573 * This function returns the optimizations supported on this cpu.
576 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
584 mono_arch_break (void)
589 is_regsize_var (MonoType *t) {
592 t = mono_type_get_underlying_type (t);
603 case MONO_TYPE_FNPTR:
604 case MONO_TYPE_BOOLEAN:
606 case MONO_TYPE_OBJECT:
607 case MONO_TYPE_STRING:
608 case MONO_TYPE_CLASS:
609 case MONO_TYPE_SZARRAY:
610 case MONO_TYPE_ARRAY:
612 case MONO_TYPE_GENERICINST:
613 if (!mono_type_generic_inst_is_valuetype (t))
616 case MONO_TYPE_VALUETYPE:
623 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
627 MonoMethodSignature *sig;
628 MonoMethodHeader *header;
631 header = mono_method_get_header (cfg->method);
633 sig = mono_method_signature (cfg->method);
635 cinfo = get_call_info (sig, FALSE);
637 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
638 MonoInst *ins = cfg->varinfo [i];
640 ArgInfo *ainfo = &cinfo->args [i];
642 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
645 if (ainfo->storage == ArgInIReg) {
646 /* The input registers are non-volatile */
647 ins->opcode = OP_REGVAR;
648 ins->dreg = 32 + ainfo->reg;
652 for (i = 0; i < cfg->num_varinfo; i++) {
653 MonoInst *ins = cfg->varinfo [i];
654 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
657 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
660 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
661 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
664 if (is_regsize_var (ins->inst_vtype)) {
665 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
666 g_assert (i == vmv->idx);
667 vars = g_list_prepend (vars, vmv);
671 vars = mono_varlist_sort (cfg, vars, 0);
677 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
680 guint32 reserved_regs;
681 MonoMethodHeader *header;
683 if (cfg->arch.reg_local0 > 0)
687 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
689 header = mono_method_get_header (cfg->method);
691 /* Some registers are reserved for use by the prolog/epilog */
692 reserved_regs = header->num_clauses ? 4 : 3;
694 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
695 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
696 /* One registers is needed by instrument_epilog to save the return value */
698 if (cinfo->reg_usage < 2)
699 /* Number of arguments passed to function call in instrument_prolog */
700 cinfo->reg_usage = 2;
703 cfg->arch.reg_in0 = 32;
704 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
705 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
707 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
708 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
709 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
712 * Frames without handlers save sp to fp, frames with handlers save it into
713 * a dedicated register.
715 if (header->num_clauses)
716 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
718 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
720 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
721 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
722 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
726 * Need to allocate at least 2 out register for use by CEE_THROW / the system
727 * exception throwing code.
729 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
735 mono_arch_get_global_int_regs (MonoCompile *cfg)
740 mono_ia64_alloc_stacked_registers (cfg);
742 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
745 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
752 * mono_arch_regalloc_cost:
754 * Return the cost, in number of memory references, of the action of
755 * allocating the variable VMV into a register during global register
759 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
761 /* FIXME: Increase costs linearly to avoid using all local registers */
767 mono_arch_allocate_vars (MonoCompile *cfg)
769 MonoMethodSignature *sig;
770 MonoMethodHeader *header;
773 guint32 locals_stack_size, locals_stack_align;
777 header = mono_method_get_header (cfg->method);
779 sig = mono_method_signature (cfg->method);
781 cinfo = get_call_info (sig, FALSE);
784 * Determine whenever the frame pointer can be eliminated.
785 * FIXME: Remove some of the restrictions.
787 cfg->arch.omit_fp = TRUE;
789 if (!debug_omit_fp ())
790 cfg->arch.omit_fp = FALSE;
792 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
793 cfg->arch.omit_fp = FALSE;
794 if (header->num_clauses)
795 cfg->arch.omit_fp = FALSE;
797 cfg->arch.omit_fp = FALSE;
798 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
799 ArgInfo *ainfo = &cinfo->args [i];
801 if (ainfo->storage == ArgOnStack) {
803 * The stack offset can only be determined when the frame
806 cfg->arch.omit_fp = FALSE;
810 mono_ia64_alloc_stacked_registers (cfg);
813 * We use the ABI calling conventions for managed code as well.
814 * Exception: valuetypes are never passed or returned in registers.
817 if (cfg->arch.omit_fp) {
818 cfg->frame_reg = IA64_SP;
819 offset = ARGS_OFFSET;
822 /* Locals are allocated backwards from %fp */
823 cfg->frame_reg = cfg->arch.reg_fp;
827 if (cfg->method->save_lmf) {
831 if (sig->ret->type != MONO_TYPE_VOID) {
832 switch (cinfo->ret.storage) {
834 cfg->ret->opcode = OP_REGVAR;
835 cfg->ret->inst_c0 = cinfo->ret.reg;
838 cfg->ret->opcode = OP_REGVAR;
839 cfg->ret->inst_c0 = cinfo->ret.reg;
841 case ArgValuetypeAddrInIReg:
842 cfg->ret->opcode = OP_REGVAR;
843 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
846 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
847 if (cfg->arch.omit_fp)
848 g_assert_not_reached ();
849 offset = ALIGN_TO (offset, 8);
850 offset += cinfo->ret.nslots * 8;
851 cfg->ret->opcode = OP_REGOFFSET;
852 cfg->ret->inst_basereg = cfg->frame_reg;
853 cfg->ret->inst_offset = - offset;
856 g_assert_not_reached ();
858 cfg->ret->dreg = cfg->ret->inst_c0;
861 /* Allocate locals */
862 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
863 if (locals_stack_align) {
864 offset = ALIGN_TO (offset, locals_stack_align);
866 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
867 if (offsets [i] != -1) {
868 MonoInst *inst = cfg->varinfo [i];
869 inst->opcode = OP_REGOFFSET;
870 inst->inst_basereg = cfg->frame_reg;
871 if (cfg->arch.omit_fp)
872 inst->inst_offset = (offset + offsets [i]);
874 inst->inst_offset = - (offset + offsets [i]);
875 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
879 offset += locals_stack_size;
881 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
882 if (cfg->arch.omit_fp)
883 g_assert_not_reached ();
884 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
885 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
888 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
889 inst = cfg->varinfo [i];
890 if (inst->opcode != OP_REGVAR) {
891 ArgInfo *ainfo = &cinfo->args [i];
892 gboolean inreg = TRUE;
895 if (sig->hasthis && (i == 0))
896 arg_type = &mono_defaults.object_class->byval_arg;
898 arg_type = sig->params [i - sig->hasthis];
900 /* FIXME: VOLATILE is only set if the liveness pass runs */
901 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
904 inst->opcode = OP_REGOFFSET;
906 switch (ainfo->storage) {
908 inst->opcode = OP_REGVAR;
909 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
913 * Since float regs are volatile, we save the arguments to
914 * the stack in the prolog.
919 if (cfg->arch.omit_fp)
920 g_assert_not_reached ();
921 inst->opcode = OP_REGOFFSET;
922 inst->inst_basereg = cfg->frame_reg;
923 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
932 if (!inreg && (ainfo->storage != ArgOnStack)) {
933 inst->opcode = OP_REGOFFSET;
934 inst->inst_basereg = cfg->frame_reg;
935 /* These arguments are saved to the stack in the prolog */
936 switch (ainfo->storage) {
938 if (ainfo->atype == AggregateSingleHFA)
939 offset += ainfo->nslots * 4;
941 offset += ainfo->nslots * 8;
944 offset += sizeof (gpointer);
947 offset = ALIGN_TO (offset, sizeof (gpointer));
948 if (cfg->arch.omit_fp)
949 inst->inst_offset = offset;
951 inst->inst_offset = - offset;
956 if (cfg->arch.omit_fp && offset == 16)
959 cfg->stack_offset = offset;
965 mono_arch_create_vars (MonoCompile *cfg)
967 MonoMethodSignature *sig;
970 sig = mono_method_signature (cfg->method);
972 cinfo = get_call_info (sig, FALSE);
974 if (cinfo->ret.storage == ArgAggregate)
975 cfg->ret_var_is_local = TRUE;
981 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
985 arg->opcode = OP_OUTARG_REG;
986 arg->inst_left = tree;
987 arg->inst_right = (MonoInst*)call;
988 arg->backend.reg3 = reg;
989 call->used_iregs |= 1 << reg;
992 arg->opcode = OP_OUTARG_FREG;
993 arg->inst_left = tree;
994 arg->inst_right = (MonoInst*)call;
995 arg->backend.reg3 = reg;
996 call->used_fregs |= 1 << reg;
999 g_assert_not_reached ();
1004 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1007 MonoMethodSignature *tmp_sig;
1010 /* FIXME: Add support for signature tokens to AOT */
1011 cfg->disable_aot = TRUE;
1013 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1016 * mono_ArgIterator_Setup assumes the signature cookie is
1017 * passed first and all the arguments which were before it are
1018 * passed on the stack after the signature. So compensate by
1019 * passing a different signature.
1021 tmp_sig = mono_metadata_signature_dup (call->signature);
1022 tmp_sig->param_count -= call->signature->sentinelpos;
1023 tmp_sig->sentinelpos = 0;
1024 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1026 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1027 sig_arg->inst_p0 = tmp_sig;
1029 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1030 arg->inst_left = sig_arg;
1031 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1032 arg->type = STACK_PTR;
1034 /* prepend, so they get reversed */
1035 arg->next = call->out_args;
1036 call->out_args = arg;
1040 * take the arguments and generate the arch-specific
1041 * instructions to properly call the function in call.
1042 * This includes pushing, moving arguments to the right register
1046 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1049 MonoMethodSignature *sig;
1050 int i, n, stack_size;
1056 mono_ia64_alloc_stacked_registers (cfg);
1058 sig = call->signature;
1059 n = sig->param_count + sig->hasthis;
1061 cinfo = get_call_info (sig, sig->pinvoke);
1063 if (cinfo->ret.storage == ArgAggregate) {
1064 /* The code in emit_this_vret_arg needs a local */
1065 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1066 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1069 for (i = 0; i < n; ++i) {
1070 ainfo = cinfo->args + i;
1072 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1073 /* Emit the signature cookie just before the implicit arguments */
1074 emit_sig_cookie (cfg, call, cinfo);
1077 if (is_virtual && i == 0) {
1078 /* the argument will be attached to the call instruction */
1079 in = call->args [i];
1083 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1084 in = call->args [i];
1085 arg->cil_code = in->cil_code;
1086 arg->inst_left = in;
1087 arg->type = in->type;
1088 /* prepend, so they get reversed */
1089 arg->next = call->out_args;
1090 call->out_args = arg;
1092 if (sig->hasthis && (i == 0))
1093 arg_type = &mono_defaults.object_class->byval_arg;
1095 arg_type = sig->params [i - sig->hasthis];
1097 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1098 MonoInst *stack_addr;
1102 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1103 size = sizeof (MonoTypedRef);
1104 align = sizeof (gpointer);
1108 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1111 * Other backends use mono_type_stack_size (), but that
1112 * aligns the size to 8, which is larger than the size of
1113 * the source, leading to reads of invalid memory if the
1114 * source is at the end of address space.
1116 size = mono_class_value_size (in->klass, &align);
1119 if (ainfo->storage == ArgAggregate) {
1120 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1123 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1126 * Part of the structure is passed in registers.
1128 for (j = 0; j < ainfo->nregs; ++j) {
1129 int offset, load_op, dest_reg, arg_storage;
1131 slot = ainfo->reg + j;
1133 if (ainfo->atype == AggregateSingleHFA) {
1134 load_op = CEE_LDIND_R4;
1136 dest_reg = ainfo->reg + j;
1137 arg_storage = ArgInFloatReg;
1138 } else if (ainfo->atype == AggregateDoubleHFA) {
1139 load_op = CEE_LDIND_R8;
1141 dest_reg = ainfo->reg + j;
1142 arg_storage = ArgInFloatReg;
1144 load_op = CEE_LDIND_I;
1146 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1147 arg_storage = ArgInIReg;
1150 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1151 load->ssa_op = MONO_SSA_LOAD;
1152 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1154 NEW_ICONST (cfg, offset_ins, offset);
1155 MONO_INST_NEW (cfg, load2, CEE_ADD);
1156 load2->inst_left = load;
1157 load2->inst_right = offset_ins;
1159 MONO_INST_NEW (cfg, load, load_op);
1160 load->inst_left = load2;
1165 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1166 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1167 if (set_reg != call->out_args) {
1168 set_reg->next = call->out_args;
1169 call->out_args = set_reg;
1174 * Part of the structure is passed on the stack.
1176 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1179 slot = ainfo->reg + j;
1181 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1182 load->ssa_op = MONO_SSA_LOAD;
1183 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1185 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1186 MONO_INST_NEW (cfg, load2, CEE_ADD);
1187 load2->inst_left = load;
1188 load2->inst_right = offset_ins;
1190 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1191 load->inst_left = load2;
1196 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1197 outarg->inst_left = load;
1198 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1200 if (outarg != call->out_args) {
1201 outarg->next = call->out_args;
1202 call->out_args = outarg;
1206 /* Trees can't be shared so make a copy */
1207 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1208 arg->cil_code = in->cil_code;
1209 arg->ssa_op = MONO_SSA_STORE;
1210 arg->inst_left = vtaddr;
1211 arg->inst_right = in;
1212 arg->type = in->type;
1214 /* prepend, so they get reversed */
1215 arg->next = call->out_args;
1216 call->out_args = arg;
1219 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1220 stack_addr->inst_basereg = IA64_SP;
1221 stack_addr->inst_offset = 16 + ainfo->offset;
1222 stack_addr->inst_imm = size;
1224 arg->opcode = OP_OUTARG_VT;
1225 arg->inst_right = stack_addr;
1229 switch (ainfo->storage) {
1231 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1234 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1237 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1238 arg->opcode = OP_OUTARG_R4;
1241 arg->opcode = OP_OUTARG;
1242 arg->inst_imm = 16 + ainfo->offset;
1245 g_assert_not_reached ();
1251 /* Handle the case where there are no implicit arguments */
1252 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1253 emit_sig_cookie (cfg, call, cinfo);
1256 call->stack_usage = cinfo->stack_usage;
1257 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1258 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1259 cfg->flags |= MONO_CFG_HAS_CALLS;
1267 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1269 MonoInst *ins, *last_ins = NULL;
1273 switch (ins->opcode) {
1282 if (ins->dreg == ins->sreg1) {
1284 last_ins->next = ins->next;
1291 * OP_MOVE sreg, dreg
1292 * OP_MOVE dreg, sreg
1294 if (last_ins && last_ins->opcode == OP_MOVE &&
1295 ins->sreg1 == last_ins->dreg &&
1296 ins->dreg == last_ins->sreg1) {
1297 last_ins->next = ins->next;
1304 /* remove unnecessary multiplication with 1 */
1305 if (ins->inst_imm == 1) {
1306 if (ins->dreg != ins->sreg1) {
1307 ins->opcode = OP_MOVE;
1309 last_ins->next = ins->next;
1320 bb->last_ins = last_ins;
1343 opcode_to_cond (int opcode)
1352 case OP_COND_EXC_EQ:
1355 case OP_COND_EXC_NE_UN:
1368 case OP_COND_EXC_LT:
1376 case OP_COND_EXC_GT:
1385 case OP_COND_EXC_LE_UN:
1399 case OP_COND_EXC_LT_UN:
1402 case OP_COND_EXC_GT_UN:
1410 printf ("%s\n", mono_inst_name (opcode));
1416 opcode_to_type (int opcode, int cmp_opcode)
1418 if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1420 else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1422 else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLE_UN))
1424 else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1426 else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLE_UN))
1428 else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1430 else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
1431 switch (cmp_opcode) {
1433 case OP_ICOMPARE_IMM:
1439 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1444 int cond_to_ia64_cmp [][3] = {
1445 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1446 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1447 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1448 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1449 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1450 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1451 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1452 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1453 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1454 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1458 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1460 return cond_to_ia64_cmp [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1463 int cond_to_ia64_cmp_imm [][3] = {
1464 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1465 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1466 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1467 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1468 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1469 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1470 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1471 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1472 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1473 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1477 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1479 /* The condition needs to be reversed */
1480 return cond_to_ia64_cmp_imm [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1484 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1488 bb->code = to_insert;
1489 to_insert->next = ins;
1492 to_insert->next = ins->next;
1493 ins->next = to_insert;
1497 #define NEW_INS(cfg,dest,op) do { \
1498 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1499 (dest)->opcode = (op); \
1500 insert_after_ins (bb, last_ins, (dest)); \
1501 last_ins = (dest); \
1505 * mono_arch_lowering_pass:
1507 * Converts complex opcodes into simpler ones so that each IR instruction
1508 * corresponds to one machine instruction.
1511 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1513 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1516 if (bb->max_ireg > cfg->rs->next_vireg)
1517 cfg->rs->next_vireg = bb->max_ireg;
1518 if (bb->max_freg > cfg->rs->next_vfreg)
1519 cfg->rs->next_vfreg = bb->max_freg;
1522 switch (ins->opcode) {
1523 case OP_STOREI1_MEMBASE_IMM:
1524 case OP_STOREI2_MEMBASE_IMM:
1525 case OP_STOREI4_MEMBASE_IMM:
1526 case OP_STOREI8_MEMBASE_IMM:
1527 case OP_STORE_MEMBASE_IMM:
1528 /* There are no store_membase instructions on ia64 */
1529 if (ins->inst_offset == 0) {
1531 } else if (ia64_is_imm14 (ins->inst_offset)) {
1532 NEW_INS (cfg, temp2, OP_ADD_IMM);
1533 temp2->sreg1 = ins->inst_destbasereg;
1534 temp2->inst_imm = ins->inst_offset;
1535 temp2->dreg = mono_regstate_next_int (cfg->rs);
1538 NEW_INS (cfg, temp, OP_I8CONST);
1539 temp->inst_c0 = ins->inst_offset;
1540 temp->dreg = mono_regstate_next_int (cfg->rs);
1541 NEW_INS (cfg, temp2, CEE_ADD);
1542 temp2->sreg1 = ins->inst_destbasereg;
1543 temp2->sreg2 = temp->dreg;
1544 temp2->dreg = mono_regstate_next_int (cfg->rs);
1547 switch (ins->opcode) {
1548 case OP_STOREI1_MEMBASE_IMM:
1549 ins->opcode = OP_STOREI1_MEMBASE_REG;
1551 case OP_STOREI2_MEMBASE_IMM:
1552 ins->opcode = OP_STOREI2_MEMBASE_REG;
1554 case OP_STOREI4_MEMBASE_IMM:
1555 ins->opcode = OP_STOREI4_MEMBASE_REG;
1557 case OP_STOREI8_MEMBASE_IMM:
1558 case OP_STORE_MEMBASE_IMM:
1559 ins->opcode = OP_STOREI8_MEMBASE_REG;
1562 g_assert_not_reached ();
1565 if (ins->inst_imm == 0)
1566 ins->sreg1 = IA64_R0;
1568 NEW_INS (cfg, temp3, OP_I8CONST);
1569 temp3->inst_c0 = ins->inst_imm;
1570 temp3->dreg = mono_regstate_next_int (cfg->rs);
1571 ins->sreg1 = temp3->dreg;
1574 ins->inst_offset = 0;
1576 ins->inst_destbasereg = temp2->dreg;
1578 case OP_STOREI1_MEMBASE_REG:
1579 case OP_STOREI2_MEMBASE_REG:
1580 case OP_STOREI4_MEMBASE_REG:
1581 case OP_STOREI8_MEMBASE_REG:
1582 case OP_STORER4_MEMBASE_REG:
1583 case OP_STORER8_MEMBASE_REG:
1584 case OP_STORE_MEMBASE_REG:
1585 /* There are no store_membase instructions on ia64 */
1586 if (ins->inst_offset == 0) {
1589 else if (ia64_is_imm14 (ins->inst_offset)) {
1590 NEW_INS (cfg, temp2, OP_ADD_IMM);
1591 temp2->sreg1 = ins->inst_destbasereg;
1592 temp2->inst_imm = ins->inst_offset;
1593 temp2->dreg = mono_regstate_next_int (cfg->rs);
1596 NEW_INS (cfg, temp, OP_I8CONST);
1597 temp->inst_c0 = ins->inst_offset;
1598 temp->dreg = mono_regstate_next_int (cfg->rs);
1599 NEW_INS (cfg, temp2, CEE_ADD);
1600 temp2->sreg1 = ins->inst_destbasereg;
1601 temp2->sreg2 = temp->dreg;
1602 temp2->dreg = mono_regstate_next_int (cfg->rs);
1605 ins->inst_offset = 0;
1606 ins->inst_destbasereg = temp2->dreg;
1608 case OP_LOADI1_MEMBASE:
1609 case OP_LOADU1_MEMBASE:
1610 case OP_LOADI2_MEMBASE:
1611 case OP_LOADU2_MEMBASE:
1612 case OP_LOADI4_MEMBASE:
1613 case OP_LOADU4_MEMBASE:
1614 case OP_LOADI8_MEMBASE:
1615 case OP_LOAD_MEMBASE:
1616 case OP_LOADR4_MEMBASE:
1617 case OP_LOADR8_MEMBASE:
1618 case OP_ATOMIC_EXCHANGE_I4:
1619 case OP_ATOMIC_EXCHANGE_I8:
1620 case OP_ATOMIC_ADD_NEW_I4:
1621 case OP_ATOMIC_ADD_NEW_I8:
1622 case OP_ATOMIC_ADD_IMM_NEW_I4:
1623 case OP_ATOMIC_ADD_IMM_NEW_I8:
1624 /* There are no membase instructions on ia64 */
1625 if (ins->inst_offset == 0) {
1628 else if (ia64_is_imm14 (ins->inst_offset)) {
1629 NEW_INS (cfg, temp2, OP_ADD_IMM);
1630 temp2->sreg1 = ins->inst_basereg;
1631 temp2->inst_imm = ins->inst_offset;
1632 temp2->dreg = mono_regstate_next_int (cfg->rs);
1635 NEW_INS (cfg, temp, OP_I8CONST);
1636 temp->inst_c0 = ins->inst_offset;
1637 temp->dreg = mono_regstate_next_int (cfg->rs);
1638 NEW_INS (cfg, temp2, CEE_ADD);
1639 temp2->sreg1 = ins->inst_basereg;
1640 temp2->sreg2 = temp->dreg;
1641 temp2->dreg = mono_regstate_next_int (cfg->rs);
1644 ins->inst_offset = 0;
1645 ins->inst_basereg = temp2->dreg;
1659 case OP_ISHR_UN_IMM:
1660 case OP_LSHR_UN_IMM: {
1661 gboolean is_imm = FALSE;
1662 gboolean switched = FALSE;
1664 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1665 ins->opcode = OP_ZEXT_I1;
1669 switch (ins->opcode) {
1672 is_imm = ia64_is_imm14 (ins->inst_imm);
1676 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1678 /* A = B - IMM -> A = B + (-IMM) */
1679 ins->inst_imm = - ins->inst_imm;
1680 ins->opcode = OP_IADD_IMM;
1688 is_imm = ia64_is_imm8 (ins->inst_imm);
1696 case OP_ISHR_UN_IMM:
1697 case OP_LSHR_UN_IMM:
1698 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1706 ins->sreg2 = ins->sreg1;
1710 switch (ins->opcode) {
1712 ins->opcode = CEE_ADD;
1715 ins->opcode = OP_IADD;
1718 ins->opcode = OP_ISUB;
1721 ins->opcode = OP_IAND;
1724 ins->opcode = OP_IOR;
1727 ins->opcode = OP_IXOR;
1730 ins->opcode = OP_ISHL;
1733 ins->opcode = OP_ISHR;
1735 case OP_ISHR_UN_IMM:
1736 ins->opcode = OP_ISHR_UN;
1739 ins->opcode = CEE_AND;
1742 ins->opcode = OP_LSHL;
1745 ins->opcode = OP_LSHL;
1748 ins->opcode = OP_LSHR;
1750 case OP_LSHR_UN_IMM:
1751 ins->opcode = OP_LSHR_UN;
1754 g_assert_not_reached ();
1757 if (ins->inst_imm == 0)
1758 ins->sreg2 = IA64_R0;
1760 NEW_INS (cfg, temp, OP_I8CONST);
1761 temp->inst_c0 = ins->inst_imm;
1762 temp->dreg = mono_regstate_next_int (cfg->rs);
1763 ins->sreg2 = temp->dreg;
1767 case OP_COMPARE_IMM:
1768 case OP_ICOMPARE_IMM: {
1769 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1773 * The compare_imm instructions have switched up arguments, and
1774 * some of them take an imm between -127 and 128.
1777 switch (next->opcode) {
1780 case OP_COND_EXC_LT:
1783 imm = ia64_is_imm8 (ins->inst_imm - 1);
1789 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1792 imm = ia64_is_imm8 (ins->inst_imm);
1797 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1798 ins->sreg2 = ins->sreg1;
1801 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1803 if (ins->inst_imm == 0)
1804 ins->sreg2 = IA64_R0;
1806 NEW_INS (cfg, temp, OP_I8CONST);
1807 temp->inst_c0 = ins->inst_imm;
1808 temp->dreg = mono_regstate_next_int (cfg->rs);
1809 ins->sreg2 = temp->dreg;
1813 switch (next->opcode) {
1834 next->opcode = OP_IA64_BR_COND;
1835 if (! (next->flags & MONO_INST_BRLABEL))
1836 next->inst_target_bb = next->inst_true_bb;
1838 case OP_COND_EXC_EQ:
1839 case OP_COND_EXC_GT:
1840 case OP_COND_EXC_LT:
1841 case OP_COND_EXC_GT_UN:
1842 case OP_COND_EXC_LE_UN:
1843 case OP_COND_EXC_NE_UN:
1844 case OP_COND_EXC_LT_UN:
1845 next->opcode = OP_IA64_COND_EXC;
1857 next->opcode = OP_IA64_CSET;
1860 printf ("%s\n", mono_inst_name (next->opcode));
1870 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1874 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1875 switch (next->opcode) {
1906 next->opcode = OP_IA64_BR_COND;
1907 if (! (next->flags & MONO_INST_BRLABEL))
1908 next->inst_target_bb = next->inst_true_bb;
1910 case OP_COND_EXC_LT:
1911 case OP_COND_EXC_GT:
1912 case OP_COND_EXC_GT_UN:
1913 case OP_COND_EXC_LE_UN:
1914 next->opcode = OP_IA64_COND_EXC;
1931 next->opcode = OP_IA64_CSET;
1934 printf ("%s\n", mono_inst_name (next->opcode));
1943 gboolean found = FALSE;
1944 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1946 /* First the easy cases */
1947 if (ins->inst_imm == 1) {
1948 ins->opcode = OP_MOVE;
1951 for (i = 1; i < 64; ++i)
1952 if (ins->inst_imm == (((gint64)1) << i)) {
1953 ins->opcode = shl_op;
1959 /* This could be optimized */
1962 for (i = 0; i < 64; ++i) {
1963 if (ins->inst_imm & (((gint64)1) << i)) {
1964 NEW_INS (cfg, temp, shl_op);
1965 temp->dreg = mono_regstate_next_int (cfg->rs);
1966 temp->sreg1 = ins->sreg1;
1970 sum_reg = temp->dreg;
1972 NEW_INS (cfg, temp2, CEE_ADD);
1973 temp2->dreg = mono_regstate_next_int (cfg->rs);
1974 temp2->sreg1 = sum_reg;
1975 temp2->sreg2 = temp->dreg;
1976 sum_reg = temp2->dreg;
1980 ins->opcode = OP_MOVE;
1981 ins->sreg1 = sum_reg;
1985 case CEE_CONV_OVF_U4:
1986 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1987 temp->sreg1 = ins->sreg1;
1988 temp->sreg2 = IA64_R0;
1990 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1991 temp->inst_p1 = (char*)"OverflowException";
1993 ins->opcode = OP_MOVE;
1995 case CEE_CONV_OVF_I4_UN:
1996 NEW_INS (cfg, temp, OP_ICONST);
1997 temp->inst_c0 = 0x7fffffff;
1998 temp->dreg = mono_regstate_next_int (cfg->rs);
2000 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
2001 temp2->sreg1 = ins->sreg1;
2002 temp2->sreg2 = temp->dreg;
2004 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
2005 temp->inst_p1 = (char*)"OverflowException";
2007 ins->opcode = OP_MOVE;
2009 case OP_FCONV_TO_I4:
2010 case OP_FCONV_TO_I2:
2011 case OP_FCONV_TO_U2:
2012 case OP_FCONV_TO_I1:
2013 case OP_FCONV_TO_U1:
2014 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
2015 temp->sreg1 = ins->sreg1;
2016 temp->dreg = ins->dreg;
2018 switch (ins->opcode) {
2019 case OP_FCONV_TO_I4:
2020 ins->opcode = OP_SEXT_I4;
2022 case OP_FCONV_TO_I2:
2023 ins->opcode = OP_SEXT_I2;
2025 case OP_FCONV_TO_U2:
2026 ins->opcode = OP_ZEXT_I4;
2028 case OP_FCONV_TO_I1:
2029 ins->opcode = OP_SEXT_I1;
2031 case OP_FCONV_TO_U1:
2032 ins->opcode = OP_ZEXT_I1;
2035 g_assert_not_reached ();
2037 ins->sreg1 = ins->dreg;
2045 bb->last_ins = last_ins;
2047 bb->max_ireg = cfg->rs->next_vireg;
2048 bb->max_freg = cfg->rs->next_vfreg;
2052 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
2057 mono_arch_lowering_pass (cfg, bb);
2059 mono_local_regalloc (cfg, bb);
2063 * emit_load_volatile_arguments:
2065 * Load volatile arguments from the stack to the original input registers.
2066 * Required before a tail call.
2068 static Ia64CodegenState
2069 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
2071 MonoMethod *method = cfg->method;
2072 MonoMethodSignature *sig;
2077 /* FIXME: Generate intermediate code instead */
2079 sig = mono_method_signature (method);
2081 cinfo = get_call_info (sig, FALSE);
2083 /* This is the opposite of the code in emit_prolog */
2084 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2085 ArgInfo *ainfo = cinfo->args + i;
2086 gint32 stack_offset;
2088 ins = cfg->varinfo [i];
2090 if (sig->hasthis && (i == 0))
2091 arg_type = &mono_defaults.object_class->byval_arg;
2093 arg_type = sig->params [i - sig->hasthis];
2095 arg_type = mono_type_get_underlying_type (arg_type);
2097 stack_offset = ainfo->offset + ARGS_OFFSET;
2099 /* Save volatile arguments to the stack */
2100 if (ins->opcode != OP_REGVAR) {
2101 switch (ainfo->storage) {
2104 /* FIXME: big offsets */
2105 g_assert (ins->opcode == OP_REGOFFSET);
2106 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2107 if (arg_type->byref)
2108 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2110 switch (arg_type->type) {
2112 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
2115 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
2118 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2130 if (ins->opcode == OP_REGVAR) {
2131 /* Argument allocated to (non-volatile) register */
2132 switch (ainfo->storage) {
2134 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
2135 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
2138 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
2139 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2152 static Ia64CodegenState
2153 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2158 /* Move return value to the target register */
2159 switch (ins->opcode) {
2161 case OP_VOIDCALL_REG:
2162 case OP_VOIDCALL_MEMBASE:
2166 case OP_CALL_MEMBASE:
2169 case OP_LCALL_MEMBASE:
2170 g_assert (ins->dreg == IA64_R8);
2174 case OP_FCALL_MEMBASE:
2175 g_assert (ins->dreg == 8);
2179 case OP_VCALL_MEMBASE: {
2182 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
2183 storage = cinfo->ret.storage;
2185 if (storage == ArgAggregate) {
2186 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2188 /* Load address of stack space allocated for the return value */
2189 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2190 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2191 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2193 for (i = 0; i < cinfo->ret.nregs; ++i) {
2194 switch (cinfo->ret.atype) {
2195 case AggregateNormal:
2196 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2198 case AggregateSingleHFA:
2199 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2201 case AggregateDoubleHFA:
2202 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2205 g_assert_not_reached ();
2213 g_assert_not_reached ();
2219 #define add_patch_info(cfg,code,patch_type,data) do { \
2220 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2223 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2224 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2226 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2228 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2229 ia64_br_cond_pred (code, (predicate), 0); \
2232 static Ia64CodegenState
2233 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2235 add_patch_info (cfg, code, patch_type, data);
2237 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2239 /* mono_arch_patch_callsite will patch this */
2240 /* mono_arch_nullify_class_init_trampoline will patch this */
2241 ia64_movl (code, GP_SCRATCH_REG, 0);
2242 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2243 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2244 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2245 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2248 /* Can't use a direct call since the displacement might be too small */
2249 /* mono_arch_patch_callsite will patch this */
2250 ia64_movl (code, GP_SCRATCH_REG, 0);
2251 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2252 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2258 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2261 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2266 Ia64CodegenState code;
2267 guint8 *code_start = cfg->native_code + cfg->code_len;
2268 MonoInst *last_ins = NULL;
2269 guint last_offset = 0;
2272 if (cfg->opt & MONO_OPT_PEEPHOLE)
2273 peephole_pass (cfg, bb);
2275 if (cfg->opt & MONO_OPT_LOOP) {
2279 if (cfg->verbose_level > 2)
2280 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2282 cpos = bb->max_offset;
2284 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2288 offset = code_start - cfg->native_code;
2290 ia64_codegen_init (code, code_start);
2293 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2299 offset = code.buf - cfg->native_code;
2301 max_len = ((int)(((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN])) + 128;
2303 while (offset + max_len + 16 > cfg->code_size) {
2304 ia64_codegen_close (code);
2306 offset = code.buf - cfg->native_code;
2308 cfg->code_size *= 2;
2309 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2310 code_start = cfg->native_code + offset;
2311 mono_jit_stats.code_reallocs++;
2313 ia64_codegen_init (code, code_start);
2316 mono_debug_record_line_number (cfg, ins, offset);
2318 switch (ins->opcode) {
2321 if (ia64_is_imm14 (ins->inst_c0))
2322 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2324 ia64_movl (code, ins->dreg, ins->inst_c0);
2327 ia64_mov (code, ins->dreg, ins->sreg1);
2330 case OP_IA64_BR_COND: {
2332 if (ins->opcode == OP_IA64_BR_COND)
2334 if (ins->flags & MONO_INST_BRLABEL) {
2335 if (ins->inst_i0->inst_c0) {
2338 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2339 ia64_br_cond_pred (code, pred, 0);
2342 if (ins->inst_target_bb->native_offset) {
2343 guint8 *pos = code.buf + code.nins;
2345 ia64_br_cond_pred (code, pred, 0);
2346 ia64_begin_bundle (code);
2347 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2349 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2350 ia64_br_cond_pred (code, pred, 0);
2356 ia64_begin_bundle (code);
2357 ins->inst_c0 = code.buf - cfg->native_code;
2362 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2363 ia64_br_cond_reg (code, IA64_B6);
2367 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2371 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2375 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2379 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2383 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2387 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2390 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2394 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2397 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2398 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2402 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2405 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2409 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2412 /* p6 and p7 is set if there is signed/unsigned overflow */
2414 /* Set p8-p9 == (sreg2 > 0) */
2415 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2417 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2419 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2420 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2421 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2422 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2424 /* res <u sreg1 => unsigned overflow */
2425 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2427 /* FIXME: Predicate this since this is a side effect */
2428 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2431 /* p6 and p7 is set if there is signed/unsigned overflow */
2433 /* Set p8-p9 == (sreg2 > 0) */
2434 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2436 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2438 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2439 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2440 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2441 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2443 /* sreg1 <u sreg2 => unsigned overflow */
2444 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2446 /* FIXME: Predicate this since this is a side effect */
2447 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2450 /* Same as OP_IADDCC */
2451 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2453 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2455 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2456 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2458 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2460 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2463 /* Same as OP_ISUBCC */
2465 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2467 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2469 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2470 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2472 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2474 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2478 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2482 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2485 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2488 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2493 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2496 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2499 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2501 case OP_ISHR_UN_IMM:
2502 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2503 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2505 case OP_LSHR_UN_IMM:
2506 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2509 /* Based on gcc code */
2510 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2511 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2512 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2513 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2516 case OP_STOREI1_MEMBASE_REG:
2517 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2519 case OP_STOREI2_MEMBASE_REG:
2520 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2522 case OP_STOREI4_MEMBASE_REG:
2523 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2525 case OP_STOREI8_MEMBASE_REG:
2526 case OP_STORE_MEMBASE_REG:
2527 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2530 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2531 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2533 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2534 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2536 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2537 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2539 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2540 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2543 case OP_LOADU1_MEMBASE:
2544 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2546 case OP_LOADU2_MEMBASE:
2547 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2549 case OP_LOADU4_MEMBASE:
2550 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2552 case OP_LOADI1_MEMBASE:
2553 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2554 ia64_sxt1 (code, ins->dreg, ins->dreg);
2556 case OP_LOADI2_MEMBASE:
2557 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2558 ia64_sxt2 (code, ins->dreg, ins->dreg);
2560 case OP_LOADI4_MEMBASE:
2561 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2562 ia64_sxt4 (code, ins->dreg, ins->dreg);
2564 case OP_LOAD_MEMBASE:
2565 case OP_LOADI8_MEMBASE:
2566 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2569 case OP_IA64_LOADU1_MEMBASE_INC:
2570 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2572 case OP_IA64_LOADU2_MEMBASE_INC:
2573 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2575 case OP_IA64_LOADU4_MEMBASE_INC:
2576 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2578 case OP_IA64_LOADI8_MEMBASE_INC:
2579 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2583 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2586 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2589 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2592 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2595 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2598 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2601 /* Compare opcodes */
2602 case OP_IA64_CMP4_EQ:
2603 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2605 case OP_IA64_CMP4_NE:
2606 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2608 case OP_IA64_CMP4_LE:
2609 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2611 case OP_IA64_CMP4_LT:
2612 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2614 case OP_IA64_CMP4_GE:
2615 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2617 case OP_IA64_CMP4_GT:
2618 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2620 case OP_IA64_CMP4_LT_UN:
2621 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2623 case OP_IA64_CMP4_LE_UN:
2624 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2626 case OP_IA64_CMP4_GT_UN:
2627 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2629 case OP_IA64_CMP4_GE_UN:
2630 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2632 case OP_IA64_CMP_EQ:
2633 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2635 case OP_IA64_CMP_NE:
2636 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2638 case OP_IA64_CMP_LE:
2639 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2641 case OP_IA64_CMP_LT:
2642 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2644 case OP_IA64_CMP_GE:
2645 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2647 case OP_IA64_CMP_GT:
2648 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2650 case OP_IA64_CMP_GT_UN:
2651 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2653 case OP_IA64_CMP_LT_UN:
2654 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2656 case OP_IA64_CMP_GE_UN:
2657 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2659 case OP_IA64_CMP_LE_UN:
2660 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2662 case OP_IA64_CMP4_EQ_IMM:
2663 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2665 case OP_IA64_CMP4_NE_IMM:
2666 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2668 case OP_IA64_CMP4_LE_IMM:
2669 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2671 case OP_IA64_CMP4_LT_IMM:
2672 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2674 case OP_IA64_CMP4_GE_IMM:
2675 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2677 case OP_IA64_CMP4_GT_IMM:
2678 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2680 case OP_IA64_CMP4_LT_UN_IMM:
2681 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2683 case OP_IA64_CMP4_LE_UN_IMM:
2684 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2686 case OP_IA64_CMP4_GT_UN_IMM:
2687 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2689 case OP_IA64_CMP4_GE_UN_IMM:
2690 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2692 case OP_IA64_CMP_EQ_IMM:
2693 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2695 case OP_IA64_CMP_NE_IMM:
2696 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2698 case OP_IA64_CMP_LE_IMM:
2699 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2701 case OP_IA64_CMP_LT_IMM:
2702 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2704 case OP_IA64_CMP_GE_IMM:
2705 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2707 case OP_IA64_CMP_GT_IMM:
2708 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2710 case OP_IA64_CMP_GT_UN_IMM:
2711 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2713 case OP_IA64_CMP_LT_UN_IMM:
2714 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2716 case OP_IA64_CMP_GE_UN_IMM:
2717 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2719 case OP_IA64_CMP_LE_UN_IMM:
2720 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2722 case OP_IA64_FCMP_EQ:
2723 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2725 case OP_IA64_FCMP_NE:
2726 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2728 case OP_IA64_FCMP_LT:
2729 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2731 case OP_IA64_FCMP_GT:
2732 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2734 case OP_IA64_FCMP_LE:
2735 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2737 case OP_IA64_FCMP_GE:
2738 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2740 case OP_IA64_FCMP_GT_UN:
2741 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2742 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2744 case OP_IA64_FCMP_LT_UN:
2745 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2746 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2748 case OP_IA64_FCMP_GE_UN:
2749 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2750 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2752 case OP_IA64_FCMP_LE_UN:
2753 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2754 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2757 case OP_COND_EXC_IOV:
2758 case OP_COND_EXC_OV:
2759 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2761 case OP_COND_EXC_IC:
2763 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2765 case OP_IA64_COND_EXC:
2766 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2769 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2770 ia64_no_stop (code);
2771 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2774 /* FIXME: Is this needed ? */
2775 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2778 /* FIXME: Is this needed ? */
2779 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2782 /* FIXME: Is this needed ? */
2783 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2786 /* FIXME: Is this needed */
2787 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2790 /* FIXME: Is this needed */
2791 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2794 /* FIXME: Is this needed */
2795 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2799 /* FIXME: Sign extend ? */
2800 ia64_mov (code, ins->dreg, ins->sreg1);
2804 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2811 double d = *(double *)ins->inst_p0;
2813 if ((d == 0.0) && (mono_signbit (d) == 0))
2814 ia64_fmov (code, ins->dreg, 0);
2816 ia64_fmov (code, ins->dreg, 1);
2818 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2819 ia64_movl (code, GP_SCRATCH_REG, 0);
2820 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2825 float f = *(float *)ins->inst_p0;
2827 if ((f == 0.0) && (mono_signbit (f) == 0))
2828 ia64_fmov (code, ins->dreg, 0);
2830 ia64_fmov (code, ins->dreg, 1);
2832 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2833 ia64_movl (code, GP_SCRATCH_REG, 0);
2834 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2839 ia64_fmov (code, ins->dreg, ins->sreg1);
2841 case OP_STORER8_MEMBASE_REG:
2842 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2844 case OP_STORER4_MEMBASE_REG:
2845 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2846 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2848 case OP_LOADR8_MEMBASE:
2849 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2851 case OP_LOADR4_MEMBASE:
2852 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2853 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2856 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2857 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2858 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2861 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2862 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2863 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2865 case OP_LCONV_TO_R8:
2866 /* FIXME: Difference with CEE_CONV_R8 ? */
2867 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2868 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2869 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2871 case OP_LCONV_TO_R4:
2872 /* FIXME: Difference with CEE_CONV_R4 ? */
2873 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2874 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2875 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2877 case OP_FCONV_TO_R4:
2878 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2880 case OP_FCONV_TO_I8:
2881 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2882 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2885 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2888 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2891 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2894 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2898 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2899 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2901 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2902 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2903 /* Positive infinity */
2904 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2905 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2906 /* Negative infinity */
2907 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2908 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2913 /* ensure ins->sreg1 is not NULL */
2914 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2917 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2918 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2925 call = (MonoCallInst*)ins;
2927 if (ins->flags & MONO_INST_HAS_METHOD)
2928 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2930 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2932 code = emit_move_return_value (cfg, ins, code);
2939 case OP_VOIDCALL_REG:
2940 call = (MonoCallInst*)ins;
2944 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2947 ia64_mov (code, IA64_R8, ins->sreg1);
2948 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2949 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2950 ia64_ld8 (code, IA64_GP, IA64_R8);
2951 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2953 code = emit_move_return_value (cfg, ins, code);
2956 case OP_FCALL_MEMBASE:
2957 case OP_LCALL_MEMBASE:
2958 case OP_VCALL_MEMBASE:
2959 case OP_VOIDCALL_MEMBASE:
2960 case OP_CALL_MEMBASE:
2962 * There are no membase instructions on ia64, but we can't
2963 * lower this since get_vcall_slot_addr () needs to decode it.
2966 /* Keep this in synch with get_vcall_slot_addr */
2967 if (ia64_is_imm14 (ins->inst_offset))
2968 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2970 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2971 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2974 ia64_begin_bundle (code);
2975 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2977 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2979 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2982 * This nop will tell get_vcall_slot_addr that this is a virtual
2985 ia64_nop_i (code, 0x12345);
2987 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2989 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2991 code = emit_move_return_value (cfg, ins, code);
2995 * Keep in sync with the code in emit_epilog.
2998 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3001 g_assert (!cfg->method->save_lmf);
3003 /* Load arguments into their original registers */
3004 code = emit_load_volatile_arguments (cfg, code);
3006 if (cfg->arch.stack_alloc_size) {
3007 if (cfg->arch.omit_fp) {
3008 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
3009 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
3011 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
3012 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3016 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
3018 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3019 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3021 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3022 ia64_movl (code, GP_SCRATCH_REG, 0);
3023 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3024 ia64_br_cond_reg (code, IA64_B6);
3029 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
3035 /* FIXME: Sigaltstack support */
3037 /* keep alignment */
3038 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->sreg1);
3039 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_FRAME_ALIGNMENT - 1));
3040 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3042 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3044 ia64_mov (code, ins->dreg, IA64_SP);
3046 /* An area at sp is reserved by the ABI for parameter passing */
3047 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
3048 if (ia64_is_adds_imm (abi_offset))
3049 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3051 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3052 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3055 if (ins->flags & MONO_INST_INIT) {
3057 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3059 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3062 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3063 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3064 ia64_br_cond_pred (code, 8, -2);
3066 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3068 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3074 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
3075 ia64_ld8 (code, ins->dreg, ins->dreg);
3078 /* Synchronization */
3079 case OP_MEMORY_BARRIER:
3082 case OP_ATOMIC_ADD_IMM_NEW_I4:
3083 g_assert (ins->inst_offset == 0);
3084 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3085 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3087 case OP_ATOMIC_ADD_IMM_NEW_I8:
3088 g_assert (ins->inst_offset == 0);
3089 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3090 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3092 case OP_ATOMIC_EXCHANGE_I4:
3093 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3094 ia64_sxt4 (code, ins->dreg, ins->dreg);
3096 case OP_ATOMIC_EXCHANGE_I8:
3097 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3099 case OP_ATOMIC_ADD_NEW_I4: {
3100 guint8 *label, *buf;
3102 /* From libatomic_ops */
3105 ia64_begin_bundle (code);
3106 label = code.buf + code.nins;
3107 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
3108 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3109 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3110 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3111 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3112 buf = code.buf + code.nins;
3113 ia64_br_cond_pred (code, 7, 0);
3114 ia64_begin_bundle (code);
3115 ia64_patch (buf, label);
3116 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3119 case OP_ATOMIC_ADD_NEW_I8: {
3120 guint8 *label, *buf;
3122 /* From libatomic_ops */
3125 ia64_begin_bundle (code);
3126 label = code.buf + code.nins;
3127 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
3128 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3129 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3130 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3131 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3132 buf = code.buf + code.nins;
3133 ia64_br_cond_pred (code, 7, 0);
3134 ia64_begin_bundle (code);
3135 ia64_patch (buf, label);
3136 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3140 /* Exception handling */
3141 case OP_CALL_HANDLER:
3143 * Using a call instruction would mess up the register stack, so
3144 * save the return address to a register and use a
3147 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3148 ia64_mov (code, IA64_R15, IA64_R0);
3149 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3150 /* Add the length of OP_CALL_HANDLER */
3151 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3152 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3153 ia64_movl (code, GP_SCRATCH_REG2, 0);
3154 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3155 ia64_br_cond_reg (code, IA64_B6);
3156 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3158 case OP_START_HANDLER: {
3160 * We receive the return address in GP_SCRATCH_REG.
3162 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3165 * R15 determines our caller. It is used since it is writable using
3167 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3168 * R15 != 0 means we are called by call_filter ().
3170 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3171 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3173 ia64_br_cond_pred (code, 6, 6);
3176 * Called by call_filter:
3177 * Allocate a new stack frame, and set the fp register from the
3178 * value passed in by the caller.
3179 * We allocate a similar frame as is done by the prolog, so
3180 * if an exception is thrown while executing the filter, the
3181 * unwinder can unwind through the filter frame using the unwind
3182 * info for the prolog.
3184 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);
3185 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3186 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3187 ia64_mov (code, cfg->frame_reg, IA64_R15);
3188 /* Signal to endfilter that we are called by call_filter */
3189 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3191 /* Save the return address */
3192 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3193 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3194 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3198 case CEE_ENDFINALLY:
3199 case OP_ENDFILTER: {
3200 /* FIXME: Return the value in ENDFILTER */
3201 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3203 /* Load the return address */
3204 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3205 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3208 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3209 ia64_br_cond_pred (code, 7, 4);
3211 /* Called by call_filter */
3213 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3214 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3215 ia64_br_ret_reg (code, IA64_B0);
3217 /* Called by CALL_HANDLER */
3218 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3219 ia64_br_cond_reg (code, IA64_B6);
3223 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3224 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3225 (gpointer)"mono_arch_throw_exception");
3228 * This might be the last instruction in the method, so add a dummy
3229 * instruction so the unwinder will work.
3231 ia64_break_i (code, 0);
3234 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3235 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3236 (gpointer)"mono_arch_rethrow_exception");
3238 ia64_break_i (code, 0);
3242 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3243 g_assert_not_reached ();
3246 if ((code.buf - cfg->native_code - offset) > max_len) {
3247 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3248 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3249 g_assert_not_reached ();
3255 last_offset = offset;
3260 ia64_codegen_close (code);
3262 cfg->code_len = code.buf - cfg->native_code;
3266 mono_arch_register_lowlevel_calls (void)
3268 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3271 static Ia64InsType ins_types_in_template [32][3] = {
3272 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3273 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3274 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3275 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3276 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3277 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3280 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3281 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3282 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3283 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3284 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3285 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3286 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3287 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3288 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3289 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3290 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3291 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3294 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3295 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3296 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3297 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3300 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3301 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3306 static gboolean stops_in_template [32][3] = {
3307 { FALSE, FALSE, FALSE },
3308 { FALSE, FALSE, TRUE },
3309 { FALSE, TRUE, FALSE },
3310 { FALSE, TRUE, TRUE },
3311 { FALSE, FALSE, FALSE },
3312 { FALSE, FALSE, TRUE },
3313 { FALSE, FALSE, FALSE },
3314 { FALSE, FALSE, FALSE },
3316 { FALSE, FALSE, FALSE },
3317 { FALSE, FALSE, TRUE },
3318 { TRUE, FALSE, FALSE },
3319 { TRUE, FALSE, TRUE },
3320 { FALSE, FALSE, FALSE },
3321 { FALSE, FALSE, TRUE },
3322 { FALSE, FALSE, FALSE },
3323 { FALSE, FALSE, TRUE },
3325 { FALSE, FALSE, FALSE },
3326 { FALSE, FALSE, TRUE },
3327 { FALSE, FALSE, FALSE },
3328 { FALSE, FALSE, TRUE },
3329 { FALSE, FALSE, FALSE },
3330 { FALSE, FALSE, FALSE },
3331 { FALSE, FALSE, FALSE },
3332 { FALSE, FALSE, TRUE },
3334 { FALSE, FALSE, FALSE },
3335 { FALSE, FALSE, TRUE },
3336 { FALSE, FALSE, FALSE },
3337 { FALSE, FALSE, FALSE },
3338 { FALSE, FALSE, FALSE },
3339 { FALSE, FALSE, TRUE },
3340 { FALSE, FALSE, FALSE },
3341 { FALSE, FALSE, FALSE }
3344 static int last_stop_in_template [32] = {
3345 -1, 2, 1, 2, -1, 2, -1, -1,
3346 -1, 2, 0, 2, -1, 2, -1, 2,
3347 -1, 2, -1, 2, -1, -1, -1, 2,
3348 -1, 2, -1, -1, -1, 2, -1, -1
3351 static guint64 nops_for_ins_types [6] = {
3360 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3367 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3369 #define DEBUG_INS_SCHED(a)
3373 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3375 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3376 guint8 *deps = code->dep_info;
3377 gboolean need_stop, no_stop;
3379 for (i = 0; i < code->nins; ++i)
3383 current_deps_start = 0;
3384 current_ins_start = 0;
3385 deps_start [ins_index] = current_ins_start;
3388 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3389 while (pos < code->dep_info_pos) {
3391 switch (deps [pos]) {
3392 case IA64_END_OF_INS:
3394 current_ins_start = pos + 2;
3395 deps_start [ins_index] = current_ins_start;
3397 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3402 reg = deps [pos + 1];
3404 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3405 for (i = current_deps_start; i < current_ins_start; i += 2)
3406 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3410 reg = code->dep_info [pos + 1];
3412 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3413 for (i = current_deps_start; i < current_ins_start; i += 2)
3414 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3418 reg = deps [pos + 1];
3420 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3421 for (i = current_deps_start; i < current_ins_start; i += 2)
3422 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3425 case IA64_READ_PR_BRANCH:
3426 reg = deps [pos + 1];
3428 /* Writes to prs by non-float instructions are visible to branches */
3429 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3430 for (i = current_deps_start; i < current_ins_start; i += 2)
3431 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3435 reg = code->dep_info [pos + 1];
3437 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3438 for (i = current_deps_start; i < current_ins_start; i += 2)
3439 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3442 case IA64_WRITE_PR_FLOAT:
3443 reg = code->dep_info [pos + 1];
3445 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3446 for (i = current_deps_start; i < current_ins_start; i += 2)
3447 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3451 reg = deps [pos + 1];
3453 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3454 for (i = current_deps_start; i < current_ins_start; i += 2)
3455 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3459 reg = code->dep_info [pos + 1];
3461 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3462 for (i = current_deps_start; i < current_ins_start; i += 2)
3463 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3466 case IA64_READ_BR_BRANCH:
3467 reg = deps [pos + 1];
3469 /* Writes to brs are visible to branches */
3470 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3473 reg = deps [pos + 1];
3475 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3476 for (i = current_deps_start; i < current_ins_start; i += 2)
3477 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3481 reg = code->dep_info [pos + 1];
3483 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3484 for (i = current_deps_start; i < current_ins_start; i += 2)
3485 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3489 reg = deps [pos + 1];
3491 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3492 for (i = current_deps_start; i < current_ins_start; i += 2)
3493 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3497 reg = code->dep_info [pos + 1];
3499 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3500 for (i = current_deps_start; i < current_ins_start; i += 2)
3501 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3506 * Explicitly indicate that a stop is not required. Useful for
3507 * example when two predicated instructions with negated predicates
3508 * write the same registers.
3513 g_assert_not_reached ();
3517 if (need_stop && !no_stop) {
3518 g_assert (ins_index > 0);
3519 stops [ins_index - 1] = 1;
3521 DEBUG_INS_SCHED (printf ("STOP\n"));
3522 current_deps_start = current_ins_start;
3524 /* Skip remaining deps for this instruction */
3525 while (deps [pos] != IA64_END_OF_INS)
3530 if (code->nins > 0) {
3531 /* No dependency info for the last instruction */
3532 stops [code->nins - 1] = 1;
3535 deps_start [code->nins] = code->dep_info_pos;
3539 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3541 int stop_pos, i, deps_to_shift, dep_shift;
3543 g_assert (n <= code->nins);
3545 // if (n > 1) printf ("FOUND: %ld.\n", template);
3547 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3549 stop_pos = last_stop_in_template [template] + 1;
3553 /* Compute the number of 'real' instructions before the stop */
3554 deps_to_shift = stop_pos;
3555 if (stop_pos >= 3 && (nops & (1 << 2)))
3557 if (stop_pos >= 2 && (nops & (1 << 1)))
3559 if (stop_pos >= 1 && (nops & (1 << 0)))
3563 * We have to keep some dependencies whose instructions have been shifted
3564 * out of the buffer. So nullify the end_of_ins markers in the dependency
3567 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3568 if (code->dep_info [i] == IA64_END_OF_INS)
3569 code->dep_info [i] = IA64_NONE;
3571 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3572 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3573 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3575 dep_shift = deps_start [deps_to_shift];
3576 for (i = 0; i < code->nins + 1 - n; ++i)
3577 deps_start [i] = deps_start [n + i] - dep_shift;
3579 /* Determine the exact positions of instructions with unwind ops */
3580 if (code->unw_op_count) {
3582 int curr_ins, curr_ins_pos;
3585 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3586 for (i = 0; i < 3; ++i) {
3587 if (! (nops & (1 << i))) {
3588 ins_pos [curr_ins] = curr_ins_pos + i;
3593 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3594 if (code->unw_ops_pos [i] < n) {
3595 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3596 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3599 if (code->unw_op_pos < code->unw_op_count)
3600 code->unw_op_pos += n;
3603 if (n == code->nins) {
3608 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3609 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3610 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3616 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3618 int i, ins_type, template, nins_to_emit;
3619 int deps_start [16];
3624 * We implement a simple scheduler which tries to put three instructions
3625 * per bundle, then two, then one.
3627 ia64_analyze_deps (code, deps_start, stops);
3629 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3630 /* Find a suitable template */
3631 for (template = 0; template < 32; ++template) {
3632 if (stops_in_template [template][0] != stops [0] ||
3633 stops_in_template [template][1] != stops [1] ||
3634 stops_in_template [template][2] != stops [2])
3638 for (i = 0; i < 3; ++i) {
3639 ins_type = ins_types_in_template [template][i];
3640 switch (code->itypes [i]) {
3641 case IA64_INS_TYPE_A:
3642 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3645 found &= (ins_type == code->itypes [i]);
3651 found = debug_ins_sched ();
3654 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3660 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3661 /* Wait for more instructions */
3664 /* If it didn't work out, try putting two instructions into one bundle */
3665 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3666 /* Try a nop at the end */
3667 for (template = 0; template < 32; ++template) {
3668 if (stops_in_template [template][0] != stops [0] ||
3669 ((stops_in_template [template][1] != stops [1]) &&
3670 (stops_in_template [template][2] != stops [1])))
3674 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3675 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3678 if (!debug_ins_sched ())
3681 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);
3686 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3687 /* Wait for more instructions */
3690 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3691 /* Try a nop in the middle */
3692 for (template = 0; template < 32; ++template) {
3693 if (((stops_in_template [template][0] != stops [0]) &&
3694 (stops_in_template [template][1] != stops [0])) ||
3695 stops_in_template [template][2] != stops [1])
3698 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3699 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3702 if (!debug_ins_sched ())
3705 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);
3710 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3711 /* Try a nop at the beginning */
3712 for (template = 0; template < 32; ++template) {
3713 if ((stops_in_template [template][1] != stops [0]) ||
3714 (stops_in_template [template][2] != stops [1]))
3717 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3718 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3721 if (!debug_ins_sched ())
3724 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);
3729 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3730 /* Wait for more instructions */
3734 nins_to_emit = code->nins;
3738 while (nins_to_emit > 0) {
3739 if (!debug_ins_sched ())
3741 switch (code->itypes [0]) {
3742 case IA64_INS_TYPE_A:
3744 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3746 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3748 case IA64_INS_TYPE_I:
3750 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3752 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3754 case IA64_INS_TYPE_M:
3756 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3758 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3760 case IA64_INS_TYPE_B:
3762 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3764 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3766 case IA64_INS_TYPE_F:
3768 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3770 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3772 case IA64_INS_TYPE_LX:
3773 if (stops [0] || stops [1])
3774 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3776 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3780 g_assert_not_reached ();
3786 unw_dyn_region_info_t*
3787 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3789 unw_dyn_region_info_t *r;
3791 g_assert (code->nins == 0);
3792 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3793 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3794 r->op_count = code->unw_op_count;
3795 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3796 code->unw_op_count = 0;
3797 code->unw_op_pos = 0;
3798 code->region_start = code->buf;
3804 ia64_patch (unsigned char* code, gpointer target)
3807 guint64 instructions [3];
3808 guint8 gen_buf [16];
3809 Ia64CodegenState gen;
3814 * code encodes both the position inside the buffer and code.nins when
3815 * the instruction was emitted.
3817 ins_to_skip = (guint64)code % 16;
3818 code = (unsigned char*)((guint64)code & ~15);
3821 * Search for the first instruction which is 'patchable', skipping
3822 * ins_to_skip instructions.
3827 template = ia64_bundle_template (code);
3828 instructions [0] = ia64_bundle_ins1 (code);
3829 instructions [1] = ia64_bundle_ins2 (code);
3830 instructions [2] = ia64_bundle_ins3 (code);
3832 ia64_codegen_init (gen, gen_buf);
3835 for (i = 0; i < 3; ++i) {
3836 guint64 ins = instructions [i];
3837 int opcode = ia64_ins_opcode (ins);
3839 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3847 switch (ins_types_in_template [template][i]) {
3848 case IA64_INS_TYPE_A:
3849 case IA64_INS_TYPE_M:
3850 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3852 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3853 instructions [i] = gen.instructions [0];
3859 case IA64_INS_TYPE_B:
3860 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3862 gint64 disp = ((guint8*)target - code) >> 4;
3865 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3867 instructions [i] = gen.instructions [0];
3870 else if (opcode == 5) {
3872 gint64 disp = ((guint8*)target - code) >> 4;
3875 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3876 instructions [i] = gen.instructions [0];
3882 case IA64_INS_TYPE_LX:
3886 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3888 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3889 instructions [1] = gen.instructions [0];
3890 instructions [2] = gen.instructions [1];
3903 ia64_codegen_init (gen, code);
3904 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3914 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3916 MonoJumpInfo *patch_info;
3918 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3919 unsigned char *ip = patch_info->ip.i + code;
3920 const unsigned char *target;
3922 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3924 if (patch_info->type == MONO_PATCH_INFO_NONE)
3926 if (mono_compile_aot) {
3930 ia64_patch (ip, (gpointer)target);
3935 mono_arch_emit_prolog (MonoCompile *cfg)
3937 MonoMethod *method = cfg->method;
3938 MonoMethodSignature *sig;
3940 int alloc_size, pos, i;
3941 Ia64CodegenState code;
3944 sig = mono_method_signature (method);
3947 cinfo = get_call_info (sig, FALSE);
3949 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3951 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3952 cfg->code_size += 1024;
3953 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3954 cfg->code_size += 1024;
3956 cfg->native_code = g_malloc (cfg->code_size);
3958 ia64_codegen_init (code, cfg->native_code);
3960 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3961 if (cfg->param_area)
3962 alloc_size += cfg->param_area;
3966 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3968 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3969 /* Force sp to be saved/restored */
3970 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3972 cfg->arch.stack_alloc_size = alloc_size;
3976 if (method->save_lmf) {
3977 /* No LMF on IA64 */
3982 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3983 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);
3984 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3985 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3987 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3988 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3989 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3990 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3991 ia64_mov (code, cfg->frame_reg, IA64_SP);
3995 int pagesize = getpagesize ();
3997 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3998 if (alloc_size >= pagesize) {
3999 gint32 remaining_size = alloc_size;
4001 /* Generate stack touching code */
4002 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
4003 while (remaining_size >= pagesize) {
4004 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
4005 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4006 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4007 remaining_size -= pagesize;
4011 if (ia64_is_imm14 (-alloc_size)) {
4012 if (cfg->arch.omit_fp)
4013 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4014 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
4017 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
4018 if (cfg->arch.omit_fp)
4019 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4020 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4024 ia64_begin_bundle (code);
4026 /* Initialize unwind info */
4027 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
4029 if (sig->ret->type != MONO_TYPE_VOID) {
4030 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
4031 /* Save volatile arguments to the stack */
4036 /* Keep this in sync with emit_load_volatile_arguments */
4037 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4038 ArgInfo *ainfo = cinfo->args + i;
4039 gint32 stack_offset;
4041 inst = cfg->varinfo [i];
4043 if (sig->hasthis && (i == 0))
4044 arg_type = &mono_defaults.object_class->byval_arg;
4046 arg_type = sig->params [i - sig->hasthis];
4048 arg_type = mono_type_get_underlying_type (arg_type);
4050 stack_offset = ainfo->offset + ARGS_OFFSET;
4052 /* Save volatile arguments to the stack */
4053 if (inst->opcode != OP_REGVAR) {
4054 switch (ainfo->storage) {
4057 /* FIXME: big offsets */
4058 g_assert (inst->opcode == OP_REGOFFSET);
4059 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4060 if (arg_type->byref)
4061 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4063 switch (arg_type->type) {
4065 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4068 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4071 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4079 if (ainfo->nslots != ainfo->nregs)
4082 g_assert (inst->opcode == OP_REGOFFSET);
4083 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4084 for (i = 0; i < ainfo->nregs; ++i) {
4085 switch (ainfo->atype) {
4086 case AggregateNormal:
4087 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
4089 case AggregateSingleHFA:
4090 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
4092 case AggregateDoubleHFA:
4093 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4101 g_assert_not_reached ();
4105 if (inst->opcode == OP_REGVAR) {
4106 /* Argument allocated to (non-volatile) register */
4107 switch (ainfo->storage) {
4109 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4110 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4113 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4114 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4122 if (method->save_lmf) {
4123 /* No LMF on IA64 */
4126 ia64_codegen_close (code);
4130 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4131 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4133 cfg->code_len = code.buf - cfg->native_code;
4135 g_assert (cfg->code_len < cfg->code_size);
4137 cfg->arch.prolog_end_offset = cfg->code_len;
4143 mono_arch_emit_epilog (MonoCompile *cfg)
4145 MonoMethod *method = cfg->method;
4147 int max_epilog_size = 16 * 4;
4148 Ia64CodegenState code;
4153 if (mono_jit_trace_calls != NULL)
4154 max_epilog_size += 1024;
4156 cfg->arch.epilog_begin_offset = cfg->code_len;
4158 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4159 cfg->code_size *= 2;
4160 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4161 mono_jit_stats.code_reallocs++;
4164 /* FIXME: Emit unwind info */
4166 buf = cfg->native_code + cfg->code_len;
4168 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4169 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4171 ia64_codegen_init (code, buf);
4173 /* the code restoring the registers must be kept in sync with CEE_JMP */
4176 if (method->save_lmf) {
4177 /* No LMF on IA64 */
4180 /* Load returned vtypes into registers if needed */
4181 cinfo = get_call_info (mono_method_signature (method), FALSE);
4182 ainfo = &cinfo->ret;
4183 switch (ainfo->storage) {
4185 if (ainfo->nslots != ainfo->nregs)
4188 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4189 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4190 for (i = 0; i < ainfo->nregs; ++i) {
4191 switch (ainfo->atype) {
4192 case AggregateNormal:
4193 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4195 case AggregateSingleHFA:
4196 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4198 case AggregateDoubleHFA:
4199 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4202 g_assert_not_reached ();
4211 ia64_begin_bundle (code);
4213 code.region_start = cfg->native_code;
4215 /* Label the unwind state at the start of the exception throwing region */
4216 //ia64_unw_label_state (code, 1234);
4218 if (cfg->arch.stack_alloc_size) {
4219 if (cfg->arch.omit_fp) {
4220 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4221 ia64_unw_pop_frames (code, 1);
4222 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4224 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4225 ia64_unw_pop_frames (code, 1);
4226 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4230 ia64_unw_pop_frames (code, 1);
4231 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4234 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4235 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4236 ia64_br_ret_reg (code, IA64_B0);
4238 ia64_codegen_close (code);
4240 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4241 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4243 cfg->code_len = code.buf - cfg->native_code;
4245 g_assert (cfg->code_len < cfg->code_size);
4249 mono_arch_emit_exceptions (MonoCompile *cfg)
4251 MonoJumpInfo *patch_info;
4253 Ia64CodegenState code;
4254 gboolean empty = TRUE;
4255 //unw_dyn_region_info_t *r_exceptions;
4256 MonoClass *exc_classes [16];
4257 guint8 *exc_throw_start [16], *exc_throw_end [16];
4258 guint32 code_size = 0;
4260 /* Compute needed space */
4261 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4262 if (patch_info->type == MONO_PATCH_INFO_EXC)
4264 if (patch_info->type == MONO_PATCH_INFO_R8)
4265 code_size += 8 + 7; /* sizeof (double) + alignment */
4266 if (patch_info->type == MONO_PATCH_INFO_R4)
4267 code_size += 4 + 7; /* sizeof (float) + alignment */
4273 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4274 cfg->code_size *= 2;
4275 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4276 mono_jit_stats.code_reallocs++;
4279 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4281 /* The unwind state here is the same as before the epilog */
4282 //ia64_unw_copy_state (code, 1234);
4284 /* add code to raise exceptions */
4285 /* FIXME: Optimize this */
4287 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4288 switch (patch_info->type) {
4289 case MONO_PATCH_INFO_EXC: {
4290 MonoClass *exc_class;
4293 guint64 exc_token_index;
4295 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4296 g_assert (exc_class);
4297 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4298 throw_ip = cfg->native_code + patch_info->ip.i;
4300 ia64_begin_bundle (code);
4302 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4304 /* Find a throw sequence for the same exception class */
4305 for (i = 0; i < nthrows; ++i)
4306 if (exc_classes [i] == exc_class)
4310 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4312 if (ia64_is_adds_imm (offset))
4313 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4315 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4317 buf = code.buf + code.nins;
4318 ia64_br_cond_pred (code, 0, 0);
4319 ia64_begin_bundle (code);
4320 ia64_patch (buf, exc_throw_start [i]);
4322 patch_info->type = MONO_PATCH_INFO_NONE;
4327 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4329 ia64_begin_bundle (code);
4332 exc_classes [nthrows] = exc_class;
4333 exc_throw_start [nthrows] = code.buf;
4337 if (ia64_is_adds_imm (exc_token_index))
4338 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4340 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4342 patch_info->data.name = "mono_arch_throw_corlib_exception";
4343 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4344 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4347 ia64_movl (code, GP_SCRATCH_REG, 0);
4348 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4349 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4350 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4352 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4354 /* Patch up the throw offset */
4355 ia64_begin_bundle (code);
4357 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4360 exc_throw_end [nthrows] = code.buf;
4374 /* The unwinder needs this to work */
4375 ia64_break_i (code, 0);
4377 ia64_codegen_close (code);
4380 //r_exceptions = mono_ia64_create_unwind_region (&code);
4381 //cfg->arch.r_epilog = r_exceptions;
4383 cfg->code_len = code.buf - cfg->native_code;
4385 g_assert (cfg->code_len < cfg->code_size);
4389 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4391 Ia64CodegenState code;
4392 CallInfo *cinfo = NULL;
4393 MonoMethodSignature *sig;
4395 int i, n, stack_area = 0;
4397 ia64_codegen_init (code, p);
4399 /* Keep this in sync with mono_arch_get_argument_info */
4401 if (enable_arguments) {
4402 /* Allocate a new area on the stack and save arguments there */
4403 sig = mono_method_signature (cfg->method);
4405 cinfo = get_call_info (sig, FALSE);
4407 n = sig->param_count + sig->hasthis;
4409 stack_area = ALIGN_TO (n * 8, 16);
4412 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4414 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4416 /* FIXME: Allocate out registers */
4418 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4420 /* Required by the ABI */
4421 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4423 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4424 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4426 /* Save arguments to the stack */
4427 for (i = 0; i < n; ++i) {
4428 ins = cfg->varinfo [i];
4430 if (ins->opcode == OP_REGVAR) {
4431 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4432 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4433 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4436 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4437 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4438 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4439 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4440 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4441 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4446 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4449 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4451 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4452 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4454 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4456 if (enable_arguments && stack_area) {
4457 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4459 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4461 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4466 ia64_codegen_close (code);
4472 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4474 Ia64CodegenState code;
4475 CallInfo *cinfo = NULL;
4476 MonoMethod *method = cfg->method;
4477 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4479 ia64_codegen_init (code, p);
4481 cinfo = get_call_info (sig, FALSE);
4483 /* Save return value + pass it to func */
4484 switch (cinfo->ret.storage) {
4488 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4489 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4492 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4493 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4494 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4495 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4497 case ArgValuetypeAddrInIReg:
4498 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4509 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4510 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4511 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4513 /* Restore return value */
4514 switch (cinfo->ret.storage) {
4518 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4521 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4522 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4524 case ArgValuetypeAddrInIReg:
4532 ia64_codegen_close (code);
4538 mono_arch_save_unwind_info (MonoCompile *cfg)
4542 /* FIXME: Unregister this for dynamic methods */
4544 di = g_malloc0 (sizeof (unw_dyn_info_t));
4545 di->start_ip = (unw_word_t) cfg->native_code;
4546 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4548 di->format = UNW_INFO_FORMAT_DYNAMIC;
4549 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4550 di->u.pi.regions = cfg->arch.r_pro;
4552 _U_dyn_register (di);
4556 unw_dyn_region_info_t *region = di->u.pi.regions;
4558 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4560 printf (" [Region: %d]\n", region->insn_count);
4561 region = region->next;
4568 mono_arch_flush_icache (guint8 *code, gint size)
4570 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4571 guint8* end = (guint8*)((guint64)code + size);
4573 #ifdef __INTEL_COMPILER
4574 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4581 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4582 /* FIXME: This could be increased to 128 on some cpus */
4589 mono_arch_flush_register_windows (void)
4591 /* Not needed because of libunwind */
4595 mono_arch_is_inst_imm (gint64 imm)
4597 /* The lowering pass will take care of it */
4603 * Determine whenever the trap whose info is in SIGINFO is caused by
4607 mono_arch_is_int_overflow (void *sigctx, void *info)
4609 /* Division is emulated with explicit overflow checks */
4614 mono_arch_get_patch_offset (guint8 *code)
4622 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4624 guint8 *bundle2 = code - 48;
4625 guint8 *bundle3 = code - 32;
4626 guint8 *bundle4 = code - 16;
4627 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4628 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4629 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4630 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4631 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4632 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4633 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4634 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4635 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4639 * Virtual calls are made with:
4641 * [MII] ld8 r31=[r8]
4645 * mov.sptk b6=r31,0x2000000000f32a80
4652 * br.call.sptk.few b0=b6;;
4655 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4656 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4657 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4658 (ins31 == IA64_NOP_M) &&
4659 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4660 (ins33 == IA64_NOP_I) &&
4661 (ins41 == IA64_NOP_M) &&
4662 (ins42 == IA64_NOP_I) &&
4663 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4664 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4665 g_assert (ins21 == IA64_NOP_M);
4666 g_assert (ins23 == IA64_NOP_I);
4667 g_assert (ia64_ins_opcode (ins22) == 0);
4668 g_assert (ia64_ins_x3 (ins22) == 7);
4669 g_assert (ia64_ins_x (ins22) == 0);
4670 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4675 * Must be a scratch register, since only those are saved by the trampoline
4677 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4679 g_assert (regs [reg]);
4688 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4695 static gboolean tls_offset_inited = FALSE;
4698 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4700 if (!tls_offset_inited) {
4701 tls_offset_inited = TRUE;
4703 appdomain_tls_offset = mono_domain_get_tls_offset ();
4704 thread_tls_offset = mono_thread_get_tls_offset ();
4709 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4714 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4716 MonoCallInst *call = (MonoCallInst*)inst;
4717 int out_reg = cfg->arch.reg_out0;
4720 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4723 if (cinfo->ret.storage == ArgAggregate) {
4724 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4727 * The valuetype is in registers after the call, need to be copied
4728 * to the stack. Save the address to a local here, so the call
4729 * instruction can access it.
4731 g_assert (local->opcode == OP_REGOFFSET);
4732 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4735 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4736 vtarg->sreg1 = vt_reg;
4737 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4738 mono_bblock_add_inst (cfg->cbb, vtarg);
4740 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4748 /* add the this argument */
4749 if (this_reg != -1) {
4751 MONO_INST_NEW (cfg, this, OP_MOVE);
4752 this->type = this_type;
4753 this->sreg1 = this_reg;
4754 this->dreg = mono_regstate_next_int (cfg->rs);
4755 mono_bblock_add_inst (cfg->cbb, this);
4757 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4762 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4764 MonoInst *ins = NULL;
4766 if (cmethod->klass == mono_defaults.thread_class &&
4767 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4768 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4769 } else if(cmethod->klass->image == mono_defaults.corlib &&
4770 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4771 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4773 if (strcmp (cmethod->name, "Increment") == 0) {
4776 if (fsig->params [0]->type == MONO_TYPE_I4)
4777 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4778 else if (fsig->params [0]->type == MONO_TYPE_I8)
4779 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4781 g_assert_not_reached ();
4782 MONO_INST_NEW (cfg, ins, opcode);
4784 ins->inst_i0 = args [0];
4785 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4788 if (fsig->params [0]->type == MONO_TYPE_I4)
4789 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4790 else if (fsig->params [0]->type == MONO_TYPE_I8)
4791 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4793 g_assert_not_reached ();
4794 MONO_INST_NEW (cfg, ins, opcode);
4796 ins->inst_i0 = args [0];
4797 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4800 if (fsig->params [0]->type == MONO_TYPE_I4)
4801 opcode = OP_ATOMIC_EXCHANGE_I4;
4802 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4803 (fsig->params [0]->type == MONO_TYPE_I) ||
4804 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4805 opcode = OP_ATOMIC_EXCHANGE_I8;
4809 MONO_INST_NEW (cfg, ins, opcode);
4811 ins->inst_i0 = args [0];
4812 ins->inst_i1 = args [1];
4813 } else if (strcmp (cmethod->name, "Add") == 0) {
4816 if (fsig->params [0]->type == MONO_TYPE_I4)
4817 opcode = OP_ATOMIC_ADD_NEW_I4;
4818 else if (fsig->params [0]->type == MONO_TYPE_I8)
4819 opcode = OP_ATOMIC_ADD_NEW_I8;
4821 g_assert_not_reached ();
4823 MONO_INST_NEW (cfg, ins, opcode);
4825 ins->inst_i0 = args [0];
4826 ins->inst_i1 = args [1];
4827 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4828 /* 64 bit reads are already atomic */
4829 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4830 ins->inst_i0 = args [0];
4838 mono_arch_print_tree (MonoInst *tree, int arity)
4843 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4847 if (appdomain_tls_offset == -1)
4850 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4851 ins->inst_offset = appdomain_tls_offset;
4855 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4859 if (thread_tls_offset == -1)
4862 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4863 ins->inst_offset = thread_tls_offset;