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"
29 #include "jit-icalls.h"
31 static gint appdomain_tls_offset = -1;
32 static gint thread_tls_offset = -1;
34 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
36 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
39 * IA64 register usage:
40 * - local registers are used for global register allocation
41 * - r8..r11, r14..r30 is used for local register allocation
42 * - r31 is a scratch register used within opcode implementations
43 * - FIXME: Use out registers as well
44 * - the first three locals are used for saving ar.pfst, b0, and sp
45 * - compare instructions allways set p6 and p7
49 * There are a lot of places where generated code is disassembled/patched.
50 * The automatic bundling of instructions done by the code generation macros
51 * could complicate things, so it is best to call
52 * ia64_codegen_set_one_ins_per_bundle () at those places.
55 #define ARGS_OFFSET 16
57 #define GP_SCRATCH_REG 31
58 #define GP_SCRATCH_REG2 30
59 #define FP_SCRATCH_REG 32
60 #define FP_SCRATCH_REG2 33
62 #define LOOP_ALIGNMENT 8
63 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
65 static const char* gregs [] = {
66 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
67 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
68 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
69 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
70 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
71 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
72 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
73 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
74 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
75 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
76 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
77 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
78 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
82 mono_arch_regname (int reg)
90 static const char* fregs [] = {
91 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
92 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
93 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
94 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
95 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
96 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
97 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
98 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
99 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
100 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
101 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
102 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
103 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
107 mono_arch_fregname (int reg)
115 G_GNUC_UNUSED static void
120 G_GNUC_UNUSED static gboolean
123 static int count = 0;
126 if (count == atoi (getenv ("COUNT"))) {
130 if (count > atoi (getenv ("COUNT"))) {
138 debug_ins_sched (void)
141 return debug_count ();
151 return debug_count ();
158 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 = is_double ? ArgInFloatReg : ArgInFloatRegR4;
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;
313 (*gr) += info->num_fields;
318 /* This also handles returning of TypedByRef used by some icalls */
321 ainfo->reg = IA64_R8;
322 ainfo->nregs = (size + 7) / 8;
323 ainfo->nslots = ainfo->nregs;
330 ainfo->offset = *stack_size;
331 ainfo->nslots = (size + 7) / 8;
333 if (((*gr) + ainfo->nslots) <= 8) {
334 /* Fits entirely in registers */
335 ainfo->nregs = ainfo->nslots;
336 (*gr) += ainfo->nregs;
340 ainfo->nregs = 8 - (*gr);
342 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
348 * Obtain information about a call according to the calling convention.
349 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
350 * Gude" document for more information.
353 get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
357 int n = sig->hasthis + sig->param_count;
358 guint32 stack_size = 0;
360 MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
363 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
365 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
372 ret_type = mono_type_get_underlying_type (sig->ret);
373 ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
374 switch (ret_type->type) {
375 case MONO_TYPE_BOOLEAN:
386 case MONO_TYPE_FNPTR:
387 case MONO_TYPE_CLASS:
388 case MONO_TYPE_OBJECT:
389 case MONO_TYPE_SZARRAY:
390 case MONO_TYPE_ARRAY:
391 case MONO_TYPE_STRING:
392 cinfo->ret.storage = ArgInIReg;
393 cinfo->ret.reg = IA64_R8;
397 cinfo->ret.storage = ArgInIReg;
398 cinfo->ret.reg = IA64_R8;
402 cinfo->ret.storage = ArgInFloatReg;
405 case MONO_TYPE_GENERICINST:
406 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
407 cinfo->ret.storage = ArgInIReg;
408 cinfo->ret.reg = IA64_R8;
412 case MONO_TYPE_VALUETYPE:
413 case MONO_TYPE_TYPEDBYREF: {
414 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
416 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
417 if (cinfo->ret.storage == ArgOnStack)
418 /* The caller passes the address where the value is stored */
419 add_general (&gr, &stack_size, &cinfo->ret);
420 if (cinfo->ret.storage == ArgInIReg)
421 cinfo->ret.storage = ArgValuetypeAddrInIReg;
425 cinfo->ret.storage = ArgNone;
428 g_error ("Can't handle as return value 0x%x", sig->ret->type);
434 add_general (&gr, &stack_size, cinfo->args + 0);
436 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
438 fr = FLOAT_PARAM_REGS;
440 /* Emit the signature cookie just before the implicit arguments */
441 add_general (&gr, &stack_size, &cinfo->sig_cookie);
444 for (i = 0; i < sig->param_count; ++i) {
445 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
448 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
449 /* We allways pass the sig cookie on the stack for simplicity */
451 * Prevent implicit arguments + the sig cookie from being passed
455 fr = FLOAT_PARAM_REGS;
457 /* Emit the signature cookie just before the implicit arguments */
458 add_general (&gr, &stack_size, &cinfo->sig_cookie);
461 if (sig->params [i]->byref) {
462 add_general (&gr, &stack_size, ainfo);
465 ptype = mono_type_get_underlying_type (sig->params [i]);
466 ptype = mini_get_basic_type_from_generic (gsctx, ptype);
467 switch (ptype->type) {
468 case MONO_TYPE_BOOLEAN:
471 add_general (&gr, &stack_size, ainfo);
476 add_general (&gr, &stack_size, ainfo);
480 add_general (&gr, &stack_size, ainfo);
485 case MONO_TYPE_FNPTR:
486 case MONO_TYPE_CLASS:
487 case MONO_TYPE_OBJECT:
488 case MONO_TYPE_STRING:
489 case MONO_TYPE_SZARRAY:
490 case MONO_TYPE_ARRAY:
491 add_general (&gr, &stack_size, ainfo);
493 case MONO_TYPE_GENERICINST:
494 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
495 add_general (&gr, &stack_size, ainfo);
499 case MONO_TYPE_VALUETYPE:
500 case MONO_TYPE_TYPEDBYREF:
502 /* We allways pass valuetypes on the stack */
503 add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
507 add_general (&gr, &stack_size, ainfo);
510 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
513 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
516 g_assert_not_reached ();
520 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
522 fr = FLOAT_PARAM_REGS;
524 /* Emit the signature cookie just before the implicit arguments */
525 add_general (&gr, &stack_size, &cinfo->sig_cookie);
528 cinfo->stack_usage = stack_size;
529 cinfo->reg_usage = gr;
530 cinfo->freg_usage = fr;
535 * mono_arch_get_argument_info:
536 * @csig: a method signature
537 * @param_count: the number of parameters to consider
538 * @arg_info: an array to store the result infos
540 * Gathers information on parameters such as size, alignment and
541 * padding. arg_info should be large enought to hold param_count + 1 entries.
543 * Returns the size of the argument area on the stack.
546 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
549 CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
550 guint32 args_size = cinfo->stack_usage;
552 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
554 arg_info [0].offset = 0;
557 for (k = 0; k < param_count; k++) {
558 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
560 arg_info [k + 1].size = 0;
569 * Initialize the cpu to execute managed code.
572 mono_arch_cpu_init (void)
577 * Initialize architecture specific code.
580 mono_arch_init (void)
585 * Cleanup architecture specific code.
588 mono_arch_cleanup (void)
593 * This function returns the optimizations supported on this cpu.
596 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
604 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
608 MonoMethodSignature *sig;
609 MonoMethodHeader *header;
612 header = mono_method_get_header (cfg->method);
614 sig = mono_method_signature (cfg->method);
616 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
618 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
619 MonoInst *ins = cfg->args [i];
621 ArgInfo *ainfo = &cinfo->args [i];
623 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
626 if (ainfo->storage == ArgInIReg) {
627 /* The input registers are non-volatile */
628 ins->opcode = OP_REGVAR;
629 ins->dreg = 32 + ainfo->reg;
633 for (i = 0; i < cfg->num_varinfo; i++) {
634 MonoInst *ins = cfg->varinfo [i];
635 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
638 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
641 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
642 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
645 if (mono_is_regsize_var (ins->inst_vtype)) {
646 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
647 g_assert (i == vmv->idx);
648 vars = g_list_prepend (vars, vmv);
652 vars = mono_varlist_sort (cfg, vars, 0);
658 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
661 guint32 reserved_regs;
662 MonoMethodHeader *header;
664 if (cfg->arch.reg_local0 > 0)
668 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
670 header = mono_method_get_header (cfg->method);
672 /* Some registers are reserved for use by the prolog/epilog */
673 reserved_regs = header->num_clauses ? 4 : 3;
675 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
676 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
677 /* One registers is needed by instrument_epilog to save the return value */
679 if (cinfo->reg_usage < 2)
680 /* Number of arguments passed to function call in instrument_prolog */
681 cinfo->reg_usage = 2;
684 cfg->arch.reg_in0 = 32;
685 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
686 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
688 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
689 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
690 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
693 * Frames without handlers save sp to fp, frames with handlers save it into
694 * a dedicated register.
696 if (header->num_clauses)
697 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
699 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
701 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
702 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
703 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
707 * Need to allocate at least 2 out register for use by OP_THROW / the system
708 * exception throwing code.
710 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, cfg->mempool, 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->vret_addr->opcode = OP_REGVAR;
822 cfg->vret_addr->dreg = 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;
890 case ArgInFloatRegR4:
892 * Since float regs are volatile, we save the arguments to
893 * the stack in the prolog.
898 if (cfg->arch.omit_fp)
899 g_assert_not_reached ();
900 inst->opcode = OP_REGOFFSET;
901 inst->inst_basereg = cfg->frame_reg;
902 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
911 if (!inreg && (ainfo->storage != ArgOnStack)) {
912 inst->opcode = OP_REGOFFSET;
913 inst->inst_basereg = cfg->frame_reg;
914 /* These arguments are saved to the stack in the prolog */
915 switch (ainfo->storage) {
917 if (ainfo->atype == AggregateSingleHFA)
918 offset += ainfo->nslots * 4;
920 offset += ainfo->nslots * 8;
923 offset += sizeof (gpointer);
926 offset = ALIGN_TO (offset, sizeof (gpointer));
927 if (cfg->arch.omit_fp)
928 inst->inst_offset = offset;
930 inst->inst_offset = - offset;
935 if (cfg->arch.omit_fp && offset == 16)
938 cfg->stack_offset = offset;
942 mono_arch_create_vars (MonoCompile *cfg)
944 MonoMethodSignature *sig;
947 sig = mono_method_signature (cfg->method);
949 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
951 if (cinfo->ret.storage == ArgAggregate)
952 cfg->ret_var_is_local = TRUE;
953 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
954 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
955 if (G_UNLIKELY (cfg->verbose_level > 1)) {
956 printf ("vret_addr = ");
957 mono_print_ins (cfg->vret_addr);
963 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
967 arg->opcode = OP_OUTARG_REG;
968 arg->inst_left = tree;
969 arg->inst_right = (MonoInst*)call;
970 arg->backend.reg3 = reg;
971 call->used_iregs |= 1 << reg;
974 arg->opcode = OP_OUTARG_FREG;
975 arg->inst_left = tree;
976 arg->inst_right = (MonoInst*)call;
977 arg->backend.reg3 = reg;
978 call->used_fregs |= 1 << reg;
980 case ArgInFloatRegR4:
981 arg->opcode = OP_OUTARG_FREG_R4;
982 arg->inst_left = tree;
983 arg->inst_right = (MonoInst*)call;
984 arg->backend.reg3 = reg;
985 call->used_fregs |= 1 << reg;
988 g_assert_not_reached ();
993 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
996 MonoMethodSignature *tmp_sig;
999 /* FIXME: Add support for signature tokens to AOT */
1000 cfg->disable_aot = TRUE;
1002 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1005 * mono_ArgIterator_Setup assumes the signature cookie is
1006 * passed first and all the arguments which were before it are
1007 * passed on the stack after the signature. So compensate by
1008 * passing a different signature.
1010 tmp_sig = mono_metadata_signature_dup (call->signature);
1011 tmp_sig->param_count -= call->signature->sentinelpos;
1012 tmp_sig->sentinelpos = 0;
1013 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1015 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1016 sig_arg->inst_p0 = tmp_sig;
1018 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1019 arg->inst_left = sig_arg;
1020 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1021 arg->type = STACK_PTR;
1023 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
1027 * take the arguments and generate the arch-specific
1028 * instructions to properly call the function in call.
1029 * This includes pushing, moving arguments to the right register
1033 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1036 MonoMethodSignature *sig;
1037 int i, n, stack_size;
1043 mono_ia64_alloc_stacked_registers (cfg);
1045 sig = call->signature;
1046 n = sig->param_count + sig->hasthis;
1048 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1050 if (cinfo->ret.storage == ArgAggregate) {
1051 /* The code in emit_this_vret_arg needs a local */
1052 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1053 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1056 for (i = 0; i < n; ++i) {
1057 ainfo = cinfo->args + i;
1059 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1060 /* Emit the signature cookie just before the implicit arguments */
1061 emit_sig_cookie (cfg, call, cinfo);
1064 if (is_virtual && i == 0) {
1065 /* the argument will be attached to the call instruction */
1066 in = call->args [i];
1070 in = call->args [i];
1071 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1072 arg->cil_code = in->cil_code;
1073 arg->inst_left = in;
1074 arg->type = in->type;
1076 if (sig->hasthis && (i == 0))
1077 arg_type = &mono_defaults.object_class->byval_arg;
1079 arg_type = sig->params [i - sig->hasthis];
1081 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1082 MonoInst *stack_addr;
1086 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1087 size = sizeof (MonoTypedRef);
1088 align = sizeof (gpointer);
1092 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1095 * Other backends use mini_type_stack_size (), but that
1096 * aligns the size to 8, which is larger than the size of
1097 * the source, leading to reads of invalid memory if the
1098 * source is at the end of address space.
1100 size = mono_class_value_size (in->klass, &align);
1103 if (ainfo->storage == ArgAggregate) {
1104 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1107 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1109 /* Trees can't be shared so make a copy */
1110 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1111 arg->cil_code = in->cil_code;
1112 arg->ssa_op = MONO_SSA_STORE;
1113 arg->inst_left = vtaddr;
1114 arg->inst_right = in;
1115 arg->type = in->type;
1116 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1119 * Part of the structure is passed in registers.
1121 for (j = 0; j < ainfo->nregs; ++j) {
1122 int offset, load_op, dest_reg, arg_storage;
1124 slot = ainfo->reg + j;
1126 if (ainfo->atype == AggregateSingleHFA) {
1127 load_op = CEE_LDIND_R4;
1129 dest_reg = ainfo->reg + j;
1130 arg_storage = ArgInFloatReg;
1131 } else if (ainfo->atype == AggregateDoubleHFA) {
1132 load_op = CEE_LDIND_R8;
1134 dest_reg = ainfo->reg + j;
1135 arg_storage = ArgInFloatReg;
1137 load_op = CEE_LDIND_I;
1139 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1140 arg_storage = ArgInIReg;
1143 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1144 load->ssa_op = MONO_SSA_LOAD;
1145 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1147 NEW_ICONST (cfg, offset_ins, offset);
1148 MONO_INST_NEW (cfg, load2, CEE_ADD);
1149 load2->inst_left = load;
1150 load2->inst_right = offset_ins;
1152 MONO_INST_NEW (cfg, load, load_op);
1153 load->inst_left = load2;
1155 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1156 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1157 MONO_INST_LIST_ADD_TAIL (&set_reg->node, &call->out_args);
1161 * Part of the structure is passed on the stack.
1163 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1166 slot = ainfo->reg + j;
1168 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1169 load->ssa_op = MONO_SSA_LOAD;
1170 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1172 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1173 MONO_INST_NEW (cfg, load2, CEE_ADD);
1174 load2->inst_left = load;
1175 load2->inst_right = offset_ins;
1177 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1178 load->inst_left = load2;
1180 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1181 outarg->inst_left = load;
1182 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1184 MONO_INST_LIST_ADD_TAIL (&outarg->node, &call->out_args);
1188 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1189 stack_addr->inst_basereg = IA64_SP;
1190 stack_addr->inst_offset = 16 + ainfo->offset;
1191 stack_addr->inst_imm = size;
1193 arg->opcode = OP_OUTARG_VT;
1194 arg->inst_right = stack_addr;
1195 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1199 switch (ainfo->storage) {
1201 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1204 case ArgInFloatRegR4:
1205 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1208 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1209 arg->opcode = OP_OUTARG_R4;
1212 arg->opcode = OP_OUTARG;
1213 arg->inst_imm = 16 + ainfo->offset;
1216 g_assert_not_reached ();
1218 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1223 /* Handle the case where there are no implicit arguments */
1224 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1225 emit_sig_cookie (cfg, call, cinfo);
1228 call->stack_usage = cinfo->stack_usage;
1229 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1230 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1231 cfg->flags |= MONO_CFG_HAS_CALLS;
1237 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1242 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1246 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1247 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1249 switch (ins->opcode) {
1257 if (ins->dreg == ins->sreg1) {
1258 MONO_DELETE_INS (bb, ins);
1264 * OP_MOVE sreg, dreg
1265 * OP_MOVE dreg, sreg
1267 if (last_ins && last_ins->opcode == OP_MOVE &&
1268 ins->sreg1 == last_ins->dreg &&
1269 ins->dreg == last_ins->sreg1) {
1270 MONO_DELETE_INS (bb, ins);
1276 /* remove unnecessary multiplication with 1 */
1277 if (ins->inst_imm == 1) {
1278 if (ins->dreg != ins->sreg1) {
1279 ins->opcode = OP_MOVE;
1281 MONO_DELETE_INS (bb, ins);
1290 int cond_to_ia64_cmp [][3] = {
1291 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1292 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1293 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1294 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1295 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1296 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1297 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1298 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1299 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1300 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1304 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1306 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1309 int cond_to_ia64_cmp_imm [][3] = {
1310 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1311 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1312 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1313 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1314 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1315 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1316 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1317 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1318 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1319 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1323 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1325 /* The condition needs to be reversed */
1326 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1329 #define NEW_INS(cfg,ins,dest,op) do { \
1330 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1331 (dest)->opcode = (op); \
1332 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
1336 * mono_arch_lowering_pass:
1338 * Converts complex opcodes into simpler ones so that each IR instruction
1339 * corresponds to one machine instruction.
1342 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1344 MonoInst *ins, *n, *next, *temp, *temp2, *temp3;
1346 if (bb->max_vreg > cfg->rs->next_vreg)
1347 cfg->rs->next_vreg = bb->max_vreg;
1349 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1350 switch (ins->opcode) {
1351 case OP_STOREI1_MEMBASE_IMM:
1352 case OP_STOREI2_MEMBASE_IMM:
1353 case OP_STOREI4_MEMBASE_IMM:
1354 case OP_STOREI8_MEMBASE_IMM:
1355 case OP_STORE_MEMBASE_IMM:
1356 /* There are no store_membase instructions on ia64 */
1357 if (ins->inst_offset == 0) {
1359 } else if (ia64_is_imm14 (ins->inst_offset)) {
1360 NEW_INS (cfg, ins, temp2, OP_ADD_IMM);
1361 temp2->sreg1 = ins->inst_destbasereg;
1362 temp2->inst_imm = ins->inst_offset;
1363 temp2->dreg = mono_regstate_next_int (cfg->rs);
1366 NEW_INS (cfg, ins, temp, OP_I8CONST);
1367 temp->inst_c0 = ins->inst_offset;
1368 temp->dreg = mono_regstate_next_int (cfg->rs);
1369 NEW_INS (cfg, ins, temp2, OP_LADD);
1370 temp2->sreg1 = ins->inst_destbasereg;
1371 temp2->sreg2 = temp->dreg;
1372 temp2->dreg = mono_regstate_next_int (cfg->rs);
1375 switch (ins->opcode) {
1376 case OP_STOREI1_MEMBASE_IMM:
1377 ins->opcode = OP_STOREI1_MEMBASE_REG;
1379 case OP_STOREI2_MEMBASE_IMM:
1380 ins->opcode = OP_STOREI2_MEMBASE_REG;
1382 case OP_STOREI4_MEMBASE_IMM:
1383 ins->opcode = OP_STOREI4_MEMBASE_REG;
1385 case OP_STOREI8_MEMBASE_IMM:
1386 case OP_STORE_MEMBASE_IMM:
1387 ins->opcode = OP_STOREI8_MEMBASE_REG;
1390 g_assert_not_reached ();
1393 if (ins->inst_imm == 0)
1394 ins->sreg1 = IA64_R0;
1396 NEW_INS (cfg, ins, temp3, OP_I8CONST);
1397 temp3->inst_c0 = ins->inst_imm;
1398 temp3->dreg = mono_regstate_next_int (cfg->rs);
1399 ins->sreg1 = temp3->dreg;
1402 ins->inst_offset = 0;
1404 ins->inst_destbasereg = temp2->dreg;
1406 case OP_STOREI1_MEMBASE_REG:
1407 case OP_STOREI2_MEMBASE_REG:
1408 case OP_STOREI4_MEMBASE_REG:
1409 case OP_STOREI8_MEMBASE_REG:
1410 case OP_STORER4_MEMBASE_REG:
1411 case OP_STORER8_MEMBASE_REG:
1412 case OP_STORE_MEMBASE_REG:
1413 /* There are no store_membase instructions on ia64 */
1414 if (ins->inst_offset == 0) {
1417 else if (ia64_is_imm14 (ins->inst_offset)) {
1418 NEW_INS (cfg, ins, temp2, OP_ADD_IMM);
1419 temp2->sreg1 = ins->inst_destbasereg;
1420 temp2->inst_imm = ins->inst_offset;
1421 temp2->dreg = mono_regstate_next_int (cfg->rs);
1424 NEW_INS (cfg, ins, temp, OP_I8CONST);
1425 temp->inst_c0 = ins->inst_offset;
1426 temp->dreg = mono_regstate_next_int (cfg->rs);
1427 NEW_INS (cfg, ins, temp2, OP_LADD);
1428 temp2->sreg1 = ins->inst_destbasereg;
1429 temp2->sreg2 = temp->dreg;
1430 temp2->dreg = mono_regstate_next_int (cfg->rs);
1433 ins->inst_offset = 0;
1434 ins->inst_destbasereg = temp2->dreg;
1436 case OP_LOADI1_MEMBASE:
1437 case OP_LOADU1_MEMBASE:
1438 case OP_LOADI2_MEMBASE:
1439 case OP_LOADU2_MEMBASE:
1440 case OP_LOADI4_MEMBASE:
1441 case OP_LOADU4_MEMBASE:
1442 case OP_LOADI8_MEMBASE:
1443 case OP_LOAD_MEMBASE:
1444 case OP_LOADR4_MEMBASE:
1445 case OP_LOADR8_MEMBASE:
1446 case OP_ATOMIC_EXCHANGE_I4:
1447 case OP_ATOMIC_EXCHANGE_I8:
1448 case OP_ATOMIC_ADD_NEW_I4:
1449 case OP_ATOMIC_ADD_NEW_I8:
1450 case OP_ATOMIC_ADD_IMM_NEW_I4:
1451 case OP_ATOMIC_ADD_IMM_NEW_I8:
1452 /* There are no membase instructions on ia64 */
1453 if (ins->inst_offset == 0) {
1456 else if (ia64_is_imm14 (ins->inst_offset)) {
1457 NEW_INS (cfg, ins, temp2, OP_ADD_IMM);
1458 temp2->sreg1 = ins->inst_basereg;
1459 temp2->inst_imm = ins->inst_offset;
1460 temp2->dreg = mono_regstate_next_int (cfg->rs);
1463 NEW_INS (cfg, ins, temp, OP_I8CONST);
1464 temp->inst_c0 = ins->inst_offset;
1465 temp->dreg = mono_regstate_next_int (cfg->rs);
1466 NEW_INS (cfg, ins, temp2, OP_LADD);
1467 temp2->sreg1 = ins->inst_basereg;
1468 temp2->sreg2 = temp->dreg;
1469 temp2->dreg = mono_regstate_next_int (cfg->rs);
1472 ins->inst_offset = 0;
1473 ins->inst_basereg = temp2->dreg;
1493 case OP_ISHR_UN_IMM:
1494 case OP_LSHR_UN_IMM: {
1495 gboolean is_imm = FALSE;
1496 gboolean switched = FALSE;
1498 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1499 ins->opcode = OP_ZEXT_I1;
1503 switch (ins->opcode) {
1507 is_imm = ia64_is_imm14 (ins->inst_imm);
1512 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1514 /* A = B - IMM -> A = B + (-IMM) */
1515 ins->inst_imm = - ins->inst_imm;
1516 ins->opcode = OP_IADD_IMM;
1527 is_imm = ia64_is_imm8 (ins->inst_imm);
1536 case OP_ISHR_UN_IMM:
1537 case OP_LSHR_UN_IMM:
1538 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1546 ins->sreg2 = ins->sreg1;
1550 ins->opcode = mono_op_imm_to_op (ins->opcode);
1552 if (ins->inst_imm == 0)
1553 ins->sreg2 = IA64_R0;
1555 NEW_INS (cfg, ins, temp, OP_I8CONST);
1556 temp->inst_c0 = ins->inst_imm;
1557 temp->dreg = mono_regstate_next_int (cfg->rs);
1558 ins->sreg2 = temp->dreg;
1562 case OP_COMPARE_IMM:
1563 case OP_ICOMPARE_IMM: {
1564 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1569 * The compare_imm instructions have switched up arguments, and
1570 * some of them take an imm between -127 and 128.
1572 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1574 cond = mono_opcode_to_cond (next->opcode);
1575 if ((cond == CMP_LT) || (cond == CMP_GE))
1576 imm = ia64_is_imm8 (ins->inst_imm - 1);
1577 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1578 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1580 imm = ia64_is_imm8 (ins->inst_imm);
1583 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1584 ins->sreg2 = ins->sreg1;
1587 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1589 if (ins->inst_imm == 0)
1590 ins->sreg2 = IA64_R0;
1592 NEW_INS (cfg, ins, temp, OP_I8CONST);
1593 temp->inst_c0 = ins->inst_imm;
1594 temp->dreg = mono_regstate_next_int (cfg->rs);
1595 ins->sreg2 = temp->dreg;
1599 switch (next->opcode) {
1620 next->opcode = OP_IA64_BR_COND;
1621 if (! (next->flags & MONO_INST_BRLABEL))
1622 next->inst_target_bb = next->inst_true_bb;
1624 case OP_COND_EXC_EQ:
1625 case OP_COND_EXC_GT:
1626 case OP_COND_EXC_LT:
1627 case OP_COND_EXC_GT_UN:
1628 case OP_COND_EXC_LE_UN:
1629 case OP_COND_EXC_NE_UN:
1630 case OP_COND_EXC_LT_UN:
1631 next->opcode = OP_IA64_COND_EXC;
1643 next->opcode = OP_IA64_CSET;
1646 printf ("%s\n", mono_inst_name (next->opcode));
1656 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1658 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1661 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1662 switch (next->opcode) {
1693 next->opcode = OP_IA64_BR_COND;
1694 if (! (next->flags & MONO_INST_BRLABEL))
1695 next->inst_target_bb = next->inst_true_bb;
1697 case OP_COND_EXC_LT:
1698 case OP_COND_EXC_GT:
1699 case OP_COND_EXC_GT_UN:
1700 case OP_COND_EXC_LE_UN:
1701 next->opcode = OP_IA64_COND_EXC;
1718 next->opcode = OP_IA64_CSET;
1721 printf ("%s\n", mono_inst_name (next->opcode));
1730 gboolean found = FALSE;
1731 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1733 /* First the easy cases */
1734 if (ins->inst_imm == 1) {
1735 ins->opcode = OP_MOVE;
1738 for (i = 1; i < 64; ++i)
1739 if (ins->inst_imm == (((gint64)1) << i)) {
1740 ins->opcode = shl_op;
1746 /* This could be optimized */
1749 for (i = 0; i < 64; ++i) {
1750 if (ins->inst_imm & (((gint64)1) << i)) {
1751 NEW_INS (cfg, ins, temp, shl_op);
1752 temp->dreg = mono_regstate_next_int (cfg->rs);
1753 temp->sreg1 = ins->sreg1;
1757 sum_reg = temp->dreg;
1759 NEW_INS (cfg, ins, temp2, OP_LADD);
1760 temp2->dreg = mono_regstate_next_int (cfg->rs);
1761 temp2->sreg1 = sum_reg;
1762 temp2->sreg2 = temp->dreg;
1763 sum_reg = temp2->dreg;
1767 ins->opcode = OP_MOVE;
1768 ins->sreg1 = sum_reg;
1772 case OP_LCONV_TO_OVF_U4:
1773 NEW_INS (cfg, ins, temp, OP_IA64_CMP4_LT);
1774 temp->sreg1 = ins->sreg1;
1775 temp->sreg2 = IA64_R0;
1777 NEW_INS (cfg, ins, temp, OP_IA64_COND_EXC);
1778 temp->inst_p1 = (char*)"OverflowException";
1780 ins->opcode = OP_MOVE;
1782 case OP_LCONV_TO_OVF_I4_UN:
1783 NEW_INS (cfg, ins, temp, OP_ICONST);
1784 temp->inst_c0 = 0x7fffffff;
1785 temp->dreg = mono_regstate_next_int (cfg->rs);
1787 NEW_INS (cfg, ins, temp2, OP_IA64_CMP4_GT_UN);
1788 temp2->sreg1 = ins->sreg1;
1789 temp2->sreg2 = temp->dreg;
1791 NEW_INS (cfg, ins, temp, OP_IA64_COND_EXC);
1792 temp->inst_p1 = (char*)"OverflowException";
1794 ins->opcode = OP_MOVE;
1796 case OP_FCONV_TO_I4:
1797 case OP_FCONV_TO_I2:
1798 case OP_FCONV_TO_U2:
1799 case OP_FCONV_TO_I1:
1800 case OP_FCONV_TO_U1:
1801 NEW_INS (cfg, ins, temp, OP_FCONV_TO_I8);
1802 temp->sreg1 = ins->sreg1;
1803 temp->dreg = ins->dreg;
1805 switch (ins->opcode) {
1806 case OP_FCONV_TO_I4:
1807 ins->opcode = OP_SEXT_I4;
1809 case OP_FCONV_TO_I2:
1810 ins->opcode = OP_SEXT_I2;
1812 case OP_FCONV_TO_U2:
1813 ins->opcode = OP_ZEXT_I4;
1815 case OP_FCONV_TO_I1:
1816 ins->opcode = OP_SEXT_I1;
1818 case OP_FCONV_TO_U1:
1819 ins->opcode = OP_ZEXT_I1;
1822 g_assert_not_reached ();
1824 ins->sreg1 = ins->dreg;
1831 bb->max_vreg = cfg->rs->next_vreg;
1835 * emit_load_volatile_arguments:
1837 * Load volatile arguments from the stack to the original input registers.
1838 * Required before a tail call.
1840 static Ia64CodegenState
1841 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1843 MonoMethod *method = cfg->method;
1844 MonoMethodSignature *sig;
1849 /* FIXME: Generate intermediate code instead */
1851 sig = mono_method_signature (method);
1853 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
1855 /* This is the opposite of the code in emit_prolog */
1856 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1857 ArgInfo *ainfo = cinfo->args + i;
1858 gint32 stack_offset;
1860 ins = cfg->args [i];
1862 if (sig->hasthis && (i == 0))
1863 arg_type = &mono_defaults.object_class->byval_arg;
1865 arg_type = sig->params [i - sig->hasthis];
1867 arg_type = mono_type_get_underlying_type (arg_type);
1869 stack_offset = ainfo->offset + ARGS_OFFSET;
1871 /* Save volatile arguments to the stack */
1872 if (ins->opcode != OP_REGVAR) {
1873 switch (ainfo->storage) {
1876 /* FIXME: big offsets */
1877 g_assert (ins->opcode == OP_REGOFFSET);
1878 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1879 if (arg_type->byref)
1880 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1882 switch (arg_type->type) {
1884 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1887 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1890 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1902 if (ins->opcode == OP_REGVAR) {
1903 /* Argument allocated to (non-volatile) register */
1904 switch (ainfo->storage) {
1906 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1907 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1910 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1911 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1922 static Ia64CodegenState
1923 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1928 /* Move return value to the target register */
1929 switch (ins->opcode) {
1931 case OP_VOIDCALL_REG:
1932 case OP_VOIDCALL_MEMBASE:
1936 case OP_CALL_MEMBASE:
1939 case OP_LCALL_MEMBASE:
1940 g_assert (ins->dreg == IA64_R8);
1944 case OP_FCALL_MEMBASE:
1945 g_assert (ins->dreg == 8);
1949 case OP_VCALL_MEMBASE: {
1952 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
1953 storage = cinfo->ret.storage;
1955 if (storage == ArgAggregate) {
1956 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
1958 /* Load address of stack space allocated for the return value */
1959 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
1960 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
1961 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
1963 for (i = 0; i < cinfo->ret.nregs; ++i) {
1964 switch (cinfo->ret.atype) {
1965 case AggregateNormal:
1966 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1968 case AggregateSingleHFA:
1969 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
1971 case AggregateDoubleHFA:
1972 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1975 g_assert_not_reached ();
1982 g_assert_not_reached ();
1988 #define add_patch_info(cfg,code,patch_type,data) do { \
1989 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
1992 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
1993 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1995 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
1997 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
1998 ia64_br_cond_pred (code, (predicate), 0); \
2001 static Ia64CodegenState
2002 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2004 add_patch_info (cfg, code, patch_type, data);
2006 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2008 /* mono_arch_patch_callsite will patch this */
2009 /* mono_arch_nullify_class_init_trampoline will patch this */
2010 ia64_movl (code, GP_SCRATCH_REG, 0);
2011 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2012 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2013 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2014 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2017 /* Can't use a direct call since the displacement might be too small */
2018 /* mono_arch_patch_callsite will patch this */
2019 ia64_movl (code, GP_SCRATCH_REG, 0);
2020 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2021 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2027 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2030 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2035 Ia64CodegenState code;
2036 guint8 *code_start = cfg->native_code + cfg->code_len;
2037 guint last_offset = 0;
2040 if (cfg->opt & MONO_OPT_LOOP) {
2044 if (cfg->verbose_level > 2)
2045 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2047 cpos = bb->max_offset;
2049 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2053 offset = code_start - cfg->native_code;
2055 ia64_codegen_init (code, code_start);
2058 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2062 MONO_BB_FOR_EACH_INS (bb, ins) {
2063 offset = code.buf - cfg->native_code;
2065 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2067 while (offset + max_len + 16 > cfg->code_size) {
2068 ia64_codegen_close (code);
2070 offset = code.buf - cfg->native_code;
2072 cfg->code_size *= 2;
2073 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2074 code_start = cfg->native_code + offset;
2075 mono_jit_stats.code_reallocs++;
2077 ia64_codegen_init (code, code_start);
2080 mono_debug_record_line_number (cfg, ins, offset);
2082 switch (ins->opcode) {
2085 if (ia64_is_imm14 (ins->inst_c0))
2086 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2088 ia64_movl (code, ins->dreg, ins->inst_c0);
2091 ia64_mov (code, ins->dreg, ins->sreg1);
2094 case OP_IA64_BR_COND: {
2096 if (ins->opcode == OP_IA64_BR_COND)
2098 if (ins->flags & MONO_INST_BRLABEL) {
2099 if (ins->inst_i0->inst_c0) {
2102 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2103 ia64_br_cond_pred (code, pred, 0);
2106 if (ins->inst_target_bb->native_offset) {
2107 guint8 *pos = code.buf + code.nins;
2109 ia64_br_cond_pred (code, pred, 0);
2110 ia64_begin_bundle (code);
2111 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2113 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2114 ia64_br_cond_pred (code, pred, 0);
2120 ia64_begin_bundle (code);
2121 ins->inst_c0 = code.buf - cfg->native_code;
2126 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2127 ia64_br_cond_reg (code, IA64_B6);
2131 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2135 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2139 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2143 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2147 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2151 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2154 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2158 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2161 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2162 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2165 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2168 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2172 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2175 /* p6 and p7 is set if there is signed/unsigned overflow */
2177 /* Set p8-p9 == (sreg2 > 0) */
2178 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2180 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2182 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2183 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2184 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2185 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2187 /* res <u sreg1 => unsigned overflow */
2188 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2190 /* FIXME: Predicate this since this is a side effect */
2191 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2194 /* p6 and p7 is set if there is signed/unsigned overflow */
2196 /* Set p8-p9 == (sreg2 > 0) */
2197 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2199 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2201 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2202 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2203 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2204 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2206 /* sreg1 <u sreg2 => unsigned overflow */
2207 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2209 /* FIXME: Predicate this since this is a side effect */
2210 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2213 /* Same as OP_IADDCC */
2214 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2216 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2218 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2219 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2221 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2223 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2226 /* Same as OP_ISUBCC */
2228 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2230 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2232 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2233 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2235 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2237 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2241 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2245 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2248 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2251 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2256 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2261 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2263 case OP_ISHR_UN_IMM:
2264 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2265 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2267 case OP_LSHR_UN_IMM:
2268 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2271 /* Based on gcc code */
2272 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2273 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2274 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2275 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2278 case OP_STOREI1_MEMBASE_REG:
2279 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2281 case OP_STOREI2_MEMBASE_REG:
2282 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2284 case OP_STOREI4_MEMBASE_REG:
2285 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2287 case OP_STOREI8_MEMBASE_REG:
2288 case OP_STORE_MEMBASE_REG:
2289 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2292 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2293 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2295 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2296 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2298 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2299 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2301 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2302 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2305 case OP_LOADU1_MEMBASE:
2306 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2308 case OP_LOADU2_MEMBASE:
2309 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2311 case OP_LOADU4_MEMBASE:
2312 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2314 case OP_LOADI1_MEMBASE:
2315 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2316 ia64_sxt1 (code, ins->dreg, ins->dreg);
2318 case OP_LOADI2_MEMBASE:
2319 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2320 ia64_sxt2 (code, ins->dreg, ins->dreg);
2322 case OP_LOADI4_MEMBASE:
2323 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2324 ia64_sxt4 (code, ins->dreg, ins->dreg);
2326 case OP_LOAD_MEMBASE:
2327 case OP_LOADI8_MEMBASE:
2328 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2331 case OP_IA64_LOADU1_MEMBASE_INC:
2332 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2334 case OP_IA64_LOADU2_MEMBASE_INC:
2335 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2337 case OP_IA64_LOADU4_MEMBASE_INC:
2338 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2340 case OP_IA64_LOADI8_MEMBASE_INC:
2341 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2345 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2348 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2351 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2354 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2357 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2360 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2363 /* Compare opcodes */
2364 case OP_IA64_CMP4_EQ:
2365 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2367 case OP_IA64_CMP4_NE:
2368 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2370 case OP_IA64_CMP4_LE:
2371 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2373 case OP_IA64_CMP4_LT:
2374 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2376 case OP_IA64_CMP4_GE:
2377 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2379 case OP_IA64_CMP4_GT:
2380 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2382 case OP_IA64_CMP4_LT_UN:
2383 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2385 case OP_IA64_CMP4_LE_UN:
2386 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2388 case OP_IA64_CMP4_GT_UN:
2389 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2391 case OP_IA64_CMP4_GE_UN:
2392 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2394 case OP_IA64_CMP_EQ:
2395 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2397 case OP_IA64_CMP_NE:
2398 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2400 case OP_IA64_CMP_LE:
2401 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2403 case OP_IA64_CMP_LT:
2404 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2406 case OP_IA64_CMP_GE:
2407 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2409 case OP_IA64_CMP_GT:
2410 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2412 case OP_IA64_CMP_GT_UN:
2413 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2415 case OP_IA64_CMP_LT_UN:
2416 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2418 case OP_IA64_CMP_GE_UN:
2419 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2421 case OP_IA64_CMP_LE_UN:
2422 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2424 case OP_IA64_CMP4_EQ_IMM:
2425 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2427 case OP_IA64_CMP4_NE_IMM:
2428 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2430 case OP_IA64_CMP4_LE_IMM:
2431 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2433 case OP_IA64_CMP4_LT_IMM:
2434 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2436 case OP_IA64_CMP4_GE_IMM:
2437 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2439 case OP_IA64_CMP4_GT_IMM:
2440 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2442 case OP_IA64_CMP4_LT_UN_IMM:
2443 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2445 case OP_IA64_CMP4_LE_UN_IMM:
2446 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2448 case OP_IA64_CMP4_GT_UN_IMM:
2449 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2451 case OP_IA64_CMP4_GE_UN_IMM:
2452 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2454 case OP_IA64_CMP_EQ_IMM:
2455 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2457 case OP_IA64_CMP_NE_IMM:
2458 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2460 case OP_IA64_CMP_LE_IMM:
2461 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2463 case OP_IA64_CMP_LT_IMM:
2464 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2466 case OP_IA64_CMP_GE_IMM:
2467 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2469 case OP_IA64_CMP_GT_IMM:
2470 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2472 case OP_IA64_CMP_GT_UN_IMM:
2473 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2475 case OP_IA64_CMP_LT_UN_IMM:
2476 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2478 case OP_IA64_CMP_GE_UN_IMM:
2479 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2481 case OP_IA64_CMP_LE_UN_IMM:
2482 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2484 case OP_IA64_FCMP_EQ:
2485 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2487 case OP_IA64_FCMP_NE:
2488 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2490 case OP_IA64_FCMP_LT:
2491 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2493 case OP_IA64_FCMP_GT:
2494 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2496 case OP_IA64_FCMP_LE:
2497 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2499 case OP_IA64_FCMP_GE:
2500 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2502 case OP_IA64_FCMP_GT_UN:
2503 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2504 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2506 case OP_IA64_FCMP_LT_UN:
2507 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2508 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2510 case OP_IA64_FCMP_GE_UN:
2511 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2512 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2514 case OP_IA64_FCMP_LE_UN:
2515 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2516 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2519 case OP_COND_EXC_IOV:
2520 case OP_COND_EXC_OV:
2521 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2523 case OP_COND_EXC_IC:
2525 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2527 case OP_IA64_COND_EXC:
2528 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2531 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2532 ia64_no_stop (code);
2533 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2535 case OP_LCONV_TO_I1:
2536 /* FIXME: Is this needed ? */
2537 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2539 case OP_LCONV_TO_I2:
2540 /* FIXME: Is this needed ? */
2541 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2543 case OP_LCONV_TO_I4:
2544 /* FIXME: Is this needed ? */
2545 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2547 case OP_LCONV_TO_U1:
2548 /* FIXME: Is this needed */
2549 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2551 case OP_LCONV_TO_U2:
2552 /* FIXME: Is this needed */
2553 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2555 case OP_LCONV_TO_U4:
2556 /* FIXME: Is this needed */
2557 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2559 case OP_LCONV_TO_I8:
2561 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2563 case OP_LCONV_TO_U8:
2565 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2572 double d = *(double *)ins->inst_p0;
2574 if ((d == 0.0) && (mono_signbit (d) == 0))
2575 ia64_fmov (code, ins->dreg, 0);
2577 ia64_fmov (code, ins->dreg, 1);
2579 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2580 ia64_movl (code, GP_SCRATCH_REG, 0);
2581 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2586 float f = *(float *)ins->inst_p0;
2588 if ((f == 0.0) && (mono_signbit (f) == 0))
2589 ia64_fmov (code, ins->dreg, 0);
2591 ia64_fmov (code, ins->dreg, 1);
2593 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2594 ia64_movl (code, GP_SCRATCH_REG, 0);
2595 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2600 ia64_fmov (code, ins->dreg, ins->sreg1);
2602 case OP_STORER8_MEMBASE_REG:
2603 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2605 case OP_STORER4_MEMBASE_REG:
2606 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2607 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2609 case OP_LOADR8_MEMBASE:
2610 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2612 case OP_LOADR4_MEMBASE:
2613 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2614 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2616 case OP_LCONV_TO_R4:
2617 case OP_ICONV_TO_R4:
2618 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2619 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2620 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2622 case OP_LCONV_TO_R8:
2623 case OP_ICONV_TO_R8:
2624 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2625 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2626 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2628 case OP_FCONV_TO_R4:
2629 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2631 case OP_FCONV_TO_I8:
2632 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2633 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2636 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2639 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2642 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2645 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2649 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2650 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2652 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2653 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2654 /* Positive infinity */
2655 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2656 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2657 /* Negative infinity */
2658 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2659 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2664 /* ensure ins->sreg1 is not NULL */
2665 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2668 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2669 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2676 call = (MonoCallInst*)ins;
2678 if (ins->flags & MONO_INST_HAS_METHOD)
2679 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2681 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2683 code = emit_move_return_value (cfg, ins, code);
2690 case OP_VOIDCALL_REG: {
2691 MonoCallInst *call = (MonoCallInst*)ins;
2696 * mono_arch_find_this_arg () needs to find the this argument in a global
2699 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2700 out_reg = cfg->arch.reg_out0;
2701 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
2703 ia64_mov (code, IA64_R10, out_reg);
2706 ia64_mov (code, IA64_R8, ins->sreg1);
2707 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2708 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2709 ia64_ld8 (code, IA64_GP, IA64_R8);
2710 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2712 code = emit_move_return_value (cfg, ins, code);
2715 case OP_FCALL_MEMBASE:
2716 case OP_LCALL_MEMBASE:
2717 case OP_VCALL_MEMBASE:
2718 case OP_VOIDCALL_MEMBASE:
2719 case OP_CALL_MEMBASE: {
2720 MonoCallInst *call = (MonoCallInst*)ins;
2725 * There are no membase instructions on ia64, but we can't
2726 * lower this since get_vcall_slot_addr () needs to decode it.
2729 /* Keep this in synch with get_vcall_slot_addr */
2730 ia64_mov (code, IA64_R11, ins->sreg1);
2731 if (ia64_is_imm14 (ins->inst_offset))
2732 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2734 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2735 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2738 if (call->method && ins->inst_offset < 0) {
2740 * This is a possible IMT call so save the IMT method in a global
2741 * register where mono_arch_find_imt_method () and its friends can
2744 ia64_movl (code, IA64_R9, call->method);
2748 * mono_arch_find_this_arg () needs to find the this argument in a global
2751 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2752 out_reg = cfg->arch.reg_out0;
2753 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
2755 ia64_mov (code, IA64_R10, out_reg);
2757 ia64_begin_bundle (code);
2758 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2760 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2762 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2765 * This nop will tell get_vcall_slot_addr that this is a virtual
2768 ia64_nop_i (code, 0x12345);
2770 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2772 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2774 code = emit_move_return_value (cfg, ins, code);
2779 * Keep in sync with the code in emit_epilog.
2782 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2785 g_assert (!cfg->method->save_lmf);
2787 /* Load arguments into their original registers */
2788 code = emit_load_volatile_arguments (cfg, code);
2790 if (cfg->arch.stack_alloc_size) {
2791 if (cfg->arch.omit_fp) {
2792 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2793 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2795 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2796 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2800 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2802 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2803 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2805 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2806 ia64_movl (code, GP_SCRATCH_REG, 0);
2807 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2808 ia64_br_cond_reg (code, IA64_B6);
2813 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
2819 /* FIXME: Sigaltstack support */
2821 /* keep alignment */
2822 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2823 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2824 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2826 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2828 ia64_mov (code, ins->dreg, IA64_SP);
2830 /* An area at sp is reserved by the ABI for parameter passing */
2831 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2832 if (ia64_is_adds_imm (abi_offset))
2833 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2835 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2836 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2839 if (ins->flags & MONO_INST_INIT) {
2841 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2843 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2846 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2847 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2848 ia64_br_cond_pred (code, 8, -2);
2850 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2852 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2858 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2859 ia64_ld8 (code, ins->dreg, ins->dreg);
2862 /* Synchronization */
2863 case OP_MEMORY_BARRIER:
2866 case OP_ATOMIC_ADD_IMM_NEW_I4:
2867 g_assert (ins->inst_offset == 0);
2868 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2869 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2871 case OP_ATOMIC_ADD_IMM_NEW_I8:
2872 g_assert (ins->inst_offset == 0);
2873 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2874 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2876 case OP_ATOMIC_EXCHANGE_I4:
2877 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2878 ia64_sxt4 (code, ins->dreg, ins->dreg);
2880 case OP_ATOMIC_EXCHANGE_I8:
2881 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2883 case OP_ATOMIC_ADD_NEW_I4: {
2884 guint8 *label, *buf;
2886 /* From libatomic_ops */
2889 ia64_begin_bundle (code);
2890 label = code.buf + code.nins;
2891 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2892 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2893 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2894 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2895 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2896 buf = code.buf + code.nins;
2897 ia64_br_cond_pred (code, 7, 0);
2898 ia64_begin_bundle (code);
2899 ia64_patch (buf, label);
2900 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2903 case OP_ATOMIC_ADD_NEW_I8: {
2904 guint8 *label, *buf;
2906 /* From libatomic_ops */
2909 ia64_begin_bundle (code);
2910 label = code.buf + code.nins;
2911 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2912 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2913 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2914 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2915 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2916 buf = code.buf + code.nins;
2917 ia64_br_cond_pred (code, 7, 0);
2918 ia64_begin_bundle (code);
2919 ia64_patch (buf, label);
2920 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2924 /* Exception handling */
2925 case OP_CALL_HANDLER:
2927 * Using a call instruction would mess up the register stack, so
2928 * save the return address to a register and use a
2931 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2932 ia64_mov (code, IA64_R15, IA64_R0);
2933 ia64_mov_from_ip (code, GP_SCRATCH_REG);
2934 /* Add the length of OP_CALL_HANDLER */
2935 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
2936 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2937 ia64_movl (code, GP_SCRATCH_REG2, 0);
2938 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2939 ia64_br_cond_reg (code, IA64_B6);
2940 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2942 case OP_START_HANDLER: {
2944 * We receive the return address in GP_SCRATCH_REG.
2946 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2949 * R15 determines our caller. It is used since it is writable using
2951 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
2952 * R15 != 0 means we are called by call_filter ().
2954 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2955 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
2957 ia64_br_cond_pred (code, 6, 6);
2960 * Called by call_filter:
2961 * Allocate a new stack frame, and set the fp register from the
2962 * value passed in by the caller.
2963 * We allocate a similar frame as is done by the prolog, so
2964 * if an exception is thrown while executing the filter, the
2965 * unwinder can unwind through the filter frame using the unwind
2966 * info for the prolog.
2968 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);
2969 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
2970 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
2971 ia64_mov (code, cfg->frame_reg, IA64_R15);
2972 /* Signal to endfilter that we are called by call_filter */
2973 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
2975 /* Save the return address */
2976 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
2977 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
2978 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2983 case OP_ENDFILTER: {
2984 /* FIXME: Return the value in ENDFILTER */
2985 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2987 /* Load the return address */
2988 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
2989 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
2992 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
2993 ia64_br_cond_pred (code, 7, 4);
2995 /* Called by call_filter */
2997 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2998 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2999 ia64_br_ret_reg (code, IA64_B0);
3001 /* Called by CALL_HANDLER */
3002 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3003 ia64_br_cond_reg (code, IA64_B6);
3007 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3008 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3009 (gpointer)"mono_arch_throw_exception");
3012 * This might be the last instruction in the method, so add a dummy
3013 * instruction so the unwinder will work.
3015 ia64_break_i (code, 0);
3018 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3019 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3020 (gpointer)"mono_arch_rethrow_exception");
3022 ia64_break_i (code, 0);
3026 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3027 g_assert_not_reached ();
3030 if ((code.buf - cfg->native_code - offset) > max_len) {
3031 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3032 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3033 g_assert_not_reached ();
3038 last_offset = offset;
3041 ia64_codegen_close (code);
3043 cfg->code_len = code.buf - cfg->native_code;
3047 mono_arch_register_lowlevel_calls (void)
3051 static Ia64InsType ins_types_in_template [32][3] = {
3052 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3053 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3054 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3055 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3056 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3057 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3060 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3061 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3062 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3063 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3064 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3065 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3066 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3067 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3068 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3069 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3070 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3071 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3074 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3075 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3076 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3077 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3080 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3081 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3086 static gboolean stops_in_template [32][3] = {
3087 { FALSE, FALSE, FALSE },
3088 { FALSE, FALSE, TRUE },
3089 { FALSE, TRUE, FALSE },
3090 { FALSE, TRUE, TRUE },
3091 { FALSE, FALSE, FALSE },
3092 { FALSE, FALSE, TRUE },
3093 { FALSE, FALSE, FALSE },
3094 { FALSE, FALSE, FALSE },
3096 { FALSE, FALSE, FALSE },
3097 { FALSE, FALSE, TRUE },
3098 { TRUE, FALSE, FALSE },
3099 { TRUE, FALSE, TRUE },
3100 { FALSE, FALSE, FALSE },
3101 { FALSE, FALSE, TRUE },
3102 { FALSE, FALSE, FALSE },
3103 { FALSE, FALSE, TRUE },
3105 { FALSE, FALSE, FALSE },
3106 { FALSE, FALSE, TRUE },
3107 { FALSE, FALSE, FALSE },
3108 { FALSE, FALSE, TRUE },
3109 { FALSE, FALSE, FALSE },
3110 { FALSE, FALSE, FALSE },
3111 { FALSE, FALSE, FALSE },
3112 { FALSE, FALSE, TRUE },
3114 { FALSE, FALSE, FALSE },
3115 { FALSE, FALSE, TRUE },
3116 { FALSE, FALSE, FALSE },
3117 { FALSE, FALSE, FALSE },
3118 { FALSE, FALSE, FALSE },
3119 { FALSE, FALSE, TRUE },
3120 { FALSE, FALSE, FALSE },
3121 { FALSE, FALSE, FALSE }
3124 static int last_stop_in_template [32] = {
3125 -1, 2, 1, 2, -1, 2, -1, -1,
3126 -1, 2, 0, 2, -1, 2, -1, 2,
3127 -1, 2, -1, 2, -1, -1, -1, 2,
3128 -1, 2, -1, -1, -1, 2, -1, -1
3131 static guint64 nops_for_ins_types [6] = {
3140 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3147 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3149 #define DEBUG_INS_SCHED(a)
3153 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3155 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3156 guint8 *deps = code->dep_info;
3157 gboolean need_stop, no_stop;
3159 for (i = 0; i < code->nins; ++i)
3163 current_deps_start = 0;
3164 current_ins_start = 0;
3165 deps_start [ins_index] = current_ins_start;
3168 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3169 while (pos < code->dep_info_pos) {
3171 switch (deps [pos]) {
3172 case IA64_END_OF_INS:
3174 current_ins_start = pos + 2;
3175 deps_start [ins_index] = current_ins_start;
3177 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3182 reg = deps [pos + 1];
3184 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3185 for (i = current_deps_start; i < current_ins_start; i += 2)
3186 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3190 reg = code->dep_info [pos + 1];
3192 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3193 for (i = current_deps_start; i < current_ins_start; i += 2)
3194 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3198 reg = deps [pos + 1];
3200 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3201 for (i = current_deps_start; i < current_ins_start; i += 2)
3202 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3205 case IA64_READ_PR_BRANCH:
3206 reg = deps [pos + 1];
3208 /* Writes to prs by non-float instructions are visible to branches */
3209 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3210 for (i = current_deps_start; i < current_ins_start; i += 2)
3211 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3215 reg = code->dep_info [pos + 1];
3217 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3218 for (i = current_deps_start; i < current_ins_start; i += 2)
3219 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3222 case IA64_WRITE_PR_FLOAT:
3223 reg = code->dep_info [pos + 1];
3225 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3226 for (i = current_deps_start; i < current_ins_start; i += 2)
3227 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3231 reg = deps [pos + 1];
3233 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3234 for (i = current_deps_start; i < current_ins_start; i += 2)
3235 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3239 reg = code->dep_info [pos + 1];
3241 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3242 for (i = current_deps_start; i < current_ins_start; i += 2)
3243 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3246 case IA64_READ_BR_BRANCH:
3247 reg = deps [pos + 1];
3249 /* Writes to brs are visible to branches */
3250 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3253 reg = deps [pos + 1];
3255 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3256 for (i = current_deps_start; i < current_ins_start; i += 2)
3257 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3261 reg = code->dep_info [pos + 1];
3263 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3264 for (i = current_deps_start; i < current_ins_start; i += 2)
3265 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3269 reg = deps [pos + 1];
3271 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3272 for (i = current_deps_start; i < current_ins_start; i += 2)
3273 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3277 reg = code->dep_info [pos + 1];
3279 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3280 for (i = current_deps_start; i < current_ins_start; i += 2)
3281 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3286 * Explicitly indicate that a stop is not required. Useful for
3287 * example when two predicated instructions with negated predicates
3288 * write the same registers.
3293 g_assert_not_reached ();
3297 if (need_stop && !no_stop) {
3298 g_assert (ins_index > 0);
3299 stops [ins_index - 1] = 1;
3301 DEBUG_INS_SCHED (printf ("STOP\n"));
3302 current_deps_start = current_ins_start;
3304 /* Skip remaining deps for this instruction */
3305 while (deps [pos] != IA64_END_OF_INS)
3310 if (code->nins > 0) {
3311 /* No dependency info for the last instruction */
3312 stops [code->nins - 1] = 1;
3315 deps_start [code->nins] = code->dep_info_pos;
3319 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3321 int stop_pos, i, deps_to_shift, dep_shift;
3323 g_assert (n <= code->nins);
3325 // if (n > 1) printf ("FOUND: %ld.\n", template);
3327 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3329 stop_pos = last_stop_in_template [template] + 1;
3333 /* Compute the number of 'real' instructions before the stop */
3334 deps_to_shift = stop_pos;
3335 if (stop_pos >= 3 && (nops & (1 << 2)))
3337 if (stop_pos >= 2 && (nops & (1 << 1)))
3339 if (stop_pos >= 1 && (nops & (1 << 0)))
3343 * We have to keep some dependencies whose instructions have been shifted
3344 * out of the buffer. So nullify the end_of_ins markers in the dependency
3347 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3348 if (code->dep_info [i] == IA64_END_OF_INS)
3349 code->dep_info [i] = IA64_NONE;
3351 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3352 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3353 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3355 dep_shift = deps_start [deps_to_shift];
3356 for (i = 0; i < code->nins + 1 - n; ++i)
3357 deps_start [i] = deps_start [n + i] - dep_shift;
3359 /* Determine the exact positions of instructions with unwind ops */
3360 if (code->unw_op_count) {
3362 int curr_ins, curr_ins_pos;
3365 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3366 for (i = 0; i < 3; ++i) {
3367 if (! (nops & (1 << i))) {
3368 ins_pos [curr_ins] = curr_ins_pos + i;
3373 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3374 if (code->unw_ops_pos [i] < n) {
3375 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3376 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3379 if (code->unw_op_pos < code->unw_op_count)
3380 code->unw_op_pos += n;
3383 if (n == code->nins) {
3388 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3389 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3390 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3396 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3398 int i, ins_type, template, nins_to_emit;
3399 int deps_start [16];
3404 * We implement a simple scheduler which tries to put three instructions
3405 * per bundle, then two, then one.
3407 ia64_analyze_deps (code, deps_start, stops);
3409 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3410 /* Find a suitable template */
3411 for (template = 0; template < 32; ++template) {
3412 if (stops_in_template [template][0] != stops [0] ||
3413 stops_in_template [template][1] != stops [1] ||
3414 stops_in_template [template][2] != stops [2])
3418 for (i = 0; i < 3; ++i) {
3419 ins_type = ins_types_in_template [template][i];
3420 switch (code->itypes [i]) {
3421 case IA64_INS_TYPE_A:
3422 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3425 found &= (ins_type == code->itypes [i]);
3431 found = debug_ins_sched ();
3434 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3440 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3441 /* Wait for more instructions */
3444 /* If it didn't work out, try putting two instructions into one bundle */
3445 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3446 /* Try a nop at the end */
3447 for (template = 0; template < 32; ++template) {
3448 if (stops_in_template [template][0] != stops [0] ||
3449 ((stops_in_template [template][1] != stops [1]) &&
3450 (stops_in_template [template][2] != stops [1])))
3454 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3455 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3458 if (!debug_ins_sched ())
3461 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);
3466 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3467 /* Wait for more instructions */
3470 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3471 /* Try a nop in the middle */
3472 for (template = 0; template < 32; ++template) {
3473 if (((stops_in_template [template][0] != stops [0]) &&
3474 (stops_in_template [template][1] != stops [0])) ||
3475 stops_in_template [template][2] != stops [1])
3478 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3479 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3482 if (!debug_ins_sched ())
3485 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);
3490 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3491 /* Try a nop at the beginning */
3492 for (template = 0; template < 32; ++template) {
3493 if ((stops_in_template [template][1] != stops [0]) ||
3494 (stops_in_template [template][2] != stops [1]))
3497 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3498 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3501 if (!debug_ins_sched ())
3504 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);
3509 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3510 /* Wait for more instructions */
3514 nins_to_emit = code->nins;
3518 while (nins_to_emit > 0) {
3519 if (!debug_ins_sched ())
3521 switch (code->itypes [0]) {
3522 case IA64_INS_TYPE_A:
3524 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3526 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3528 case IA64_INS_TYPE_I:
3530 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3532 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3534 case IA64_INS_TYPE_M:
3536 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3538 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3540 case IA64_INS_TYPE_B:
3542 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3544 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3546 case IA64_INS_TYPE_F:
3548 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3550 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3552 case IA64_INS_TYPE_LX:
3553 if (stops [0] || stops [1])
3554 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3556 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3560 g_assert_not_reached ();
3566 unw_dyn_region_info_t*
3567 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3569 unw_dyn_region_info_t *r;
3571 g_assert (code->nins == 0);
3572 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3573 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3574 r->op_count = code->unw_op_count;
3575 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3576 code->unw_op_count = 0;
3577 code->unw_op_pos = 0;
3578 code->region_start = code->buf;
3584 ia64_patch (unsigned char* code, gpointer target)
3587 guint64 instructions [3];
3588 guint8 gen_buf [16];
3589 Ia64CodegenState gen;
3594 * code encodes both the position inside the buffer and code.nins when
3595 * the instruction was emitted.
3597 ins_to_skip = (guint64)code % 16;
3598 code = (unsigned char*)((guint64)code & ~15);
3601 * Search for the first instruction which is 'patchable', skipping
3602 * ins_to_skip instructions.
3607 template = ia64_bundle_template (code);
3608 instructions [0] = ia64_bundle_ins1 (code);
3609 instructions [1] = ia64_bundle_ins2 (code);
3610 instructions [2] = ia64_bundle_ins3 (code);
3612 ia64_codegen_init (gen, gen_buf);
3615 for (i = 0; i < 3; ++i) {
3616 guint64 ins = instructions [i];
3617 int opcode = ia64_ins_opcode (ins);
3619 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3627 switch (ins_types_in_template [template][i]) {
3628 case IA64_INS_TYPE_A:
3629 case IA64_INS_TYPE_M:
3630 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3632 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3633 instructions [i] = gen.instructions [0];
3639 case IA64_INS_TYPE_B:
3640 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3642 gint64 disp = ((guint8*)target - code) >> 4;
3645 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3647 instructions [i] = gen.instructions [0];
3650 else if (opcode == 5) {
3652 gint64 disp = ((guint8*)target - code) >> 4;
3655 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3656 instructions [i] = gen.instructions [0];
3662 case IA64_INS_TYPE_LX:
3666 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3668 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3669 instructions [1] = gen.instructions [0];
3670 instructions [2] = gen.instructions [1];
3683 ia64_codegen_init (gen, code);
3684 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3694 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3696 MonoJumpInfo *patch_info;
3698 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3699 unsigned char *ip = patch_info->ip.i + code;
3700 const unsigned char *target;
3702 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3704 if (patch_info->type == MONO_PATCH_INFO_NONE)
3706 if (mono_compile_aot) {
3710 ia64_patch (ip, (gpointer)target);
3715 mono_arch_emit_prolog (MonoCompile *cfg)
3717 MonoMethod *method = cfg->method;
3718 MonoMethodSignature *sig;
3720 int alloc_size, pos, i;
3721 Ia64CodegenState code;
3724 sig = mono_method_signature (method);
3727 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
3729 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3731 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3732 cfg->code_size += 1024;
3733 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3734 cfg->code_size += 1024;
3736 cfg->native_code = g_malloc (cfg->code_size);
3738 ia64_codegen_init (code, cfg->native_code);
3740 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3741 if (cfg->param_area)
3742 alloc_size += cfg->param_area;
3746 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3748 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3749 /* Force sp to be saved/restored */
3750 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3752 cfg->arch.stack_alloc_size = alloc_size;
3756 if (method->save_lmf) {
3757 /* No LMF on IA64 */
3762 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3763 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);
3764 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3765 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3767 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3768 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3769 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3770 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3771 ia64_mov (code, cfg->frame_reg, IA64_SP);
3775 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3776 int pagesize = getpagesize ();
3778 if (alloc_size >= pagesize) {
3779 gint32 remaining_size = alloc_size;
3781 /* Generate stack touching code */
3782 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3783 while (remaining_size >= pagesize) {
3784 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3785 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3786 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3787 remaining_size -= pagesize;
3791 if (ia64_is_imm14 (-alloc_size)) {
3792 if (cfg->arch.omit_fp)
3793 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3794 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3797 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3798 if (cfg->arch.omit_fp)
3799 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3800 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3804 ia64_begin_bundle (code);
3806 /* Initialize unwind info */
3807 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3809 if (sig->ret->type != MONO_TYPE_VOID) {
3810 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3811 /* Save volatile arguments to the stack */
3816 /* Keep this in sync with emit_load_volatile_arguments */
3817 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3818 ArgInfo *ainfo = cinfo->args + i;
3819 gint32 stack_offset;
3821 inst = cfg->args [i];
3823 if (sig->hasthis && (i == 0))
3824 arg_type = &mono_defaults.object_class->byval_arg;
3826 arg_type = sig->params [i - sig->hasthis];
3828 arg_type = mono_type_get_underlying_type (arg_type);
3830 stack_offset = ainfo->offset + ARGS_OFFSET;
3832 /* Save volatile arguments to the stack */
3833 if (inst->opcode != OP_REGVAR) {
3834 switch (ainfo->storage) {
3837 case ArgInFloatRegR4:
3838 g_assert (inst->opcode == OP_REGOFFSET);
3839 if (ia64_is_adds_imm (inst->inst_offset))
3840 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3842 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3843 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3845 if (arg_type->byref)
3846 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3848 switch (arg_type->type) {
3850 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3853 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3856 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3864 if (ainfo->nslots != ainfo->nregs)
3867 g_assert (inst->opcode == OP_REGOFFSET);
3868 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3869 for (i = 0; i < ainfo->nregs; ++i) {
3870 switch (ainfo->atype) {
3871 case AggregateNormal:
3872 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3874 case AggregateSingleHFA:
3875 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3877 case AggregateDoubleHFA:
3878 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3886 g_assert_not_reached ();
3890 if (inst->opcode == OP_REGVAR) {
3891 /* Argument allocated to (non-volatile) register */
3892 switch (ainfo->storage) {
3894 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3895 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3898 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3899 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3907 if (method->save_lmf) {
3908 /* No LMF on IA64 */
3911 ia64_codegen_close (code);
3913 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3914 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
3916 cfg->code_len = code.buf - cfg->native_code;
3918 g_assert (cfg->code_len < cfg->code_size);
3920 cfg->arch.prolog_end_offset = cfg->code_len;
3926 mono_arch_emit_epilog (MonoCompile *cfg)
3928 MonoMethod *method = cfg->method;
3930 int max_epilog_size = 16 * 4;
3931 Ia64CodegenState code;
3936 if (mono_jit_trace_calls != NULL)
3937 max_epilog_size += 1024;
3939 cfg->arch.epilog_begin_offset = cfg->code_len;
3941 while (cfg->code_len + max_epilog_size > cfg->code_size) {
3942 cfg->code_size *= 2;
3943 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3944 mono_jit_stats.code_reallocs++;
3947 /* FIXME: Emit unwind info */
3949 buf = cfg->native_code + cfg->code_len;
3951 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3952 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
3954 ia64_codegen_init (code, buf);
3956 /* the code restoring the registers must be kept in sync with OP_JMP */
3959 if (method->save_lmf) {
3960 /* No LMF on IA64 */
3963 /* Load returned vtypes into registers if needed */
3964 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
3965 ainfo = &cinfo->ret;
3966 switch (ainfo->storage) {
3968 if (ainfo->nslots != ainfo->nregs)
3971 g_assert (cfg->ret->opcode == OP_REGOFFSET);
3972 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
3973 for (i = 0; i < ainfo->nregs; ++i) {
3974 switch (ainfo->atype) {
3975 case AggregateNormal:
3976 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
3978 case AggregateSingleHFA:
3979 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
3981 case AggregateDoubleHFA:
3982 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
3985 g_assert_not_reached ();
3993 ia64_begin_bundle (code);
3995 code.region_start = cfg->native_code;
3997 /* Label the unwind state at the start of the exception throwing region */
3998 //ia64_unw_label_state (code, 1234);
4000 if (cfg->arch.stack_alloc_size) {
4001 if (cfg->arch.omit_fp) {
4002 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4003 ia64_unw_pop_frames (code, 1);
4004 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4006 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4007 ia64_unw_pop_frames (code, 1);
4008 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4012 ia64_unw_pop_frames (code, 1);
4013 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4016 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4017 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4018 ia64_br_ret_reg (code, IA64_B0);
4020 ia64_codegen_close (code);
4022 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4023 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4025 cfg->code_len = code.buf - cfg->native_code;
4027 g_assert (cfg->code_len < cfg->code_size);
4031 mono_arch_emit_exceptions (MonoCompile *cfg)
4033 MonoJumpInfo *patch_info;
4035 Ia64CodegenState code;
4036 gboolean empty = TRUE;
4037 //unw_dyn_region_info_t *r_exceptions;
4038 MonoClass *exc_classes [16];
4039 guint8 *exc_throw_start [16], *exc_throw_end [16];
4040 guint32 code_size = 0;
4042 /* Compute needed space */
4043 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4044 if (patch_info->type == MONO_PATCH_INFO_EXC)
4046 if (patch_info->type == MONO_PATCH_INFO_R8)
4047 code_size += 8 + 7; /* sizeof (double) + alignment */
4048 if (patch_info->type == MONO_PATCH_INFO_R4)
4049 code_size += 4 + 7; /* sizeof (float) + alignment */
4055 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4056 cfg->code_size *= 2;
4057 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4058 mono_jit_stats.code_reallocs++;
4061 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4063 /* The unwind state here is the same as before the epilog */
4064 //ia64_unw_copy_state (code, 1234);
4066 /* add code to raise exceptions */
4067 /* FIXME: Optimize this */
4069 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4070 switch (patch_info->type) {
4071 case MONO_PATCH_INFO_EXC: {
4072 MonoClass *exc_class;
4075 guint64 exc_token_index;
4077 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4078 g_assert (exc_class);
4079 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4080 throw_ip = cfg->native_code + patch_info->ip.i;
4082 ia64_begin_bundle (code);
4084 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4086 /* Find a throw sequence for the same exception class */
4087 for (i = 0; i < nthrows; ++i)
4088 if (exc_classes [i] == exc_class)
4092 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4094 if (ia64_is_adds_imm (offset))
4095 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4097 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4099 buf = code.buf + code.nins;
4100 ia64_br_cond_pred (code, 0, 0);
4101 ia64_begin_bundle (code);
4102 ia64_patch (buf, exc_throw_start [i]);
4104 patch_info->type = MONO_PATCH_INFO_NONE;
4109 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4111 ia64_begin_bundle (code);
4114 exc_classes [nthrows] = exc_class;
4115 exc_throw_start [nthrows] = code.buf;
4119 if (ia64_is_adds_imm (exc_token_index))
4120 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4122 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4124 patch_info->data.name = "mono_arch_throw_corlib_exception";
4125 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4126 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4129 ia64_movl (code, GP_SCRATCH_REG, 0);
4130 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4131 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4132 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4134 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4136 /* Patch up the throw offset */
4137 ia64_begin_bundle (code);
4139 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4142 exc_throw_end [nthrows] = code.buf;
4156 /* The unwinder needs this to work */
4157 ia64_break_i (code, 0);
4159 ia64_codegen_close (code);
4162 //r_exceptions = mono_ia64_create_unwind_region (&code);
4163 //cfg->arch.r_epilog = r_exceptions;
4165 cfg->code_len = code.buf - cfg->native_code;
4167 g_assert (cfg->code_len < cfg->code_size);
4171 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4173 Ia64CodegenState code;
4174 CallInfo *cinfo = NULL;
4175 MonoMethodSignature *sig;
4177 int i, n, stack_area = 0;
4179 ia64_codegen_init (code, p);
4181 /* Keep this in sync with mono_arch_get_argument_info */
4183 if (enable_arguments) {
4184 /* Allocate a new area on the stack and save arguments there */
4185 sig = mono_method_signature (cfg->method);
4187 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4189 n = sig->param_count + sig->hasthis;
4191 stack_area = ALIGN_TO (n * 8, 16);
4194 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4196 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4198 /* FIXME: Allocate out registers */
4200 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4202 /* Required by the ABI */
4203 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4205 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4206 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4208 /* Save arguments to the stack */
4209 for (i = 0; i < n; ++i) {
4210 ins = cfg->args [i];
4212 if (ins->opcode == OP_REGVAR) {
4213 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4214 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4215 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4218 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4219 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4220 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4221 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4222 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4223 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4228 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4231 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4233 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4234 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4236 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4238 if (enable_arguments && stack_area) {
4239 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4241 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4243 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4246 ia64_codegen_close (code);
4252 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4254 Ia64CodegenState code;
4255 CallInfo *cinfo = NULL;
4256 MonoMethod *method = cfg->method;
4257 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4259 ia64_codegen_init (code, p);
4261 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4263 /* Save return value + pass it to func */
4264 switch (cinfo->ret.storage) {
4268 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4269 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4272 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4273 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4274 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4275 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4277 case ArgValuetypeAddrInIReg:
4278 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4287 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4288 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4289 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4291 /* Restore return value */
4292 switch (cinfo->ret.storage) {
4296 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4299 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4300 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4302 case ArgValuetypeAddrInIReg:
4310 ia64_codegen_close (code);
4316 mono_arch_save_unwind_info (MonoCompile *cfg)
4320 /* FIXME: Unregister this for dynamic methods */
4322 di = g_malloc0 (sizeof (unw_dyn_info_t));
4323 di->start_ip = (unw_word_t) cfg->native_code;
4324 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4326 di->format = UNW_INFO_FORMAT_DYNAMIC;
4327 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4328 di->u.pi.regions = cfg->arch.r_pro;
4330 _U_dyn_register (di);
4334 unw_dyn_region_info_t *region = di->u.pi.regions;
4336 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4338 printf (" [Region: %d]\n", region->insn_count);
4339 region = region->next;
4346 mono_arch_flush_icache (guint8 *code, gint size)
4348 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4349 guint8* end = (guint8*)((guint64)code + size);
4351 #ifdef __INTEL_COMPILER
4352 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4359 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4360 /* FIXME: This could be increased to 128 on some cpus */
4367 mono_arch_flush_register_windows (void)
4369 /* Not needed because of libunwind */
4373 mono_arch_is_inst_imm (gint64 imm)
4375 /* The lowering pass will take care of it */
4381 * Determine whenever the trap whose info is in SIGINFO is caused by
4385 mono_arch_is_int_overflow (void *sigctx, void *info)
4387 /* Division is emulated with explicit overflow checks */
4392 mono_arch_get_patch_offset (guint8 *code)
4400 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4402 guint8 *bundle2 = code - 48;
4403 guint8 *bundle3 = code - 32;
4404 guint8 *bundle4 = code - 16;
4405 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4406 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4407 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4408 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4409 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4410 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4411 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4412 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4413 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4416 * Virtual calls are made with:
4418 * [MII] ld8 r31=[r8]
4422 * mov.sptk b6=r31,0x2000000000f32a80
4429 * br.call.sptk.few b0=b6;;
4432 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4433 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4434 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4435 (ins31 == IA64_NOP_M) &&
4436 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4437 (ins33 == IA64_NOP_I) &&
4438 (ins41 == IA64_NOP_M) &&
4439 (ins42 == IA64_NOP_I) &&
4440 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4441 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4442 g_assert (ins21 == IA64_NOP_M);
4443 g_assert (ins23 == IA64_NOP_I);
4444 g_assert (ia64_ins_opcode (ins22) == 0);
4445 g_assert (ia64_ins_x3 (ins22) == 7);
4446 g_assert (ia64_ins_x (ins22) == 0);
4447 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4449 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4451 return regs [IA64_R11];
4458 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4462 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4465 return (gpointer*)(gpointer)((char*)vt + displacement);
4469 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4476 static gboolean tls_offset_inited = FALSE;
4479 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4481 if (!tls_offset_inited) {
4482 tls_offset_inited = TRUE;
4484 appdomain_tls_offset = mono_domain_get_tls_offset ();
4485 thread_tls_offset = mono_thread_get_tls_offset ();
4490 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4495 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4497 MonoCallInst *call = (MonoCallInst*)inst;
4498 int out_reg = cfg->arch.reg_out0;
4501 CallInfo * cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
4504 if (cinfo->ret.storage == ArgAggregate) {
4505 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4508 * The valuetype is in registers after the call, need to be copied
4509 * to the stack. Save the address to a local here, so the call
4510 * instruction can access it.
4512 g_assert (local->opcode == OP_REGOFFSET);
4513 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4516 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4517 vtarg->sreg1 = vt_reg;
4518 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4519 mono_bblock_add_inst (cfg->cbb, vtarg);
4521 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4527 /* add the this argument */
4528 if (this_reg != -1) {
4530 MONO_INST_NEW (cfg, this, OP_MOVE);
4531 this->type = this_type;
4532 this->sreg1 = this_reg;
4533 this->dreg = mono_regstate_next_int (cfg->rs);
4534 mono_bblock_add_inst (cfg->cbb, this);
4536 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4541 #ifdef MONO_ARCH_HAVE_IMT
4544 * LOCKING: called with the domain lock held
4547 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4551 guint8 *start, *buf;
4552 Ia64CodegenState code;
4555 buf = g_malloc0 (size);
4556 ia64_codegen_init (code, buf);
4558 /* IA64_R9 contains the IMT method */
4560 for (i = 0; i < count; ++i) {
4561 MonoIMTCheckItem *item = imt_entries [i];
4562 ia64_begin_bundle (code);
4563 item->code_target = (guint8*)code.buf + code.nins;
4564 if (item->is_equals) {
4565 if (item->check_target_idx) {
4566 if (!item->compare_done) {
4567 ia64_movl (code, GP_SCRATCH_REG, item->method);
4568 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4570 item->jmp_code = (guint8*)code.buf + code.nins;
4571 ia64_br_cond_pred (code, 7, 0);
4573 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4574 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4575 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4576 ia64_br_cond_reg (code, IA64_B6);
4578 /* enable the commented code to assert on wrong method */
4579 #if ENABLE_WRONG_METHOD_CHECK
4580 g_assert_not_reached ();
4582 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4583 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4584 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4585 ia64_br_cond_reg (code, IA64_B6);
4586 #if ENABLE_WRONG_METHOD_CHECK
4587 g_assert_not_reached ();
4591 ia64_movl (code, GP_SCRATCH_REG, item->method);
4592 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4593 item->jmp_code = (guint8*)code.buf + code.nins;
4594 ia64_br_cond_pred (code, 6, 0);
4597 /* patch the branches to get to the target items */
4598 for (i = 0; i < count; ++i) {
4599 MonoIMTCheckItem *item = imt_entries [i];
4600 if (item->jmp_code) {
4601 if (item->check_target_idx) {
4602 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4607 ia64_codegen_close (code);
4608 g_assert (code.buf - buf <= size);
4610 size = code.buf - buf;
4611 start = mono_code_manager_reserve (domain->code_mp, size);
4612 memcpy (start, buf, size);
4614 mono_arch_flush_icache (start, size);
4616 mono_stats.imt_thunks_size += size;
4622 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4624 return regs [IA64_R9];
4628 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
4630 /* Done by the implementation of the CALL_MEMBASE opcodes */
4635 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
4637 return (gpointer)regs [IA64_R10];
4641 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4643 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4647 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
4653 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4655 MonoInst *ins = NULL;
4657 if(cmethod->klass->image == mono_defaults.corlib &&
4658 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4659 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4661 * We don't use the generic version in mini_get_inst_for_method () since the
4662 * ia64 has atomic_add_imm opcodes.
4664 if (strcmp (cmethod->name, "Increment") == 0) {
4667 if (fsig->params [0]->type == MONO_TYPE_I4)
4668 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4669 else if (fsig->params [0]->type == MONO_TYPE_I8)
4670 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4672 g_assert_not_reached ();
4673 MONO_INST_NEW (cfg, ins, opcode);
4675 ins->inst_i0 = args [0];
4676 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4679 if (fsig->params [0]->type == MONO_TYPE_I4)
4680 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4681 else if (fsig->params [0]->type == MONO_TYPE_I8)
4682 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4684 g_assert_not_reached ();
4685 MONO_INST_NEW (cfg, ins, opcode);
4687 ins->inst_i0 = args [0];
4688 } else if (strcmp (cmethod->name, "Add") == 0) {
4691 if (fsig->params [0]->type == MONO_TYPE_I4)
4692 opcode = OP_ATOMIC_ADD_NEW_I4;
4693 else if (fsig->params [0]->type == MONO_TYPE_I8)
4694 opcode = OP_ATOMIC_ADD_NEW_I8;
4696 g_assert_not_reached ();
4698 MONO_INST_NEW (cfg, ins, opcode);
4700 ins->inst_i0 = args [0];
4701 ins->inst_i1 = args [1];
4709 mono_arch_print_tree (MonoInst *tree, int arity)
4714 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4718 if (appdomain_tls_offset == -1)
4721 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4722 ins->inst_offset = appdomain_tls_offset;
4726 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4730 if (thread_tls_offset == -1)
4733 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4734 ins->inst_offset = thread_tls_offset;
4739 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4741 /* FIXME: implement */
4742 g_assert_not_reached ();