2 * mini-ia64.c: IA64 backend for the Mono code generator
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2003 Ximian, Inc.
15 #ifdef __INTEL_COMPILER
16 #include <ia64intrin.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/utils/mono-math.h>
26 #include "mini-ia64.h"
30 static gint appdomain_tls_offset = -1;
31 static gint thread_tls_offset = -1;
33 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
35 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
38 * IA64 register usage:
39 * - local registers are used for global register allocation
40 * - r8..r11, r14..r30 is used for local register allocation
41 * - r31 is a scratch register used within opcode implementations
42 * - FIXME: Use out registers as well
43 * - the first three locals are used for saving ar.pfst, b0, and sp
44 * - compare instructions allways set p6 and p7
48 * There are a lot of places where generated code is disassembled/patched.
49 * The automatic bundling of instructions done by the code generation macros
50 * could complicate things, so it is best to call
51 * ia64_codegen_set_one_ins_per_bundle () at those places.
54 #define ARGS_OFFSET 16
56 #define GP_SCRATCH_REG 31
57 #define GP_SCRATCH_REG2 30
58 #define FP_SCRATCH_REG 32
59 #define FP_SCRATCH_REG2 33
61 #define LOOP_ALIGNMENT 8
62 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
64 #define NOT_IMPLEMENTED g_assert_not_reached ()
66 static const char* gregs [] = {
67 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
68 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
69 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
70 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
71 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
72 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
73 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
74 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
75 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
76 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
77 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
78 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
79 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
83 mono_arch_regname (int reg)
91 static const char* fregs [] = {
92 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
93 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
94 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
95 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
96 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
97 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
98 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
99 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
100 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
101 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
102 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
103 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
104 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
108 mono_arch_fregname (int reg)
116 G_GNUC_UNUSED static void
121 G_GNUC_UNUSED static gboolean
124 static int count = 0;
127 if (count == atoi (getenv ("COUNT"))) {
131 if (count > atoi (getenv ("COUNT"))) {
139 debug_ins_sched (void)
142 return debug_count ();
152 return debug_count ();
159 ia64_patch (unsigned char* code, gpointer target);
165 ArgValuetypeAddrInIReg,
183 /* Only if storage == ArgAggregate */
193 gboolean need_stack_align;
199 #define DEBUG(a) if (cfg->verbose_level > 1) a
201 #define NEW_ICONST(cfg,dest,val) do { \
202 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
203 (dest)->opcode = OP_ICONST; \
204 (dest)->inst_c0 = (val); \
205 (dest)->type = STACK_I4; \
211 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
213 ainfo->offset = *stack_size;
215 if (*gr >= PARAM_REGS) {
216 ainfo->storage = ArgOnStack;
217 (*stack_size) += sizeof (gpointer);
220 ainfo->storage = ArgInIReg;
226 #define FLOAT_PARAM_REGS 8
229 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
231 ainfo->offset = *stack_size;
233 if (*gr >= PARAM_REGS) {
234 ainfo->storage = ArgOnStack;
235 (*stack_size) += sizeof (gpointer);
238 ainfo->storage = ArgInFloatReg;
239 ainfo->reg = 8 + *fr;
246 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
248 guint32 *gr, guint32 *fr, guint32 *stack_size)
252 MonoMarshalType *info;
253 gboolean is_hfa = TRUE;
254 guint32 hfa_type = 0;
256 klass = mono_class_from_mono_type (type);
257 if (type->type == MONO_TYPE_TYPEDBYREF)
258 size = 3 * sizeof (gpointer);
259 else if (sig->pinvoke)
260 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
262 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
264 if (!sig->pinvoke || (size == 0)) {
265 /* Allways pass in memory */
266 ainfo->offset = *stack_size;
267 *stack_size += ALIGN_TO (size, 8);
268 ainfo->storage = ArgOnStack;
273 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
274 info = mono_marshal_load_type_info (klass);
276 for (i = 0; i < info->num_fields; ++i) {
277 guint32 ftype = info->fields [i].field->type->type;
278 if (!(info->fields [i].field->type->byref) &&
279 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
282 else if (hfa_type != ftype)
291 ainfo->storage = ArgAggregate;
292 ainfo->atype = AggregateNormal;
295 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
297 if (info->num_fields <= 8) {
299 ainfo->nregs = info->num_fields;
300 ainfo->nslots = ainfo->nregs;
306 if ((*fr) + info->num_fields > 8)
309 ainfo->reg = 8 + (*fr);
310 ainfo->nregs = info->num_fields;
311 ainfo->nslots = ainfo->nregs;
312 (*fr) += info->num_fields;
317 /* This also handles returning of TypedByRef used by some icalls */
320 ainfo->reg = IA64_R8;
321 ainfo->nregs = (size + 7) / 8;
322 ainfo->nslots = ainfo->nregs;
329 ainfo->offset = *stack_size;
330 ainfo->nslots = (size + 7) / 8;
332 if (((*gr) + ainfo->nslots) <= 8) {
333 /* Fits entirely in registers */
334 ainfo->nregs = ainfo->nslots;
335 (*gr) += ainfo->nregs;
339 ainfo->nregs = 8 - (*gr);
341 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
347 * Obtain information about a call according to the calling convention.
348 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
349 * Gude" document for more information.
352 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
356 int n = sig->hasthis + sig->param_count;
357 guint32 stack_size = 0;
360 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
367 ret_type = mono_type_get_underlying_type (sig->ret);
368 switch (ret_type->type) {
369 case MONO_TYPE_BOOLEAN:
380 case MONO_TYPE_FNPTR:
381 case MONO_TYPE_CLASS:
382 case MONO_TYPE_OBJECT:
383 case MONO_TYPE_SZARRAY:
384 case MONO_TYPE_ARRAY:
385 case MONO_TYPE_STRING:
386 cinfo->ret.storage = ArgInIReg;
387 cinfo->ret.reg = IA64_R8;
391 cinfo->ret.storage = ArgInIReg;
392 cinfo->ret.reg = IA64_R8;
396 cinfo->ret.storage = ArgInFloatReg;
399 case MONO_TYPE_GENERICINST:
400 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
401 cinfo->ret.storage = ArgInIReg;
402 cinfo->ret.reg = IA64_R8;
406 case MONO_TYPE_VALUETYPE:
407 case MONO_TYPE_TYPEDBYREF: {
408 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
410 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
411 if (cinfo->ret.storage == ArgOnStack)
412 /* The caller passes the address where the value is stored */
413 add_general (&gr, &stack_size, &cinfo->ret);
414 if (cinfo->ret.storage == ArgInIReg)
415 cinfo->ret.storage = ArgValuetypeAddrInIReg;
419 cinfo->ret.storage = ArgNone;
422 g_error ("Can't handle as return value 0x%x", sig->ret->type);
428 add_general (&gr, &stack_size, cinfo->args + 0);
430 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
432 fr = FLOAT_PARAM_REGS;
434 /* Emit the signature cookie just before the implicit arguments */
435 add_general (&gr, &stack_size, &cinfo->sig_cookie);
438 for (i = 0; i < sig->param_count; ++i) {
439 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
442 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
443 /* We allways pass the sig cookie on the stack for simplicity */
445 * Prevent implicit arguments + the sig cookie from being passed
449 fr = FLOAT_PARAM_REGS;
451 /* Emit the signature cookie just before the implicit arguments */
452 add_general (&gr, &stack_size, &cinfo->sig_cookie);
455 if (sig->params [i]->byref) {
456 add_general (&gr, &stack_size, ainfo);
459 ptype = mono_type_get_underlying_type (sig->params [i]);
460 switch (ptype->type) {
461 case MONO_TYPE_BOOLEAN:
464 add_general (&gr, &stack_size, ainfo);
469 add_general (&gr, &stack_size, ainfo);
473 add_general (&gr, &stack_size, ainfo);
478 case MONO_TYPE_FNPTR:
479 case MONO_TYPE_CLASS:
480 case MONO_TYPE_OBJECT:
481 case MONO_TYPE_STRING:
482 case MONO_TYPE_SZARRAY:
483 case MONO_TYPE_ARRAY:
484 add_general (&gr, &stack_size, ainfo);
486 case MONO_TYPE_GENERICINST:
487 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
488 add_general (&gr, &stack_size, ainfo);
492 case MONO_TYPE_VALUETYPE:
493 case MONO_TYPE_TYPEDBYREF:
495 /* We allways pass valuetypes on the stack */
496 add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
500 add_general (&gr, &stack_size, ainfo);
503 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
506 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
509 g_assert_not_reached ();
513 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
515 fr = FLOAT_PARAM_REGS;
517 /* Emit the signature cookie just before the implicit arguments */
518 add_general (&gr, &stack_size, &cinfo->sig_cookie);
521 cinfo->stack_usage = stack_size;
522 cinfo->reg_usage = gr;
523 cinfo->freg_usage = fr;
528 * mono_arch_get_argument_info:
529 * @csig: a method signature
530 * @param_count: the number of parameters to consider
531 * @arg_info: an array to store the result infos
533 * Gathers information on parameters such as size, alignment and
534 * padding. arg_info should be large enought to hold param_count + 1 entries.
536 * Returns the size of the argument area on the stack.
539 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
542 CallInfo *cinfo = get_call_info (NULL, csig, FALSE);
543 guint32 args_size = cinfo->stack_usage;
545 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
547 arg_info [0].offset = 0;
550 for (k = 0; k < param_count; k++) {
551 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
553 arg_info [k + 1].size = 0;
562 * Initialize the cpu to execute managed code.
565 mono_arch_cpu_init (void)
570 * Initialize architecture specific code.
573 mono_arch_init (void)
578 * Cleanup architecture specific code.
581 mono_arch_cleanup (void)
586 * This function returns the optimizations supported on this cpu.
589 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
597 mono_arch_break (void)
602 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
606 MonoMethodSignature *sig;
607 MonoMethodHeader *header;
610 header = mono_method_get_header (cfg->method);
612 sig = mono_method_signature (cfg->method);
614 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
616 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
617 MonoInst *ins = cfg->args [i];
619 ArgInfo *ainfo = &cinfo->args [i];
621 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
624 if (ainfo->storage == ArgInIReg) {
625 /* The input registers are non-volatile */
626 ins->opcode = OP_REGVAR;
627 ins->dreg = 32 + ainfo->reg;
631 for (i = 0; i < cfg->num_varinfo; i++) {
632 MonoInst *ins = cfg->varinfo [i];
633 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
636 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
639 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
640 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
643 if (mono_is_regsize_var (ins->inst_vtype)) {
644 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
645 g_assert (i == vmv->idx);
646 vars = g_list_prepend (vars, vmv);
650 vars = mono_varlist_sort (cfg, vars, 0);
656 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
659 guint32 reserved_regs;
660 MonoMethodHeader *header;
662 if (cfg->arch.reg_local0 > 0)
666 cinfo = get_call_info (cfg->generic_sharing_context, mono_method_signature (cfg->method), FALSE);
668 header = mono_method_get_header (cfg->method);
670 /* Some registers are reserved for use by the prolog/epilog */
671 reserved_regs = header->num_clauses ? 4 : 3;
673 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
674 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
675 /* One registers is needed by instrument_epilog to save the return value */
677 if (cinfo->reg_usage < 2)
678 /* Number of arguments passed to function call in instrument_prolog */
679 cinfo->reg_usage = 2;
682 cfg->arch.reg_in0 = 32;
683 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
684 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
686 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
687 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
688 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
691 * Frames without handlers save sp to fp, frames with handlers save it into
692 * a dedicated register.
694 if (header->num_clauses)
695 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
697 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
699 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
700 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
701 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
705 * Need to allocate at least 2 out register for use by OP_THROW / the system
706 * exception throwing code.
708 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
714 mono_arch_get_global_int_regs (MonoCompile *cfg)
719 mono_ia64_alloc_stacked_registers (cfg);
721 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
724 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
731 * mono_arch_regalloc_cost:
733 * Return the cost, in number of memory references, of the action of
734 * allocating the variable VMV into a register during global register
738 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
740 /* FIXME: Increase costs linearly to avoid using all local registers */
746 mono_arch_allocate_vars (MonoCompile *cfg)
748 MonoMethodSignature *sig;
749 MonoMethodHeader *header;
752 guint32 locals_stack_size, locals_stack_align;
756 header = mono_method_get_header (cfg->method);
758 sig = mono_method_signature (cfg->method);
760 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
763 * Determine whenever the frame pointer can be eliminated.
764 * FIXME: Remove some of the restrictions.
766 cfg->arch.omit_fp = TRUE;
768 if (!debug_omit_fp ())
769 cfg->arch.omit_fp = FALSE;
771 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
772 cfg->arch.omit_fp = FALSE;
773 if (header->num_clauses)
774 cfg->arch.omit_fp = FALSE;
776 cfg->arch.omit_fp = FALSE;
777 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
778 ArgInfo *ainfo = &cinfo->args [i];
780 if (ainfo->storage == ArgOnStack) {
782 * The stack offset can only be determined when the frame
785 cfg->arch.omit_fp = FALSE;
789 mono_ia64_alloc_stacked_registers (cfg);
792 * We use the ABI calling conventions for managed code as well.
793 * Exception: valuetypes are never passed or returned in registers.
796 if (cfg->arch.omit_fp) {
797 cfg->frame_reg = IA64_SP;
798 offset = ARGS_OFFSET;
801 /* Locals are allocated backwards from %fp */
802 cfg->frame_reg = cfg->arch.reg_fp;
806 if (cfg->method->save_lmf) {
810 if (sig->ret->type != MONO_TYPE_VOID) {
811 switch (cinfo->ret.storage) {
813 cfg->ret->opcode = OP_REGVAR;
814 cfg->ret->inst_c0 = cinfo->ret.reg;
817 cfg->ret->opcode = OP_REGVAR;
818 cfg->ret->inst_c0 = cinfo->ret.reg;
820 case ArgValuetypeAddrInIReg:
821 cfg->ret->opcode = OP_REGVAR;
822 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
825 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
826 if (cfg->arch.omit_fp)
827 g_assert_not_reached ();
828 offset = ALIGN_TO (offset, 8);
829 offset += cinfo->ret.nslots * 8;
830 cfg->ret->opcode = OP_REGOFFSET;
831 cfg->ret->inst_basereg = cfg->frame_reg;
832 cfg->ret->inst_offset = - offset;
835 g_assert_not_reached ();
837 cfg->ret->dreg = cfg->ret->inst_c0;
840 /* Allocate locals */
841 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
842 if (locals_stack_align) {
843 offset = ALIGN_TO (offset, locals_stack_align);
845 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
846 if (offsets [i] != -1) {
847 MonoInst *inst = cfg->varinfo [i];
848 inst->opcode = OP_REGOFFSET;
849 inst->inst_basereg = cfg->frame_reg;
850 if (cfg->arch.omit_fp)
851 inst->inst_offset = (offset + offsets [i]);
853 inst->inst_offset = - (offset + offsets [i]);
854 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
857 offset += locals_stack_size;
859 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
860 if (cfg->arch.omit_fp)
861 g_assert_not_reached ();
862 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
863 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
866 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
867 inst = cfg->args [i];
868 if (inst->opcode != OP_REGVAR) {
869 ArgInfo *ainfo = &cinfo->args [i];
870 gboolean inreg = TRUE;
873 if (sig->hasthis && (i == 0))
874 arg_type = &mono_defaults.object_class->byval_arg;
876 arg_type = sig->params [i - sig->hasthis];
878 /* FIXME: VOLATILE is only set if the liveness pass runs */
879 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
882 inst->opcode = OP_REGOFFSET;
884 switch (ainfo->storage) {
886 inst->opcode = OP_REGVAR;
887 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
891 * Since float regs are volatile, we save the arguments to
892 * the stack in the prolog.
897 if (cfg->arch.omit_fp)
898 g_assert_not_reached ();
899 inst->opcode = OP_REGOFFSET;
900 inst->inst_basereg = cfg->frame_reg;
901 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
910 if (!inreg && (ainfo->storage != ArgOnStack)) {
911 inst->opcode = OP_REGOFFSET;
912 inst->inst_basereg = cfg->frame_reg;
913 /* These arguments are saved to the stack in the prolog */
914 switch (ainfo->storage) {
916 if (ainfo->atype == AggregateSingleHFA)
917 offset += ainfo->nslots * 4;
919 offset += ainfo->nslots * 8;
922 offset += sizeof (gpointer);
925 offset = ALIGN_TO (offset, sizeof (gpointer));
926 if (cfg->arch.omit_fp)
927 inst->inst_offset = offset;
929 inst->inst_offset = - offset;
934 if (cfg->arch.omit_fp && offset == 16)
937 cfg->stack_offset = offset;
943 mono_arch_create_vars (MonoCompile *cfg)
945 MonoMethodSignature *sig;
948 sig = mono_method_signature (cfg->method);
950 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
952 if (cinfo->ret.storage == ArgAggregate)
953 cfg->ret_var_is_local = TRUE;
959 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
963 arg->opcode = OP_OUTARG_REG;
964 arg->inst_left = tree;
965 arg->inst_right = (MonoInst*)call;
966 arg->backend.reg3 = reg;
967 call->used_iregs |= 1 << reg;
970 arg->opcode = OP_OUTARG_FREG;
971 arg->inst_left = tree;
972 arg->inst_right = (MonoInst*)call;
973 arg->backend.reg3 = reg;
974 call->used_fregs |= 1 << reg;
977 g_assert_not_reached ();
982 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
985 MonoMethodSignature *tmp_sig;
988 /* FIXME: Add support for signature tokens to AOT */
989 cfg->disable_aot = TRUE;
991 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
994 * mono_ArgIterator_Setup assumes the signature cookie is
995 * passed first and all the arguments which were before it are
996 * passed on the stack after the signature. So compensate by
997 * passing a different signature.
999 tmp_sig = mono_metadata_signature_dup (call->signature);
1000 tmp_sig->param_count -= call->signature->sentinelpos;
1001 tmp_sig->sentinelpos = 0;
1002 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1004 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1005 sig_arg->inst_p0 = tmp_sig;
1007 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1008 arg->inst_left = sig_arg;
1009 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1010 arg->type = STACK_PTR;
1012 /* prepend, so they get reversed */
1013 arg->next = call->out_args;
1014 call->out_args = arg;
1018 * take the arguments and generate the arch-specific
1019 * instructions to properly call the function in call.
1020 * This includes pushing, moving arguments to the right register
1024 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1027 MonoMethodSignature *sig;
1028 int i, n, stack_size;
1034 mono_ia64_alloc_stacked_registers (cfg);
1036 sig = call->signature;
1037 n = sig->param_count + sig->hasthis;
1039 cinfo = get_call_info (cfg->generic_sharing_context, sig, sig->pinvoke);
1041 if (cinfo->ret.storage == ArgAggregate) {
1042 /* The code in emit_this_vret_arg needs a local */
1043 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1044 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1047 for (i = 0; i < n; ++i) {
1048 ainfo = cinfo->args + i;
1050 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1051 /* Emit the signature cookie just before the implicit arguments */
1052 emit_sig_cookie (cfg, call, cinfo);
1055 if (is_virtual && i == 0) {
1056 /* the argument will be attached to the call instruction */
1057 in = call->args [i];
1061 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1062 in = call->args [i];
1063 arg->cil_code = in->cil_code;
1064 arg->inst_left = in;
1065 arg->type = in->type;
1066 /* prepend, so they get reversed */
1067 arg->next = call->out_args;
1068 call->out_args = arg;
1070 if (sig->hasthis && (i == 0))
1071 arg_type = &mono_defaults.object_class->byval_arg;
1073 arg_type = sig->params [i - sig->hasthis];
1075 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1076 MonoInst *stack_addr;
1080 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1081 size = sizeof (MonoTypedRef);
1082 align = sizeof (gpointer);
1086 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1089 * Other backends use mini_type_stack_size (), but that
1090 * aligns the size to 8, which is larger than the size of
1091 * the source, leading to reads of invalid memory if the
1092 * source is at the end of address space.
1094 size = mono_class_value_size (in->klass, &align);
1097 if (ainfo->storage == ArgAggregate) {
1098 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1101 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1104 * Part of the structure is passed in registers.
1106 for (j = 0; j < ainfo->nregs; ++j) {
1107 int offset, load_op, dest_reg, arg_storage;
1109 slot = ainfo->reg + j;
1111 if (ainfo->atype == AggregateSingleHFA) {
1112 load_op = CEE_LDIND_R4;
1114 dest_reg = ainfo->reg + j;
1115 arg_storage = ArgInFloatReg;
1116 } else if (ainfo->atype == AggregateDoubleHFA) {
1117 load_op = CEE_LDIND_R8;
1119 dest_reg = ainfo->reg + j;
1120 arg_storage = ArgInFloatReg;
1122 load_op = CEE_LDIND_I;
1124 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1125 arg_storage = ArgInIReg;
1128 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1129 load->ssa_op = MONO_SSA_LOAD;
1130 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1132 NEW_ICONST (cfg, offset_ins, offset);
1133 MONO_INST_NEW (cfg, load2, CEE_ADD);
1134 load2->inst_left = load;
1135 load2->inst_right = offset_ins;
1137 MONO_INST_NEW (cfg, load, load_op);
1138 load->inst_left = load2;
1143 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1144 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1145 if (set_reg != call->out_args) {
1146 set_reg->next = call->out_args;
1147 call->out_args = set_reg;
1152 * Part of the structure is passed on the stack.
1154 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1157 slot = ainfo->reg + j;
1159 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1160 load->ssa_op = MONO_SSA_LOAD;
1161 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1163 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1164 MONO_INST_NEW (cfg, load2, CEE_ADD);
1165 load2->inst_left = load;
1166 load2->inst_right = offset_ins;
1168 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1169 load->inst_left = load2;
1174 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1175 outarg->inst_left = load;
1176 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1178 if (outarg != call->out_args) {
1179 outarg->next = call->out_args;
1180 call->out_args = outarg;
1184 /* Trees can't be shared so make a copy */
1185 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1186 arg->cil_code = in->cil_code;
1187 arg->ssa_op = MONO_SSA_STORE;
1188 arg->inst_left = vtaddr;
1189 arg->inst_right = in;
1190 arg->type = in->type;
1192 /* prepend, so they get reversed */
1193 arg->next = call->out_args;
1194 call->out_args = arg;
1197 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1198 stack_addr->inst_basereg = IA64_SP;
1199 stack_addr->inst_offset = 16 + ainfo->offset;
1200 stack_addr->inst_imm = size;
1202 arg->opcode = OP_OUTARG_VT;
1203 arg->inst_right = stack_addr;
1207 switch (ainfo->storage) {
1209 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1212 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1215 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1216 arg->opcode = OP_OUTARG_R4;
1219 arg->opcode = OP_OUTARG;
1220 arg->inst_imm = 16 + ainfo->offset;
1223 g_assert_not_reached ();
1229 /* Handle the case where there are no implicit arguments */
1230 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1231 emit_sig_cookie (cfg, call, cinfo);
1234 call->stack_usage = cinfo->stack_usage;
1235 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1236 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1237 cfg->flags |= MONO_CFG_HAS_CALLS;
1245 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1247 MonoInst *ins, *last_ins = NULL;
1251 switch (ins->opcode) {
1259 if (ins->dreg == ins->sreg1) {
1261 last_ins->next = ins->next;
1268 * OP_MOVE sreg, dreg
1269 * OP_MOVE dreg, sreg
1271 if (last_ins && last_ins->opcode == OP_MOVE &&
1272 ins->sreg1 == last_ins->dreg &&
1273 ins->dreg == last_ins->sreg1) {
1274 last_ins->next = ins->next;
1281 /* remove unnecessary multiplication with 1 */
1282 if (ins->inst_imm == 1) {
1283 if (ins->dreg != ins->sreg1) {
1284 ins->opcode = OP_MOVE;
1286 last_ins->next = ins->next;
1297 bb->last_ins = last_ins;
1300 int cond_to_ia64_cmp [][3] = {
1301 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1302 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1303 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1304 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1305 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1306 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1307 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1308 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1309 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1310 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1314 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1316 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1319 int cond_to_ia64_cmp_imm [][3] = {
1320 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1321 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1322 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1323 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1324 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1325 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1326 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1327 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1328 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1329 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1333 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1335 /* The condition needs to be reversed */
1336 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1340 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1344 bb->code = to_insert;
1345 to_insert->next = ins;
1348 to_insert->next = ins->next;
1349 ins->next = to_insert;
1353 #define NEW_INS(cfg,dest,op) do { \
1354 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1355 (dest)->opcode = (op); \
1356 insert_after_ins (bb, last_ins, (dest)); \
1357 last_ins = (dest); \
1361 * mono_arch_lowering_pass:
1363 * Converts complex opcodes into simpler ones so that each IR instruction
1364 * corresponds to one machine instruction.
1367 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1369 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1372 if (bb->max_vreg > cfg->rs->next_vreg)
1373 cfg->rs->next_vreg = bb->max_vreg;
1376 switch (ins->opcode) {
1377 case OP_STOREI1_MEMBASE_IMM:
1378 case OP_STOREI2_MEMBASE_IMM:
1379 case OP_STOREI4_MEMBASE_IMM:
1380 case OP_STOREI8_MEMBASE_IMM:
1381 case OP_STORE_MEMBASE_IMM:
1382 /* There are no store_membase instructions on ia64 */
1383 if (ins->inst_offset == 0) {
1385 } else if (ia64_is_imm14 (ins->inst_offset)) {
1386 NEW_INS (cfg, temp2, OP_ADD_IMM);
1387 temp2->sreg1 = ins->inst_destbasereg;
1388 temp2->inst_imm = ins->inst_offset;
1389 temp2->dreg = mono_regstate_next_int (cfg->rs);
1392 NEW_INS (cfg, temp, OP_I8CONST);
1393 temp->inst_c0 = ins->inst_offset;
1394 temp->dreg = mono_regstate_next_int (cfg->rs);
1395 NEW_INS (cfg, temp2, CEE_ADD);
1396 temp2->sreg1 = ins->inst_destbasereg;
1397 temp2->sreg2 = temp->dreg;
1398 temp2->dreg = mono_regstate_next_int (cfg->rs);
1401 switch (ins->opcode) {
1402 case OP_STOREI1_MEMBASE_IMM:
1403 ins->opcode = OP_STOREI1_MEMBASE_REG;
1405 case OP_STOREI2_MEMBASE_IMM:
1406 ins->opcode = OP_STOREI2_MEMBASE_REG;
1408 case OP_STOREI4_MEMBASE_IMM:
1409 ins->opcode = OP_STOREI4_MEMBASE_REG;
1411 case OP_STOREI8_MEMBASE_IMM:
1412 case OP_STORE_MEMBASE_IMM:
1413 ins->opcode = OP_STOREI8_MEMBASE_REG;
1416 g_assert_not_reached ();
1419 if (ins->inst_imm == 0)
1420 ins->sreg1 = IA64_R0;
1422 NEW_INS (cfg, temp3, OP_I8CONST);
1423 temp3->inst_c0 = ins->inst_imm;
1424 temp3->dreg = mono_regstate_next_int (cfg->rs);
1425 ins->sreg1 = temp3->dreg;
1428 ins->inst_offset = 0;
1430 ins->inst_destbasereg = temp2->dreg;
1432 case OP_STOREI1_MEMBASE_REG:
1433 case OP_STOREI2_MEMBASE_REG:
1434 case OP_STOREI4_MEMBASE_REG:
1435 case OP_STOREI8_MEMBASE_REG:
1436 case OP_STORER4_MEMBASE_REG:
1437 case OP_STORER8_MEMBASE_REG:
1438 case OP_STORE_MEMBASE_REG:
1439 /* There are no store_membase instructions on ia64 */
1440 if (ins->inst_offset == 0) {
1443 else if (ia64_is_imm14 (ins->inst_offset)) {
1444 NEW_INS (cfg, temp2, OP_ADD_IMM);
1445 temp2->sreg1 = ins->inst_destbasereg;
1446 temp2->inst_imm = ins->inst_offset;
1447 temp2->dreg = mono_regstate_next_int (cfg->rs);
1450 NEW_INS (cfg, temp, OP_I8CONST);
1451 temp->inst_c0 = ins->inst_offset;
1452 temp->dreg = mono_regstate_next_int (cfg->rs);
1453 NEW_INS (cfg, temp2, CEE_ADD);
1454 temp2->sreg1 = ins->inst_destbasereg;
1455 temp2->sreg2 = temp->dreg;
1456 temp2->dreg = mono_regstate_next_int (cfg->rs);
1459 ins->inst_offset = 0;
1460 ins->inst_destbasereg = temp2->dreg;
1462 case OP_LOADI1_MEMBASE:
1463 case OP_LOADU1_MEMBASE:
1464 case OP_LOADI2_MEMBASE:
1465 case OP_LOADU2_MEMBASE:
1466 case OP_LOADI4_MEMBASE:
1467 case OP_LOADU4_MEMBASE:
1468 case OP_LOADI8_MEMBASE:
1469 case OP_LOAD_MEMBASE:
1470 case OP_LOADR4_MEMBASE:
1471 case OP_LOADR8_MEMBASE:
1472 case OP_ATOMIC_EXCHANGE_I4:
1473 case OP_ATOMIC_EXCHANGE_I8:
1474 case OP_ATOMIC_ADD_NEW_I4:
1475 case OP_ATOMIC_ADD_NEW_I8:
1476 case OP_ATOMIC_ADD_IMM_NEW_I4:
1477 case OP_ATOMIC_ADD_IMM_NEW_I8:
1478 /* There are no membase instructions on ia64 */
1479 if (ins->inst_offset == 0) {
1482 else if (ia64_is_imm14 (ins->inst_offset)) {
1483 NEW_INS (cfg, temp2, OP_ADD_IMM);
1484 temp2->sreg1 = ins->inst_basereg;
1485 temp2->inst_imm = ins->inst_offset;
1486 temp2->dreg = mono_regstate_next_int (cfg->rs);
1489 NEW_INS (cfg, temp, OP_I8CONST);
1490 temp->inst_c0 = ins->inst_offset;
1491 temp->dreg = mono_regstate_next_int (cfg->rs);
1492 NEW_INS (cfg, temp2, CEE_ADD);
1493 temp2->sreg1 = ins->inst_basereg;
1494 temp2->sreg2 = temp->dreg;
1495 temp2->dreg = mono_regstate_next_int (cfg->rs);
1498 ins->inst_offset = 0;
1499 ins->inst_basereg = temp2->dreg;
1514 case OP_ISHR_UN_IMM:
1515 case OP_LSHR_UN_IMM: {
1516 gboolean is_imm = FALSE;
1517 gboolean switched = FALSE;
1519 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1520 ins->opcode = OP_ZEXT_I1;
1524 switch (ins->opcode) {
1527 is_imm = ia64_is_imm14 (ins->inst_imm);
1531 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1533 /* A = B - IMM -> A = B + (-IMM) */
1534 ins->inst_imm = - ins->inst_imm;
1535 ins->opcode = OP_IADD_IMM;
1543 is_imm = ia64_is_imm8 (ins->inst_imm);
1552 case OP_ISHR_UN_IMM:
1553 case OP_LSHR_UN_IMM:
1554 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1562 ins->sreg2 = ins->sreg1;
1566 switch (ins->opcode) {
1568 ins->opcode = CEE_ADD;
1571 ins->opcode = OP_IADD;
1574 ins->opcode = OP_ISUB;
1577 ins->opcode = OP_IAND;
1580 ins->opcode = OP_IOR;
1583 ins->opcode = OP_IXOR;
1586 ins->opcode = OP_ISHL;
1589 ins->opcode = OP_ISHR;
1591 case OP_ISHR_UN_IMM:
1592 ins->opcode = OP_ISHR_UN;
1595 ins->opcode = CEE_AND;
1598 ins->opcode = OP_LSHL;
1601 ins->opcode = OP_LSHR;
1604 ins->opcode = OP_LSHL;
1607 ins->opcode = OP_LSHR;
1609 case OP_LSHR_UN_IMM:
1610 ins->opcode = OP_LSHR_UN;
1613 g_assert_not_reached ();
1616 if (ins->inst_imm == 0)
1617 ins->sreg2 = IA64_R0;
1619 NEW_INS (cfg, temp, OP_I8CONST);
1620 temp->inst_c0 = ins->inst_imm;
1621 temp->dreg = mono_regstate_next_int (cfg->rs);
1622 ins->sreg2 = temp->dreg;
1626 case OP_COMPARE_IMM:
1627 case OP_ICOMPARE_IMM: {
1628 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1633 * The compare_imm instructions have switched up arguments, and
1634 * some of them take an imm between -127 and 128.
1637 cond = mono_opcode_to_cond (next->opcode);
1638 if ((cond == CMP_LT) || (cond == CMP_GE))
1639 imm = ia64_is_imm8 (ins->inst_imm - 1);
1640 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1641 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1643 imm = ia64_is_imm8 (ins->inst_imm);
1646 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1647 ins->sreg2 = ins->sreg1;
1650 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1652 if (ins->inst_imm == 0)
1653 ins->sreg2 = IA64_R0;
1655 NEW_INS (cfg, temp, OP_I8CONST);
1656 temp->inst_c0 = ins->inst_imm;
1657 temp->dreg = mono_regstate_next_int (cfg->rs);
1658 ins->sreg2 = temp->dreg;
1662 switch (next->opcode) {
1683 next->opcode = OP_IA64_BR_COND;
1684 if (! (next->flags & MONO_INST_BRLABEL))
1685 next->inst_target_bb = next->inst_true_bb;
1687 case OP_COND_EXC_EQ:
1688 case OP_COND_EXC_GT:
1689 case OP_COND_EXC_LT:
1690 case OP_COND_EXC_GT_UN:
1691 case OP_COND_EXC_LE_UN:
1692 case OP_COND_EXC_NE_UN:
1693 case OP_COND_EXC_LT_UN:
1694 next->opcode = OP_IA64_COND_EXC;
1706 next->opcode = OP_IA64_CSET;
1709 printf ("%s\n", mono_inst_name (next->opcode));
1719 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1723 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1724 switch (next->opcode) {
1755 next->opcode = OP_IA64_BR_COND;
1756 if (! (next->flags & MONO_INST_BRLABEL))
1757 next->inst_target_bb = next->inst_true_bb;
1759 case OP_COND_EXC_LT:
1760 case OP_COND_EXC_GT:
1761 case OP_COND_EXC_GT_UN:
1762 case OP_COND_EXC_LE_UN:
1763 next->opcode = OP_IA64_COND_EXC;
1780 next->opcode = OP_IA64_CSET;
1783 printf ("%s\n", mono_inst_name (next->opcode));
1792 gboolean found = FALSE;
1793 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1795 /* First the easy cases */
1796 if (ins->inst_imm == 1) {
1797 ins->opcode = OP_MOVE;
1800 for (i = 1; i < 64; ++i)
1801 if (ins->inst_imm == (((gint64)1) << i)) {
1802 ins->opcode = shl_op;
1808 /* This could be optimized */
1811 for (i = 0; i < 64; ++i) {
1812 if (ins->inst_imm & (((gint64)1) << i)) {
1813 NEW_INS (cfg, temp, shl_op);
1814 temp->dreg = mono_regstate_next_int (cfg->rs);
1815 temp->sreg1 = ins->sreg1;
1819 sum_reg = temp->dreg;
1821 NEW_INS (cfg, temp2, CEE_ADD);
1822 temp2->dreg = mono_regstate_next_int (cfg->rs);
1823 temp2->sreg1 = sum_reg;
1824 temp2->sreg2 = temp->dreg;
1825 sum_reg = temp2->dreg;
1829 ins->opcode = OP_MOVE;
1830 ins->sreg1 = sum_reg;
1834 case CEE_CONV_OVF_U4:
1835 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1836 temp->sreg1 = ins->sreg1;
1837 temp->sreg2 = IA64_R0;
1839 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1840 temp->inst_p1 = (char*)"OverflowException";
1842 ins->opcode = OP_MOVE;
1844 case CEE_CONV_OVF_I4_UN:
1845 NEW_INS (cfg, temp, OP_ICONST);
1846 temp->inst_c0 = 0x7fffffff;
1847 temp->dreg = mono_regstate_next_int (cfg->rs);
1849 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1850 temp2->sreg1 = ins->sreg1;
1851 temp2->sreg2 = temp->dreg;
1853 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1854 temp->inst_p1 = (char*)"OverflowException";
1856 ins->opcode = OP_MOVE;
1858 case OP_FCONV_TO_I4:
1859 case OP_FCONV_TO_I2:
1860 case OP_FCONV_TO_U2:
1861 case OP_FCONV_TO_I1:
1862 case OP_FCONV_TO_U1:
1863 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1864 temp->sreg1 = ins->sreg1;
1865 temp->dreg = ins->dreg;
1867 switch (ins->opcode) {
1868 case OP_FCONV_TO_I4:
1869 ins->opcode = OP_SEXT_I4;
1871 case OP_FCONV_TO_I2:
1872 ins->opcode = OP_SEXT_I2;
1874 case OP_FCONV_TO_U2:
1875 ins->opcode = OP_ZEXT_I4;
1877 case OP_FCONV_TO_I1:
1878 ins->opcode = OP_SEXT_I1;
1880 case OP_FCONV_TO_U1:
1881 ins->opcode = OP_ZEXT_I1;
1884 g_assert_not_reached ();
1886 ins->sreg1 = ins->dreg;
1894 bb->last_ins = last_ins;
1896 bb->max_vreg = cfg->rs->next_vreg;
1900 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1905 mono_arch_lowering_pass (cfg, bb);
1907 mono_local_regalloc (cfg, bb);
1911 * emit_load_volatile_arguments:
1913 * Load volatile arguments from the stack to the original input registers.
1914 * Required before a tail call.
1916 static Ia64CodegenState
1917 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1919 MonoMethod *method = cfg->method;
1920 MonoMethodSignature *sig;
1925 /* FIXME: Generate intermediate code instead */
1927 sig = mono_method_signature (method);
1929 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1931 /* This is the opposite of the code in emit_prolog */
1932 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1933 ArgInfo *ainfo = cinfo->args + i;
1934 gint32 stack_offset;
1936 ins = cfg->args [i];
1938 if (sig->hasthis && (i == 0))
1939 arg_type = &mono_defaults.object_class->byval_arg;
1941 arg_type = sig->params [i - sig->hasthis];
1943 arg_type = mono_type_get_underlying_type (arg_type);
1945 stack_offset = ainfo->offset + ARGS_OFFSET;
1947 /* Save volatile arguments to the stack */
1948 if (ins->opcode != OP_REGVAR) {
1949 switch (ainfo->storage) {
1952 /* FIXME: big offsets */
1953 g_assert (ins->opcode == OP_REGOFFSET);
1954 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1955 if (arg_type->byref)
1956 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1958 switch (arg_type->type) {
1960 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1963 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1966 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1978 if (ins->opcode == OP_REGVAR) {
1979 /* Argument allocated to (non-volatile) register */
1980 switch (ainfo->storage) {
1982 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1983 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1986 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1987 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2000 static Ia64CodegenState
2001 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2006 /* Move return value to the target register */
2007 switch (ins->opcode) {
2009 case OP_VOIDCALL_REG:
2010 case OP_VOIDCALL_MEMBASE:
2014 case OP_CALL_MEMBASE:
2017 case OP_LCALL_MEMBASE:
2018 g_assert (ins->dreg == IA64_R8);
2022 case OP_FCALL_MEMBASE:
2023 g_assert (ins->dreg == 8);
2027 case OP_VCALL_MEMBASE: {
2030 cinfo = get_call_info (cfg->generic_sharing_context, ((MonoCallInst*)ins)->signature, FALSE);
2031 storage = cinfo->ret.storage;
2033 if (storage == ArgAggregate) {
2034 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2036 /* Load address of stack space allocated for the return value */
2037 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2038 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2039 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2041 for (i = 0; i < cinfo->ret.nregs; ++i) {
2042 switch (cinfo->ret.atype) {
2043 case AggregateNormal:
2044 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2046 case AggregateSingleHFA:
2047 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2049 case AggregateDoubleHFA:
2050 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2053 g_assert_not_reached ();
2061 g_assert_not_reached ();
2067 #define add_patch_info(cfg,code,patch_type,data) do { \
2068 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2071 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2072 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2074 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2076 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2077 ia64_br_cond_pred (code, (predicate), 0); \
2080 static Ia64CodegenState
2081 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2083 add_patch_info (cfg, code, patch_type, data);
2085 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2087 /* mono_arch_patch_callsite will patch this */
2088 /* mono_arch_nullify_class_init_trampoline will patch this */
2089 ia64_movl (code, GP_SCRATCH_REG, 0);
2090 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2091 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2092 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2093 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2096 /* Can't use a direct call since the displacement might be too small */
2097 /* mono_arch_patch_callsite will patch this */
2098 ia64_movl (code, GP_SCRATCH_REG, 0);
2099 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2100 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2106 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2109 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2114 Ia64CodegenState code;
2115 guint8 *code_start = cfg->native_code + cfg->code_len;
2116 MonoInst *last_ins = NULL;
2117 guint last_offset = 0;
2120 if (cfg->opt & MONO_OPT_PEEPHOLE)
2121 peephole_pass (cfg, bb);
2123 if (cfg->opt & MONO_OPT_LOOP) {
2127 if (cfg->verbose_level > 2)
2128 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2130 cpos = bb->max_offset;
2132 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2136 offset = code_start - cfg->native_code;
2138 ia64_codegen_init (code, code_start);
2141 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2147 offset = code.buf - cfg->native_code;
2149 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2151 while (offset + max_len + 16 > cfg->code_size) {
2152 ia64_codegen_close (code);
2154 offset = code.buf - cfg->native_code;
2156 cfg->code_size *= 2;
2157 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2158 code_start = cfg->native_code + offset;
2159 mono_jit_stats.code_reallocs++;
2161 ia64_codegen_init (code, code_start);
2164 mono_debug_record_line_number (cfg, ins, offset);
2166 switch (ins->opcode) {
2169 if (ia64_is_imm14 (ins->inst_c0))
2170 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2172 ia64_movl (code, ins->dreg, ins->inst_c0);
2175 ia64_mov (code, ins->dreg, ins->sreg1);
2178 case OP_IA64_BR_COND: {
2180 if (ins->opcode == OP_IA64_BR_COND)
2182 if (ins->flags & MONO_INST_BRLABEL) {
2183 if (ins->inst_i0->inst_c0) {
2186 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2187 ia64_br_cond_pred (code, pred, 0);
2190 if (ins->inst_target_bb->native_offset) {
2191 guint8 *pos = code.buf + code.nins;
2193 ia64_br_cond_pred (code, pred, 0);
2194 ia64_begin_bundle (code);
2195 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2197 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2198 ia64_br_cond_pred (code, pred, 0);
2204 ia64_begin_bundle (code);
2205 ins->inst_c0 = code.buf - cfg->native_code;
2210 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2211 ia64_br_cond_reg (code, IA64_B6);
2215 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2219 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2223 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2227 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2231 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2235 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2238 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2242 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2245 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2246 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2250 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2253 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2257 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2260 /* p6 and p7 is set if there is signed/unsigned overflow */
2262 /* Set p8-p9 == (sreg2 > 0) */
2263 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2265 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2267 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2268 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2269 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2270 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2272 /* res <u sreg1 => unsigned overflow */
2273 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2275 /* FIXME: Predicate this since this is a side effect */
2276 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2279 /* p6 and p7 is set if there is signed/unsigned overflow */
2281 /* Set p8-p9 == (sreg2 > 0) */
2282 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2284 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2286 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2287 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2288 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2289 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2291 /* sreg1 <u sreg2 => unsigned overflow */
2292 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2294 /* FIXME: Predicate this since this is a side effect */
2295 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2298 /* Same as OP_IADDCC */
2299 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2301 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2303 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2304 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2306 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2308 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2311 /* Same as OP_ISUBCC */
2313 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2315 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2317 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2318 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2320 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2322 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2326 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2330 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2333 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2336 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2341 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2346 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2348 case OP_ISHR_UN_IMM:
2349 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2350 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2352 case OP_LSHR_UN_IMM:
2353 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2356 /* Based on gcc code */
2357 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2358 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2359 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2360 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2363 case OP_STOREI1_MEMBASE_REG:
2364 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2366 case OP_STOREI2_MEMBASE_REG:
2367 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2369 case OP_STOREI4_MEMBASE_REG:
2370 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2372 case OP_STOREI8_MEMBASE_REG:
2373 case OP_STORE_MEMBASE_REG:
2374 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2377 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2378 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2380 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2381 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2383 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2384 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2386 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2387 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2390 case OP_LOADU1_MEMBASE:
2391 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2393 case OP_LOADU2_MEMBASE:
2394 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2396 case OP_LOADU4_MEMBASE:
2397 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2399 case OP_LOADI1_MEMBASE:
2400 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2401 ia64_sxt1 (code, ins->dreg, ins->dreg);
2403 case OP_LOADI2_MEMBASE:
2404 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2405 ia64_sxt2 (code, ins->dreg, ins->dreg);
2407 case OP_LOADI4_MEMBASE:
2408 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2409 ia64_sxt4 (code, ins->dreg, ins->dreg);
2411 case OP_LOAD_MEMBASE:
2412 case OP_LOADI8_MEMBASE:
2413 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2416 case OP_IA64_LOADU1_MEMBASE_INC:
2417 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2419 case OP_IA64_LOADU2_MEMBASE_INC:
2420 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2422 case OP_IA64_LOADU4_MEMBASE_INC:
2423 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2425 case OP_IA64_LOADI8_MEMBASE_INC:
2426 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2430 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2433 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2436 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2439 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2442 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2445 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2448 /* Compare opcodes */
2449 case OP_IA64_CMP4_EQ:
2450 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2452 case OP_IA64_CMP4_NE:
2453 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2455 case OP_IA64_CMP4_LE:
2456 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2458 case OP_IA64_CMP4_LT:
2459 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2461 case OP_IA64_CMP4_GE:
2462 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2464 case OP_IA64_CMP4_GT:
2465 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2467 case OP_IA64_CMP4_LT_UN:
2468 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2470 case OP_IA64_CMP4_LE_UN:
2471 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2473 case OP_IA64_CMP4_GT_UN:
2474 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2476 case OP_IA64_CMP4_GE_UN:
2477 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2479 case OP_IA64_CMP_EQ:
2480 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2482 case OP_IA64_CMP_NE:
2483 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2485 case OP_IA64_CMP_LE:
2486 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2488 case OP_IA64_CMP_LT:
2489 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2491 case OP_IA64_CMP_GE:
2492 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2494 case OP_IA64_CMP_GT:
2495 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2497 case OP_IA64_CMP_GT_UN:
2498 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2500 case OP_IA64_CMP_LT_UN:
2501 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2503 case OP_IA64_CMP_GE_UN:
2504 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2506 case OP_IA64_CMP_LE_UN:
2507 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2509 case OP_IA64_CMP4_EQ_IMM:
2510 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2512 case OP_IA64_CMP4_NE_IMM:
2513 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2515 case OP_IA64_CMP4_LE_IMM:
2516 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2518 case OP_IA64_CMP4_LT_IMM:
2519 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2521 case OP_IA64_CMP4_GE_IMM:
2522 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2524 case OP_IA64_CMP4_GT_IMM:
2525 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2527 case OP_IA64_CMP4_LT_UN_IMM:
2528 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2530 case OP_IA64_CMP4_LE_UN_IMM:
2531 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2533 case OP_IA64_CMP4_GT_UN_IMM:
2534 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2536 case OP_IA64_CMP4_GE_UN_IMM:
2537 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2539 case OP_IA64_CMP_EQ_IMM:
2540 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2542 case OP_IA64_CMP_NE_IMM:
2543 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2545 case OP_IA64_CMP_LE_IMM:
2546 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2548 case OP_IA64_CMP_LT_IMM:
2549 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2551 case OP_IA64_CMP_GE_IMM:
2552 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2554 case OP_IA64_CMP_GT_IMM:
2555 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2557 case OP_IA64_CMP_GT_UN_IMM:
2558 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2560 case OP_IA64_CMP_LT_UN_IMM:
2561 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2563 case OP_IA64_CMP_GE_UN_IMM:
2564 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2566 case OP_IA64_CMP_LE_UN_IMM:
2567 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2569 case OP_IA64_FCMP_EQ:
2570 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2572 case OP_IA64_FCMP_NE:
2573 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2575 case OP_IA64_FCMP_LT:
2576 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2578 case OP_IA64_FCMP_GT:
2579 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2581 case OP_IA64_FCMP_LE:
2582 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2584 case OP_IA64_FCMP_GE:
2585 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2587 case OP_IA64_FCMP_GT_UN:
2588 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2589 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2591 case OP_IA64_FCMP_LT_UN:
2592 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2593 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2595 case OP_IA64_FCMP_GE_UN:
2596 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2597 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2599 case OP_IA64_FCMP_LE_UN:
2600 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2601 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2604 case OP_COND_EXC_IOV:
2605 case OP_COND_EXC_OV:
2606 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2608 case OP_COND_EXC_IC:
2610 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2612 case OP_IA64_COND_EXC:
2613 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2616 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2617 ia64_no_stop (code);
2618 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2621 /* FIXME: Is this needed ? */
2622 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2625 /* FIXME: Is this needed ? */
2626 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2629 /* FIXME: Is this needed ? */
2630 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2633 /* FIXME: Is this needed */
2634 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2637 /* FIXME: Is this needed */
2638 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2641 /* FIXME: Is this needed */
2642 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2646 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2650 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2657 double d = *(double *)ins->inst_p0;
2659 if ((d == 0.0) && (mono_signbit (d) == 0))
2660 ia64_fmov (code, ins->dreg, 0);
2662 ia64_fmov (code, ins->dreg, 1);
2664 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2665 ia64_movl (code, GP_SCRATCH_REG, 0);
2666 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2671 float f = *(float *)ins->inst_p0;
2673 if ((f == 0.0) && (mono_signbit (f) == 0))
2674 ia64_fmov (code, ins->dreg, 0);
2676 ia64_fmov (code, ins->dreg, 1);
2678 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2679 ia64_movl (code, GP_SCRATCH_REG, 0);
2680 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2685 ia64_fmov (code, ins->dreg, ins->sreg1);
2687 case OP_STORER8_MEMBASE_REG:
2688 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2690 case OP_STORER4_MEMBASE_REG:
2691 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2692 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2694 case OP_LOADR8_MEMBASE:
2695 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2697 case OP_LOADR4_MEMBASE:
2698 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2699 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2702 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2703 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2704 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2707 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2708 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2709 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2711 case OP_LCONV_TO_R8:
2712 /* FIXME: Difference with CEE_CONV_R8 ? */
2713 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2714 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2715 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2717 case OP_LCONV_TO_R4:
2718 /* FIXME: Difference with CEE_CONV_R4 ? */
2719 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2720 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2721 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2723 case OP_FCONV_TO_R4:
2724 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2726 case OP_FCONV_TO_I8:
2727 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2728 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2731 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2734 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2737 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2740 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2744 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2745 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2747 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2748 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2749 /* Positive infinity */
2750 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2751 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2752 /* Negative infinity */
2753 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2754 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2759 /* ensure ins->sreg1 is not NULL */
2760 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2763 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2764 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2771 call = (MonoCallInst*)ins;
2773 if (ins->flags & MONO_INST_HAS_METHOD)
2774 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2776 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2778 code = emit_move_return_value (cfg, ins, code);
2785 case OP_VOIDCALL_REG:
2786 call = (MonoCallInst*)ins;
2790 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2793 ia64_mov (code, IA64_R8, ins->sreg1);
2794 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2795 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2796 ia64_ld8 (code, IA64_GP, IA64_R8);
2797 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2799 code = emit_move_return_value (cfg, ins, code);
2802 case OP_FCALL_MEMBASE:
2803 case OP_LCALL_MEMBASE:
2804 case OP_VCALL_MEMBASE:
2805 case OP_VOIDCALL_MEMBASE:
2806 case OP_CALL_MEMBASE: {
2807 MonoCallInst *call = (MonoCallInst*)ins;
2812 * There are no membase instructions on ia64, but we can't
2813 * lower this since get_vcall_slot_addr () needs to decode it.
2816 /* Keep this in synch with get_vcall_slot_addr */
2817 ia64_mov (code, IA64_R11, ins->sreg1);
2818 if (ia64_is_imm14 (ins->inst_offset))
2819 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2821 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2822 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2825 if (call->method && ins->inst_offset < 0) {
2827 * This is a possible IMT call so save the IMT method in a global
2828 * register where mono_arch_find_imt_method () and its friends can access
2831 ia64_movl (code, IA64_R9, call->method);
2835 * mono_arch_find_this_arg () needs to find the this argument in a global
2838 cinfo = get_call_info (NULL, call->signature, FALSE);
2839 out_reg = cfg->arch.reg_out0;
2840 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
2843 ia64_mov (code, IA64_R10, out_reg);
2845 ia64_begin_bundle (code);
2846 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2848 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2850 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2853 * This nop will tell get_vcall_slot_addr that this is a virtual
2856 ia64_nop_i (code, 0x12345);
2858 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2860 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2862 code = emit_move_return_value (cfg, ins, code);
2867 * Keep in sync with the code in emit_epilog.
2870 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2873 g_assert (!cfg->method->save_lmf);
2875 /* Load arguments into their original registers */
2876 code = emit_load_volatile_arguments (cfg, code);
2878 if (cfg->arch.stack_alloc_size) {
2879 if (cfg->arch.omit_fp) {
2880 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2881 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2883 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2884 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2888 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2890 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2891 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2893 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2894 ia64_movl (code, GP_SCRATCH_REG, 0);
2895 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2896 ia64_br_cond_reg (code, IA64_B6);
2901 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2907 /* FIXME: Sigaltstack support */
2909 /* keep alignment */
2910 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2911 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2912 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2914 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2916 ia64_mov (code, ins->dreg, IA64_SP);
2918 /* An area at sp is reserved by the ABI for parameter passing */
2919 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2920 if (ia64_is_adds_imm (abi_offset))
2921 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2923 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2924 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2927 if (ins->flags & MONO_INST_INIT) {
2929 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2931 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2934 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2935 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2936 ia64_br_cond_pred (code, 8, -2);
2938 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2940 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2946 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2947 ia64_ld8 (code, ins->dreg, ins->dreg);
2950 /* Synchronization */
2951 case OP_MEMORY_BARRIER:
2954 case OP_ATOMIC_ADD_IMM_NEW_I4:
2955 g_assert (ins->inst_offset == 0);
2956 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2957 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2959 case OP_ATOMIC_ADD_IMM_NEW_I8:
2960 g_assert (ins->inst_offset == 0);
2961 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2962 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2964 case OP_ATOMIC_EXCHANGE_I4:
2965 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2966 ia64_sxt4 (code, ins->dreg, ins->dreg);
2968 case OP_ATOMIC_EXCHANGE_I8:
2969 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2971 case OP_ATOMIC_ADD_NEW_I4: {
2972 guint8 *label, *buf;
2974 /* From libatomic_ops */
2977 ia64_begin_bundle (code);
2978 label = code.buf + code.nins;
2979 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2980 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2981 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2982 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2983 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2984 buf = code.buf + code.nins;
2985 ia64_br_cond_pred (code, 7, 0);
2986 ia64_begin_bundle (code);
2987 ia64_patch (buf, label);
2988 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2991 case OP_ATOMIC_ADD_NEW_I8: {
2992 guint8 *label, *buf;
2994 /* From libatomic_ops */
2997 ia64_begin_bundle (code);
2998 label = code.buf + code.nins;
2999 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
3000 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3001 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3002 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3003 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3004 buf = code.buf + code.nins;
3005 ia64_br_cond_pred (code, 7, 0);
3006 ia64_begin_bundle (code);
3007 ia64_patch (buf, label);
3008 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3012 /* Exception handling */
3013 case OP_CALL_HANDLER:
3015 * Using a call instruction would mess up the register stack, so
3016 * save the return address to a register and use a
3019 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3020 ia64_mov (code, IA64_R15, IA64_R0);
3021 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3022 /* Add the length of OP_CALL_HANDLER */
3023 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3024 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3025 ia64_movl (code, GP_SCRATCH_REG2, 0);
3026 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3027 ia64_br_cond_reg (code, IA64_B6);
3028 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3030 case OP_START_HANDLER: {
3032 * We receive the return address in GP_SCRATCH_REG.
3034 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3037 * R15 determines our caller. It is used since it is writable using
3039 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3040 * R15 != 0 means we are called by call_filter ().
3042 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3043 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3045 ia64_br_cond_pred (code, 6, 6);
3048 * Called by call_filter:
3049 * Allocate a new stack frame, and set the fp register from the
3050 * value passed in by the caller.
3051 * We allocate a similar frame as is done by the prolog, so
3052 * if an exception is thrown while executing the filter, the
3053 * unwinder can unwind through the filter frame using the unwind
3054 * info for the prolog.
3056 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);
3057 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3058 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3059 ia64_mov (code, cfg->frame_reg, IA64_R15);
3060 /* Signal to endfilter that we are called by call_filter */
3061 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3063 /* Save the return address */
3064 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3065 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3066 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3071 case OP_ENDFILTER: {
3072 /* FIXME: Return the value in ENDFILTER */
3073 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3075 /* Load the return address */
3076 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3077 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3080 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3081 ia64_br_cond_pred (code, 7, 4);
3083 /* Called by call_filter */
3085 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3086 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3087 ia64_br_ret_reg (code, IA64_B0);
3089 /* Called by CALL_HANDLER */
3090 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3091 ia64_br_cond_reg (code, IA64_B6);
3095 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3096 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3097 (gpointer)"mono_arch_throw_exception");
3100 * This might be the last instruction in the method, so add a dummy
3101 * instruction so the unwinder will work.
3103 ia64_break_i (code, 0);
3106 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3107 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3108 (gpointer)"mono_arch_rethrow_exception");
3110 ia64_break_i (code, 0);
3114 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3115 g_assert_not_reached ();
3118 if ((code.buf - cfg->native_code - offset) > max_len) {
3119 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3120 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3121 g_assert_not_reached ();
3127 last_offset = offset;
3132 ia64_codegen_close (code);
3134 cfg->code_len = code.buf - cfg->native_code;
3138 mono_arch_register_lowlevel_calls (void)
3140 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3143 static Ia64InsType ins_types_in_template [32][3] = {
3144 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3145 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3146 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3147 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3148 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3149 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3152 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3153 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3154 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3155 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3156 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3157 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3158 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3159 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3160 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3161 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3162 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3163 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3166 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3167 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3168 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3169 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3172 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3173 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3178 static gboolean stops_in_template [32][3] = {
3179 { FALSE, FALSE, FALSE },
3180 { FALSE, FALSE, TRUE },
3181 { FALSE, TRUE, FALSE },
3182 { FALSE, TRUE, TRUE },
3183 { FALSE, FALSE, FALSE },
3184 { FALSE, FALSE, TRUE },
3185 { FALSE, FALSE, FALSE },
3186 { FALSE, FALSE, FALSE },
3188 { FALSE, FALSE, FALSE },
3189 { FALSE, FALSE, TRUE },
3190 { TRUE, FALSE, FALSE },
3191 { TRUE, FALSE, TRUE },
3192 { FALSE, FALSE, FALSE },
3193 { FALSE, FALSE, TRUE },
3194 { FALSE, FALSE, FALSE },
3195 { FALSE, FALSE, TRUE },
3197 { FALSE, FALSE, FALSE },
3198 { FALSE, FALSE, TRUE },
3199 { FALSE, FALSE, FALSE },
3200 { FALSE, FALSE, TRUE },
3201 { FALSE, FALSE, FALSE },
3202 { FALSE, FALSE, FALSE },
3203 { FALSE, FALSE, FALSE },
3204 { FALSE, FALSE, TRUE },
3206 { FALSE, FALSE, FALSE },
3207 { FALSE, FALSE, TRUE },
3208 { FALSE, FALSE, FALSE },
3209 { FALSE, FALSE, FALSE },
3210 { FALSE, FALSE, FALSE },
3211 { FALSE, FALSE, TRUE },
3212 { FALSE, FALSE, FALSE },
3213 { FALSE, FALSE, FALSE }
3216 static int last_stop_in_template [32] = {
3217 -1, 2, 1, 2, -1, 2, -1, -1,
3218 -1, 2, 0, 2, -1, 2, -1, 2,
3219 -1, 2, -1, 2, -1, -1, -1, 2,
3220 -1, 2, -1, -1, -1, 2, -1, -1
3223 static guint64 nops_for_ins_types [6] = {
3232 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3239 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3241 #define DEBUG_INS_SCHED(a)
3245 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3247 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3248 guint8 *deps = code->dep_info;
3249 gboolean need_stop, no_stop;
3251 for (i = 0; i < code->nins; ++i)
3255 current_deps_start = 0;
3256 current_ins_start = 0;
3257 deps_start [ins_index] = current_ins_start;
3260 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3261 while (pos < code->dep_info_pos) {
3263 switch (deps [pos]) {
3264 case IA64_END_OF_INS:
3266 current_ins_start = pos + 2;
3267 deps_start [ins_index] = current_ins_start;
3269 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3274 reg = deps [pos + 1];
3276 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3277 for (i = current_deps_start; i < current_ins_start; i += 2)
3278 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3282 reg = code->dep_info [pos + 1];
3284 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3285 for (i = current_deps_start; i < current_ins_start; i += 2)
3286 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3290 reg = deps [pos + 1];
3292 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3293 for (i = current_deps_start; i < current_ins_start; i += 2)
3294 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3297 case IA64_READ_PR_BRANCH:
3298 reg = deps [pos + 1];
3300 /* Writes to prs by non-float instructions are visible to branches */
3301 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3302 for (i = current_deps_start; i < current_ins_start; i += 2)
3303 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3307 reg = code->dep_info [pos + 1];
3309 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3310 for (i = current_deps_start; i < current_ins_start; i += 2)
3311 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3314 case IA64_WRITE_PR_FLOAT:
3315 reg = code->dep_info [pos + 1];
3317 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3318 for (i = current_deps_start; i < current_ins_start; i += 2)
3319 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3323 reg = deps [pos + 1];
3325 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3326 for (i = current_deps_start; i < current_ins_start; i += 2)
3327 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3331 reg = code->dep_info [pos + 1];
3333 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3334 for (i = current_deps_start; i < current_ins_start; i += 2)
3335 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3338 case IA64_READ_BR_BRANCH:
3339 reg = deps [pos + 1];
3341 /* Writes to brs are visible to branches */
3342 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3345 reg = deps [pos + 1];
3347 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3348 for (i = current_deps_start; i < current_ins_start; i += 2)
3349 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3353 reg = code->dep_info [pos + 1];
3355 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3356 for (i = current_deps_start; i < current_ins_start; i += 2)
3357 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3361 reg = deps [pos + 1];
3363 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3364 for (i = current_deps_start; i < current_ins_start; i += 2)
3365 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3369 reg = code->dep_info [pos + 1];
3371 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3372 for (i = current_deps_start; i < current_ins_start; i += 2)
3373 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3378 * Explicitly indicate that a stop is not required. Useful for
3379 * example when two predicated instructions with negated predicates
3380 * write the same registers.
3385 g_assert_not_reached ();
3389 if (need_stop && !no_stop) {
3390 g_assert (ins_index > 0);
3391 stops [ins_index - 1] = 1;
3393 DEBUG_INS_SCHED (printf ("STOP\n"));
3394 current_deps_start = current_ins_start;
3396 /* Skip remaining deps for this instruction */
3397 while (deps [pos] != IA64_END_OF_INS)
3402 if (code->nins > 0) {
3403 /* No dependency info for the last instruction */
3404 stops [code->nins - 1] = 1;
3407 deps_start [code->nins] = code->dep_info_pos;
3411 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3413 int stop_pos, i, deps_to_shift, dep_shift;
3415 g_assert (n <= code->nins);
3417 // if (n > 1) printf ("FOUND: %ld.\n", template);
3419 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3421 stop_pos = last_stop_in_template [template] + 1;
3425 /* Compute the number of 'real' instructions before the stop */
3426 deps_to_shift = stop_pos;
3427 if (stop_pos >= 3 && (nops & (1 << 2)))
3429 if (stop_pos >= 2 && (nops & (1 << 1)))
3431 if (stop_pos >= 1 && (nops & (1 << 0)))
3435 * We have to keep some dependencies whose instructions have been shifted
3436 * out of the buffer. So nullify the end_of_ins markers in the dependency
3439 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3440 if (code->dep_info [i] == IA64_END_OF_INS)
3441 code->dep_info [i] = IA64_NONE;
3443 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3444 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3445 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3447 dep_shift = deps_start [deps_to_shift];
3448 for (i = 0; i < code->nins + 1 - n; ++i)
3449 deps_start [i] = deps_start [n + i] - dep_shift;
3451 /* Determine the exact positions of instructions with unwind ops */
3452 if (code->unw_op_count) {
3454 int curr_ins, curr_ins_pos;
3457 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3458 for (i = 0; i < 3; ++i) {
3459 if (! (nops & (1 << i))) {
3460 ins_pos [curr_ins] = curr_ins_pos + i;
3465 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3466 if (code->unw_ops_pos [i] < n) {
3467 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3468 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3471 if (code->unw_op_pos < code->unw_op_count)
3472 code->unw_op_pos += n;
3475 if (n == code->nins) {
3480 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3481 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3482 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3488 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3490 int i, ins_type, template, nins_to_emit;
3491 int deps_start [16];
3496 * We implement a simple scheduler which tries to put three instructions
3497 * per bundle, then two, then one.
3499 ia64_analyze_deps (code, deps_start, stops);
3501 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3502 /* Find a suitable template */
3503 for (template = 0; template < 32; ++template) {
3504 if (stops_in_template [template][0] != stops [0] ||
3505 stops_in_template [template][1] != stops [1] ||
3506 stops_in_template [template][2] != stops [2])
3510 for (i = 0; i < 3; ++i) {
3511 ins_type = ins_types_in_template [template][i];
3512 switch (code->itypes [i]) {
3513 case IA64_INS_TYPE_A:
3514 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3517 found &= (ins_type == code->itypes [i]);
3523 found = debug_ins_sched ();
3526 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3532 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3533 /* Wait for more instructions */
3536 /* If it didn't work out, try putting two instructions into one bundle */
3537 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3538 /* Try a nop at the end */
3539 for (template = 0; template < 32; ++template) {
3540 if (stops_in_template [template][0] != stops [0] ||
3541 ((stops_in_template [template][1] != stops [1]) &&
3542 (stops_in_template [template][2] != stops [1])))
3546 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3547 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3550 if (!debug_ins_sched ())
3553 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);
3558 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3559 /* Wait for more instructions */
3562 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3563 /* Try a nop in the middle */
3564 for (template = 0; template < 32; ++template) {
3565 if (((stops_in_template [template][0] != stops [0]) &&
3566 (stops_in_template [template][1] != stops [0])) ||
3567 stops_in_template [template][2] != stops [1])
3570 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3571 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3574 if (!debug_ins_sched ())
3577 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);
3582 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3583 /* Try a nop at the beginning */
3584 for (template = 0; template < 32; ++template) {
3585 if ((stops_in_template [template][1] != stops [0]) ||
3586 (stops_in_template [template][2] != stops [1]))
3589 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3590 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3593 if (!debug_ins_sched ())
3596 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);
3601 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3602 /* Wait for more instructions */
3606 nins_to_emit = code->nins;
3610 while (nins_to_emit > 0) {
3611 if (!debug_ins_sched ())
3613 switch (code->itypes [0]) {
3614 case IA64_INS_TYPE_A:
3616 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3618 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3620 case IA64_INS_TYPE_I:
3622 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3624 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3626 case IA64_INS_TYPE_M:
3628 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3630 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3632 case IA64_INS_TYPE_B:
3634 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3636 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3638 case IA64_INS_TYPE_F:
3640 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3642 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3644 case IA64_INS_TYPE_LX:
3645 if (stops [0] || stops [1])
3646 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3648 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3652 g_assert_not_reached ();
3658 unw_dyn_region_info_t*
3659 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3661 unw_dyn_region_info_t *r;
3663 g_assert (code->nins == 0);
3664 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3665 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3666 r->op_count = code->unw_op_count;
3667 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3668 code->unw_op_count = 0;
3669 code->unw_op_pos = 0;
3670 code->region_start = code->buf;
3676 ia64_patch (unsigned char* code, gpointer target)
3679 guint64 instructions [3];
3680 guint8 gen_buf [16];
3681 Ia64CodegenState gen;
3686 * code encodes both the position inside the buffer and code.nins when
3687 * the instruction was emitted.
3689 ins_to_skip = (guint64)code % 16;
3690 code = (unsigned char*)((guint64)code & ~15);
3693 * Search for the first instruction which is 'patchable', skipping
3694 * ins_to_skip instructions.
3699 template = ia64_bundle_template (code);
3700 instructions [0] = ia64_bundle_ins1 (code);
3701 instructions [1] = ia64_bundle_ins2 (code);
3702 instructions [2] = ia64_bundle_ins3 (code);
3704 ia64_codegen_init (gen, gen_buf);
3707 for (i = 0; i < 3; ++i) {
3708 guint64 ins = instructions [i];
3709 int opcode = ia64_ins_opcode (ins);
3711 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3719 switch (ins_types_in_template [template][i]) {
3720 case IA64_INS_TYPE_A:
3721 case IA64_INS_TYPE_M:
3722 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3724 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3725 instructions [i] = gen.instructions [0];
3731 case IA64_INS_TYPE_B:
3732 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3734 gint64 disp = ((guint8*)target - code) >> 4;
3737 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3739 instructions [i] = gen.instructions [0];
3742 else if (opcode == 5) {
3744 gint64 disp = ((guint8*)target - code) >> 4;
3747 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3748 instructions [i] = gen.instructions [0];
3754 case IA64_INS_TYPE_LX:
3758 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3760 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3761 instructions [1] = gen.instructions [0];
3762 instructions [2] = gen.instructions [1];
3775 ia64_codegen_init (gen, code);
3776 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3786 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3788 MonoJumpInfo *patch_info;
3790 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3791 unsigned char *ip = patch_info->ip.i + code;
3792 const unsigned char *target;
3794 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3796 if (patch_info->type == MONO_PATCH_INFO_NONE)
3798 if (mono_compile_aot) {
3802 ia64_patch (ip, (gpointer)target);
3807 mono_arch_emit_prolog (MonoCompile *cfg)
3809 MonoMethod *method = cfg->method;
3810 MonoMethodSignature *sig;
3812 int alloc_size, pos, i;
3813 Ia64CodegenState code;
3816 sig = mono_method_signature (method);
3819 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
3821 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3823 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3824 cfg->code_size += 1024;
3825 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3826 cfg->code_size += 1024;
3828 cfg->native_code = g_malloc (cfg->code_size);
3830 ia64_codegen_init (code, cfg->native_code);
3832 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3833 if (cfg->param_area)
3834 alloc_size += cfg->param_area;
3838 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3840 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3841 /* Force sp to be saved/restored */
3842 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3844 cfg->arch.stack_alloc_size = alloc_size;
3848 if (method->save_lmf) {
3849 /* No LMF on IA64 */
3854 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3855 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);
3856 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3857 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3859 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3860 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3861 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3862 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3863 ia64_mov (code, cfg->frame_reg, IA64_SP);
3867 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3868 int pagesize = getpagesize ();
3870 if (alloc_size >= pagesize) {
3871 gint32 remaining_size = alloc_size;
3873 /* Generate stack touching code */
3874 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3875 while (remaining_size >= pagesize) {
3876 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3877 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3878 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3879 remaining_size -= pagesize;
3883 if (ia64_is_imm14 (-alloc_size)) {
3884 if (cfg->arch.omit_fp)
3885 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3886 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3889 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3890 if (cfg->arch.omit_fp)
3891 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3892 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3896 ia64_begin_bundle (code);
3898 /* Initialize unwind info */
3899 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3901 if (sig->ret->type != MONO_TYPE_VOID) {
3902 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3903 /* Save volatile arguments to the stack */
3908 /* Keep this in sync with emit_load_volatile_arguments */
3909 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3910 ArgInfo *ainfo = cinfo->args + i;
3911 gint32 stack_offset;
3913 inst = cfg->args [i];
3915 if (sig->hasthis && (i == 0))
3916 arg_type = &mono_defaults.object_class->byval_arg;
3918 arg_type = sig->params [i - sig->hasthis];
3920 arg_type = mono_type_get_underlying_type (arg_type);
3922 stack_offset = ainfo->offset + ARGS_OFFSET;
3924 /* Save volatile arguments to the stack */
3925 if (inst->opcode != OP_REGVAR) {
3926 switch (ainfo->storage) {
3929 g_assert (inst->opcode == OP_REGOFFSET);
3930 if (ia64_is_adds_imm (inst->inst_offset))
3931 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3933 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3934 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3936 if (arg_type->byref)
3937 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3939 switch (arg_type->type) {
3941 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3944 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3947 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3955 if (ainfo->nslots != ainfo->nregs)
3958 g_assert (inst->opcode == OP_REGOFFSET);
3959 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3960 for (i = 0; i < ainfo->nregs; ++i) {
3961 switch (ainfo->atype) {
3962 case AggregateNormal:
3963 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3965 case AggregateSingleHFA:
3966 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3968 case AggregateDoubleHFA:
3969 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3977 g_assert_not_reached ();
3981 if (inst->opcode == OP_REGVAR) {
3982 /* Argument allocated to (non-volatile) register */
3983 switch (ainfo->storage) {
3985 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3986 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3989 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3990 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3998 if (method->save_lmf) {
3999 /* No LMF on IA64 */
4002 ia64_codegen_close (code);
4006 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4007 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4009 cfg->code_len = code.buf - cfg->native_code;
4011 g_assert (cfg->code_len < cfg->code_size);
4013 cfg->arch.prolog_end_offset = cfg->code_len;
4019 mono_arch_emit_epilog (MonoCompile *cfg)
4021 MonoMethod *method = cfg->method;
4023 int max_epilog_size = 16 * 4;
4024 Ia64CodegenState code;
4029 if (mono_jit_trace_calls != NULL)
4030 max_epilog_size += 1024;
4032 cfg->arch.epilog_begin_offset = cfg->code_len;
4034 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4035 cfg->code_size *= 2;
4036 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4037 mono_jit_stats.code_reallocs++;
4040 /* FIXME: Emit unwind info */
4042 buf = cfg->native_code + cfg->code_len;
4044 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4045 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4047 ia64_codegen_init (code, buf);
4049 /* the code restoring the registers must be kept in sync with OP_JMP */
4052 if (method->save_lmf) {
4053 /* No LMF on IA64 */
4056 /* Load returned vtypes into registers if needed */
4057 cinfo = get_call_info (cfg->generic_sharing_context, mono_method_signature (method), FALSE);
4058 ainfo = &cinfo->ret;
4059 switch (ainfo->storage) {
4061 if (ainfo->nslots != ainfo->nregs)
4064 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4065 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4066 for (i = 0; i < ainfo->nregs; ++i) {
4067 switch (ainfo->atype) {
4068 case AggregateNormal:
4069 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4071 case AggregateSingleHFA:
4072 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4074 case AggregateDoubleHFA:
4075 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4078 g_assert_not_reached ();
4087 ia64_begin_bundle (code);
4089 code.region_start = cfg->native_code;
4091 /* Label the unwind state at the start of the exception throwing region */
4092 //ia64_unw_label_state (code, 1234);
4094 if (cfg->arch.stack_alloc_size) {
4095 if (cfg->arch.omit_fp) {
4096 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4097 ia64_unw_pop_frames (code, 1);
4098 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4100 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4101 ia64_unw_pop_frames (code, 1);
4102 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4106 ia64_unw_pop_frames (code, 1);
4107 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4110 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4111 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4112 ia64_br_ret_reg (code, IA64_B0);
4114 ia64_codegen_close (code);
4116 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4117 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4119 cfg->code_len = code.buf - cfg->native_code;
4121 g_assert (cfg->code_len < cfg->code_size);
4125 mono_arch_emit_exceptions (MonoCompile *cfg)
4127 MonoJumpInfo *patch_info;
4129 Ia64CodegenState code;
4130 gboolean empty = TRUE;
4131 //unw_dyn_region_info_t *r_exceptions;
4132 MonoClass *exc_classes [16];
4133 guint8 *exc_throw_start [16], *exc_throw_end [16];
4134 guint32 code_size = 0;
4136 /* Compute needed space */
4137 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4138 if (patch_info->type == MONO_PATCH_INFO_EXC)
4140 if (patch_info->type == MONO_PATCH_INFO_R8)
4141 code_size += 8 + 7; /* sizeof (double) + alignment */
4142 if (patch_info->type == MONO_PATCH_INFO_R4)
4143 code_size += 4 + 7; /* sizeof (float) + alignment */
4149 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4150 cfg->code_size *= 2;
4151 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4152 mono_jit_stats.code_reallocs++;
4155 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4157 /* The unwind state here is the same as before the epilog */
4158 //ia64_unw_copy_state (code, 1234);
4160 /* add code to raise exceptions */
4161 /* FIXME: Optimize this */
4163 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4164 switch (patch_info->type) {
4165 case MONO_PATCH_INFO_EXC: {
4166 MonoClass *exc_class;
4169 guint64 exc_token_index;
4171 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4172 g_assert (exc_class);
4173 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4174 throw_ip = cfg->native_code + patch_info->ip.i;
4176 ia64_begin_bundle (code);
4178 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4180 /* Find a throw sequence for the same exception class */
4181 for (i = 0; i < nthrows; ++i)
4182 if (exc_classes [i] == exc_class)
4186 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4188 if (ia64_is_adds_imm (offset))
4189 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4191 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4193 buf = code.buf + code.nins;
4194 ia64_br_cond_pred (code, 0, 0);
4195 ia64_begin_bundle (code);
4196 ia64_patch (buf, exc_throw_start [i]);
4198 patch_info->type = MONO_PATCH_INFO_NONE;
4203 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4205 ia64_begin_bundle (code);
4208 exc_classes [nthrows] = exc_class;
4209 exc_throw_start [nthrows] = code.buf;
4213 if (ia64_is_adds_imm (exc_token_index))
4214 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4216 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4218 patch_info->data.name = "mono_arch_throw_corlib_exception";
4219 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4220 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4223 ia64_movl (code, GP_SCRATCH_REG, 0);
4224 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4225 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4226 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4228 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4230 /* Patch up the throw offset */
4231 ia64_begin_bundle (code);
4233 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4236 exc_throw_end [nthrows] = code.buf;
4250 /* The unwinder needs this to work */
4251 ia64_break_i (code, 0);
4253 ia64_codegen_close (code);
4256 //r_exceptions = mono_ia64_create_unwind_region (&code);
4257 //cfg->arch.r_epilog = r_exceptions;
4259 cfg->code_len = code.buf - cfg->native_code;
4261 g_assert (cfg->code_len < cfg->code_size);
4265 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4267 Ia64CodegenState code;
4268 CallInfo *cinfo = NULL;
4269 MonoMethodSignature *sig;
4271 int i, n, stack_area = 0;
4273 ia64_codegen_init (code, p);
4275 /* Keep this in sync with mono_arch_get_argument_info */
4277 if (enable_arguments) {
4278 /* Allocate a new area on the stack and save arguments there */
4279 sig = mono_method_signature (cfg->method);
4281 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
4283 n = sig->param_count + sig->hasthis;
4285 stack_area = ALIGN_TO (n * 8, 16);
4288 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4290 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4292 /* FIXME: Allocate out registers */
4294 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4296 /* Required by the ABI */
4297 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4299 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4300 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4302 /* Save arguments to the stack */
4303 for (i = 0; i < n; ++i) {
4304 ins = cfg->args [i];
4306 if (ins->opcode == OP_REGVAR) {
4307 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4308 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4309 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4312 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4313 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4314 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4315 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4316 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4317 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4322 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4325 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4327 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4328 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4330 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4332 if (enable_arguments && stack_area) {
4333 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4335 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4337 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4342 ia64_codegen_close (code);
4348 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4350 Ia64CodegenState code;
4351 CallInfo *cinfo = NULL;
4352 MonoMethod *method = cfg->method;
4353 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4355 ia64_codegen_init (code, p);
4357 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
4359 /* Save return value + pass it to func */
4360 switch (cinfo->ret.storage) {
4364 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4365 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4368 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4369 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4370 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4371 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4373 case ArgValuetypeAddrInIReg:
4374 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4385 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4386 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4387 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4389 /* Restore return value */
4390 switch (cinfo->ret.storage) {
4394 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4397 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4398 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4400 case ArgValuetypeAddrInIReg:
4408 ia64_codegen_close (code);
4414 mono_arch_save_unwind_info (MonoCompile *cfg)
4418 /* FIXME: Unregister this for dynamic methods */
4420 di = g_malloc0 (sizeof (unw_dyn_info_t));
4421 di->start_ip = (unw_word_t) cfg->native_code;
4422 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4424 di->format = UNW_INFO_FORMAT_DYNAMIC;
4425 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4426 di->u.pi.regions = cfg->arch.r_pro;
4428 _U_dyn_register (di);
4432 unw_dyn_region_info_t *region = di->u.pi.regions;
4434 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4436 printf (" [Region: %d]\n", region->insn_count);
4437 region = region->next;
4444 mono_arch_flush_icache (guint8 *code, gint size)
4446 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4447 guint8* end = (guint8*)((guint64)code + size);
4449 #ifdef __INTEL_COMPILER
4450 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4457 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4458 /* FIXME: This could be increased to 128 on some cpus */
4465 mono_arch_flush_register_windows (void)
4467 /* Not needed because of libunwind */
4471 mono_arch_is_inst_imm (gint64 imm)
4473 /* The lowering pass will take care of it */
4479 * Determine whenever the trap whose info is in SIGINFO is caused by
4483 mono_arch_is_int_overflow (void *sigctx, void *info)
4485 /* Division is emulated with explicit overflow checks */
4490 mono_arch_get_patch_offset (guint8 *code)
4498 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4500 guint8 *bundle2 = code - 48;
4501 guint8 *bundle3 = code - 32;
4502 guint8 *bundle4 = code - 16;
4503 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4504 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4505 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4506 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4507 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4508 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4509 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4510 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4511 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4514 * Virtual calls are made with:
4516 * [MII] ld8 r31=[r8]
4520 * mov.sptk b6=r31,0x2000000000f32a80
4527 * br.call.sptk.few b0=b6;;
4530 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4531 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4532 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4533 (ins31 == IA64_NOP_M) &&
4534 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4535 (ins33 == IA64_NOP_I) &&
4536 (ins41 == IA64_NOP_M) &&
4537 (ins42 == IA64_NOP_I) &&
4538 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4539 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4540 g_assert (ins21 == IA64_NOP_M);
4541 g_assert (ins23 == IA64_NOP_I);
4542 g_assert (ia64_ins_opcode (ins22) == 0);
4543 g_assert (ia64_ins_x3 (ins22) == 7);
4544 g_assert (ia64_ins_x (ins22) == 0);
4545 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4547 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4549 return regs [IA64_R11];
4556 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4560 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4563 return (gpointer*)(gpointer)((char*)vt + displacement);
4567 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4574 static gboolean tls_offset_inited = FALSE;
4577 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4579 if (!tls_offset_inited) {
4580 tls_offset_inited = TRUE;
4582 appdomain_tls_offset = mono_domain_get_tls_offset ();
4583 thread_tls_offset = mono_thread_get_tls_offset ();
4588 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4593 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4595 MonoCallInst *call = (MonoCallInst*)inst;
4596 int out_reg = cfg->arch.reg_out0;
4599 CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, inst->signature, FALSE);
4602 if (cinfo->ret.storage == ArgAggregate) {
4603 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4606 * The valuetype is in registers after the call, need to be copied
4607 * to the stack. Save the address to a local here, so the call
4608 * instruction can access it.
4610 g_assert (local->opcode == OP_REGOFFSET);
4611 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4614 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4615 vtarg->sreg1 = vt_reg;
4616 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4617 mono_bblock_add_inst (cfg->cbb, vtarg);
4619 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4627 /* add the this argument */
4628 if (this_reg != -1) {
4630 MONO_INST_NEW (cfg, this, OP_MOVE);
4631 this->type = this_type;
4632 this->sreg1 = this_reg;
4633 this->dreg = mono_regstate_next_int (cfg->rs);
4634 mono_bblock_add_inst (cfg->cbb, this);
4636 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4641 #ifdef MONO_ARCH_HAVE_IMT
4644 * LOCKING: called with the domain lock held
4647 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4651 guint8 *start, *buf;
4652 Ia64CodegenState code;
4655 buf = g_malloc0 (size);
4656 ia64_codegen_init (code, buf);
4658 /* IA64_R9 contains the IMT method */
4660 for (i = 0; i < count; ++i) {
4661 MonoIMTCheckItem *item = imt_entries [i];
4662 ia64_begin_bundle (code);
4663 item->code_target = (guint8*)code.buf + code.nins;
4664 if (item->is_equals) {
4665 if (item->check_target_idx) {
4666 if (!item->compare_done) {
4667 ia64_movl (code, GP_SCRATCH_REG, item->method);
4668 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4670 item->jmp_code = (guint8*)code.buf + code.nins;
4671 ia64_br_cond_pred (code, 7, 0);
4673 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4674 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4675 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4676 ia64_br_cond_reg (code, IA64_B6);
4678 /* enable the commented code to assert on wrong method */
4679 #if ENABLE_WRONG_METHOD_CHECK
4680 g_assert_not_reached ();
4682 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4683 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4684 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4685 ia64_br_cond_reg (code, IA64_B6);
4686 #if ENABLE_WRONG_METHOD_CHECK
4687 g_assert_not_reached ();
4691 ia64_movl (code, GP_SCRATCH_REG, item->method);
4692 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4693 item->jmp_code = (guint8*)code.buf + code.nins;
4694 ia64_br_cond_pred (code, 6, 0);
4697 /* patch the branches to get to the target items */
4698 for (i = 0; i < count; ++i) {
4699 MonoIMTCheckItem *item = imt_entries [i];
4700 if (item->jmp_code) {
4701 if (item->check_target_idx) {
4702 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4707 ia64_codegen_close (code);
4708 g_assert (code.buf - buf <= size);
4710 size = code.buf - buf;
4711 start = mono_code_manager_reserve (domain->code_mp, size);
4712 memcpy (start, buf, size);
4714 mono_arch_flush_icache (start, size);
4716 mono_stats.imt_thunks_size += size;
4722 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4724 return regs [IA64_R9];
4728 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
4730 return regs [IA64_R10];
4734 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
4736 /* Done by the implementation of the CALL_MEMBASE opcodes */
4741 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4743 MonoInst *ins = NULL;
4745 if (cmethod->klass == mono_defaults.thread_class &&
4746 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4747 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4748 } else if(cmethod->klass->image == mono_defaults.corlib &&
4749 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4750 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4752 if (strcmp (cmethod->name, "Increment") == 0) {
4755 if (fsig->params [0]->type == MONO_TYPE_I4)
4756 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4757 else if (fsig->params [0]->type == MONO_TYPE_I8)
4758 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4760 g_assert_not_reached ();
4761 MONO_INST_NEW (cfg, ins, opcode);
4763 ins->inst_i0 = args [0];
4764 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4767 if (fsig->params [0]->type == MONO_TYPE_I4)
4768 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4769 else if (fsig->params [0]->type == MONO_TYPE_I8)
4770 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4772 g_assert_not_reached ();
4773 MONO_INST_NEW (cfg, ins, opcode);
4775 ins->inst_i0 = args [0];
4776 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4779 if (fsig->params [0]->type == MONO_TYPE_I4)
4780 opcode = OP_ATOMIC_EXCHANGE_I4;
4781 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4782 (fsig->params [0]->type == MONO_TYPE_I) ||
4783 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4784 opcode = OP_ATOMIC_EXCHANGE_I8;
4788 MONO_INST_NEW (cfg, ins, opcode);
4790 ins->inst_i0 = args [0];
4791 ins->inst_i1 = args [1];
4792 } else if (strcmp (cmethod->name, "Add") == 0) {
4795 if (fsig->params [0]->type == MONO_TYPE_I4)
4796 opcode = OP_ATOMIC_ADD_NEW_I4;
4797 else if (fsig->params [0]->type == MONO_TYPE_I8)
4798 opcode = OP_ATOMIC_ADD_NEW_I8;
4800 g_assert_not_reached ();
4802 MONO_INST_NEW (cfg, ins, opcode);
4804 ins->inst_i0 = args [0];
4805 ins->inst_i1 = args [1];
4806 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4807 /* 64 bit reads are already atomic */
4808 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4809 ins->inst_i0 = args [0];
4817 mono_arch_print_tree (MonoInst *tree, int arity)
4822 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4826 if (appdomain_tls_offset == -1)
4829 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4830 ins->inst_offset = appdomain_tls_offset;
4834 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4838 if (thread_tls_offset == -1)
4841 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4842 ins->inst_offset = thread_tls_offset;