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"
28 #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
204 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
206 ainfo->offset = *stack_size;
208 if (*gr >= PARAM_REGS) {
209 ainfo->storage = ArgOnStack;
210 (*stack_size) += sizeof (gpointer);
213 ainfo->storage = ArgInIReg;
219 #define FLOAT_PARAM_REGS 8
222 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
224 ainfo->offset = *stack_size;
226 if (*gr >= PARAM_REGS) {
227 ainfo->storage = ArgOnStack;
228 (*stack_size) += sizeof (gpointer);
231 ainfo->storage = is_double ? ArgInFloatReg : ArgInFloatRegR4;
232 ainfo->reg = 8 + *fr;
239 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
241 guint32 *gr, guint32 *fr, guint32 *stack_size)
245 MonoMarshalType *info;
246 gboolean is_hfa = TRUE;
247 guint32 hfa_type = 0;
249 klass = mono_class_from_mono_type (type);
250 if (type->type == MONO_TYPE_TYPEDBYREF)
251 size = 3 * sizeof (gpointer);
252 else if (sig->pinvoke)
253 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
255 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
257 if (!sig->pinvoke || (size == 0)) {
258 /* Allways pass in memory */
259 ainfo->offset = *stack_size;
260 *stack_size += ALIGN_TO (size, 8);
261 ainfo->storage = ArgOnStack;
266 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
267 info = mono_marshal_load_type_info (klass);
269 for (i = 0; i < info->num_fields; ++i) {
270 guint32 ftype = info->fields [i].field->type->type;
271 if (!(info->fields [i].field->type->byref) &&
272 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
275 else if (hfa_type != ftype)
284 ainfo->storage = ArgAggregate;
285 ainfo->atype = AggregateNormal;
288 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
290 if (info->num_fields <= 8) {
292 ainfo->nregs = info->num_fields;
293 ainfo->nslots = ainfo->nregs;
299 if ((*fr) + info->num_fields > 8)
302 ainfo->reg = 8 + (*fr);
303 ainfo->nregs = info->num_fields;
304 ainfo->nslots = ainfo->nregs;
305 (*fr) += info->num_fields;
306 if (ainfo->atype == AggregateSingleHFA) {
308 * FIXME: Have to keep track of the parameter slot number, which is
309 * not the same as *gr.
311 (*gr) += ALIGN_TO (info->num_fields, 2) / 2;
313 (*gr) += info->num_fields;
319 /* This also handles returning of TypedByRef used by some icalls */
322 ainfo->reg = IA64_R8;
323 ainfo->nregs = (size + 7) / 8;
324 ainfo->nslots = ainfo->nregs;
331 ainfo->offset = *stack_size;
332 ainfo->nslots = (size + 7) / 8;
334 if (((*gr) + ainfo->nslots) <= 8) {
335 /* Fits entirely in registers */
336 ainfo->nregs = ainfo->nslots;
337 (*gr) += ainfo->nregs;
341 ainfo->nregs = 8 - (*gr);
343 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
349 * Obtain information about a call according to the calling convention.
350 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
351 * Gude" document for more information.
354 get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
358 int n = sig->hasthis + sig->param_count;
359 guint32 stack_size = 0;
361 MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
364 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
366 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
373 ret_type = mono_type_get_underlying_type (sig->ret);
374 ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
375 switch (ret_type->type) {
376 case MONO_TYPE_BOOLEAN:
387 case MONO_TYPE_FNPTR:
388 case MONO_TYPE_CLASS:
389 case MONO_TYPE_OBJECT:
390 case MONO_TYPE_SZARRAY:
391 case MONO_TYPE_ARRAY:
392 case MONO_TYPE_STRING:
393 cinfo->ret.storage = ArgInIReg;
394 cinfo->ret.reg = IA64_R8;
398 cinfo->ret.storage = ArgInIReg;
399 cinfo->ret.reg = IA64_R8;
403 cinfo->ret.storage = ArgInFloatReg;
406 case MONO_TYPE_GENERICINST:
407 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
408 cinfo->ret.storage = ArgInIReg;
409 cinfo->ret.reg = IA64_R8;
413 case MONO_TYPE_VALUETYPE:
414 case MONO_TYPE_TYPEDBYREF: {
415 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
417 if (sig->ret->byref) {
418 /* This seems to happen with ldfld wrappers */
419 cinfo->ret.storage = ArgInIReg;
421 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
422 if (cinfo->ret.storage == ArgOnStack)
423 /* The caller passes the address where the value is stored */
424 add_general (&gr, &stack_size, &cinfo->ret);
425 if (cinfo->ret.storage == ArgInIReg)
426 cinfo->ret.storage = ArgValuetypeAddrInIReg;
431 cinfo->ret.storage = ArgNone;
434 g_error ("Can't handle as return value 0x%x", sig->ret->type);
440 add_general (&gr, &stack_size, cinfo->args + 0);
442 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
444 fr = FLOAT_PARAM_REGS;
446 /* Emit the signature cookie just before the implicit arguments */
447 add_general (&gr, &stack_size, &cinfo->sig_cookie);
450 for (i = 0; i < sig->param_count; ++i) {
451 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
454 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
455 /* We allways pass the sig cookie on the stack for simplicity */
457 * Prevent implicit arguments + the sig cookie from being passed
461 fr = FLOAT_PARAM_REGS;
463 /* Emit the signature cookie just before the implicit arguments */
464 add_general (&gr, &stack_size, &cinfo->sig_cookie);
467 if (sig->params [i]->byref) {
468 add_general (&gr, &stack_size, ainfo);
471 ptype = mono_type_get_underlying_type (sig->params [i]);
472 ptype = mini_get_basic_type_from_generic (gsctx, ptype);
473 switch (ptype->type) {
474 case MONO_TYPE_BOOLEAN:
477 add_general (&gr, &stack_size, ainfo);
482 add_general (&gr, &stack_size, ainfo);
486 add_general (&gr, &stack_size, ainfo);
491 case MONO_TYPE_FNPTR:
492 case MONO_TYPE_CLASS:
493 case MONO_TYPE_OBJECT:
494 case MONO_TYPE_STRING:
495 case MONO_TYPE_SZARRAY:
496 case MONO_TYPE_ARRAY:
497 add_general (&gr, &stack_size, ainfo);
499 case MONO_TYPE_GENERICINST:
500 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
501 add_general (&gr, &stack_size, ainfo);
505 case MONO_TYPE_VALUETYPE:
506 case MONO_TYPE_TYPEDBYREF:
508 /* We allways pass valuetypes on the stack */
509 add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
513 add_general (&gr, &stack_size, ainfo);
516 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
519 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
522 g_assert_not_reached ();
526 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
528 fr = FLOAT_PARAM_REGS;
530 /* Emit the signature cookie just before the implicit arguments */
531 add_general (&gr, &stack_size, &cinfo->sig_cookie);
534 cinfo->stack_usage = stack_size;
535 cinfo->reg_usage = gr;
536 cinfo->freg_usage = fr;
541 * mono_arch_get_argument_info:
542 * @csig: a method signature
543 * @param_count: the number of parameters to consider
544 * @arg_info: an array to store the result infos
546 * Gathers information on parameters such as size, alignment and
547 * padding. arg_info should be large enought to hold param_count + 1 entries.
549 * Returns the size of the argument area on the stack.
552 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
555 CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
556 guint32 args_size = cinfo->stack_usage;
558 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
560 arg_info [0].offset = 0;
563 for (k = 0; k < param_count; k++) {
564 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
566 arg_info [k + 1].size = 0;
575 * Initialize the cpu to execute managed code.
578 mono_arch_cpu_init (void)
583 * Initialize architecture specific code.
586 mono_arch_init (void)
591 * Cleanup architecture specific code.
594 mono_arch_cleanup (void)
599 * This function returns the optimizations supported on this cpu.
602 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
610 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
614 MonoMethodSignature *sig;
615 MonoMethodHeader *header;
618 header = mono_method_get_header (cfg->method);
620 sig = mono_method_signature (cfg->method);
622 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
624 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
625 MonoInst *ins = cfg->args [i];
627 ArgInfo *ainfo = &cinfo->args [i];
629 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
632 if (ainfo->storage == ArgInIReg) {
633 /* The input registers are non-volatile */
634 ins->opcode = OP_REGVAR;
635 ins->dreg = 32 + ainfo->reg;
639 for (i = 0; i < cfg->num_varinfo; i++) {
640 MonoInst *ins = cfg->varinfo [i];
641 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
644 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
647 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
648 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
651 if (mono_is_regsize_var (ins->inst_vtype)) {
652 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
653 g_assert (i == vmv->idx);
654 vars = g_list_prepend (vars, vmv);
658 vars = mono_varlist_sort (cfg, vars, 0);
664 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
667 guint32 reserved_regs;
668 MonoMethodHeader *header;
670 if (cfg->arch.reg_local0 > 0)
674 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
676 header = mono_method_get_header (cfg->method);
678 /* Some registers are reserved for use by the prolog/epilog */
679 reserved_regs = header->num_clauses ? 4 : 3;
681 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
682 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
683 /* One registers is needed by instrument_epilog to save the return value */
685 if (cinfo->reg_usage < 2)
686 /* Number of arguments passed to function call in instrument_prolog */
687 cinfo->reg_usage = 2;
690 cfg->arch.reg_in0 = 32;
691 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
692 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
694 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
695 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
696 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
699 * Frames without handlers save sp to fp, frames with handlers save it into
700 * a dedicated register.
702 if (header->num_clauses)
703 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
705 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
707 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
708 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
709 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
713 * Need to allocate at least 2 out register for use by OP_THROW / the system
714 * exception throwing code.
716 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
720 mono_arch_get_global_int_regs (MonoCompile *cfg)
725 mono_ia64_alloc_stacked_registers (cfg);
727 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
730 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
737 * mono_arch_regalloc_cost:
739 * Return the cost, in number of memory references, of the action of
740 * allocating the variable VMV into a register during global register
744 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
746 /* FIXME: Increase costs linearly to avoid using all local registers */
752 mono_arch_allocate_vars (MonoCompile *cfg)
754 MonoMethodSignature *sig;
755 MonoMethodHeader *header;
758 guint32 locals_stack_size, locals_stack_align;
762 header = mono_method_get_header (cfg->method);
764 sig = mono_method_signature (cfg->method);
766 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
769 * Determine whenever the frame pointer can be eliminated.
770 * FIXME: Remove some of the restrictions.
772 cfg->arch.omit_fp = TRUE;
774 if (!debug_omit_fp ())
775 cfg->arch.omit_fp = FALSE;
777 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
778 cfg->arch.omit_fp = FALSE;
779 if (header->num_clauses)
780 cfg->arch.omit_fp = FALSE;
782 cfg->arch.omit_fp = FALSE;
783 if ((sig->ret->type != MONO_TYPE_VOID) && (cinfo->ret.storage == ArgAggregate))
784 cfg->arch.omit_fp = FALSE;
785 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
786 cfg->arch.omit_fp = FALSE;
787 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
788 ArgInfo *ainfo = &cinfo->args [i];
790 if (ainfo->storage == ArgOnStack) {
792 * The stack offset can only be determined when the frame
795 cfg->arch.omit_fp = FALSE;
799 mono_ia64_alloc_stacked_registers (cfg);
802 * We use the ABI calling conventions for managed code as well.
803 * Exception: valuetypes are never passed or returned in registers.
806 if (cfg->arch.omit_fp) {
807 cfg->flags |= MONO_CFG_HAS_SPILLUP;
808 cfg->frame_reg = IA64_SP;
809 offset = ARGS_OFFSET;
812 /* Locals are allocated backwards from %fp */
813 cfg->frame_reg = cfg->arch.reg_fp;
817 if (cfg->method->save_lmf) {
821 if (sig->ret->type != MONO_TYPE_VOID) {
822 switch (cinfo->ret.storage) {
824 cfg->ret->opcode = OP_REGVAR;
825 cfg->ret->inst_c0 = cinfo->ret.reg;
828 cfg->ret->opcode = OP_REGVAR;
829 cfg->ret->inst_c0 = cinfo->ret.reg;
831 case ArgValuetypeAddrInIReg:
832 cfg->vret_addr->opcode = OP_REGVAR;
833 cfg->vret_addr->dreg = cfg->arch.reg_in0 + cinfo->ret.reg;
836 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
837 if (cfg->arch.omit_fp)
838 g_assert_not_reached ();
839 offset = ALIGN_TO (offset, 8);
840 offset += cinfo->ret.nslots * 8;
841 cfg->ret->opcode = OP_REGOFFSET;
842 cfg->ret->inst_basereg = cfg->frame_reg;
843 cfg->ret->inst_offset = - offset;
846 g_assert_not_reached ();
848 cfg->ret->dreg = cfg->ret->inst_c0;
851 /* Allocate locals */
852 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
853 if (locals_stack_align) {
854 offset = ALIGN_TO (offset, locals_stack_align);
856 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
857 if (offsets [i] != -1) {
858 MonoInst *inst = cfg->varinfo [i];
859 inst->opcode = OP_REGOFFSET;
860 inst->inst_basereg = cfg->frame_reg;
861 if (cfg->arch.omit_fp)
862 inst->inst_offset = (offset + offsets [i]);
864 inst->inst_offset = - (offset + offsets [i]);
865 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
868 offset += locals_stack_size;
870 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
871 if (cfg->arch.omit_fp)
872 g_assert_not_reached ();
873 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
874 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
877 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
878 inst = cfg->args [i];
879 if (inst->opcode != OP_REGVAR) {
880 ArgInfo *ainfo = &cinfo->args [i];
881 gboolean inreg = TRUE;
884 if (sig->hasthis && (i == 0))
885 arg_type = &mono_defaults.object_class->byval_arg;
887 arg_type = sig->params [i - sig->hasthis];
889 /* FIXME: VOLATILE is only set if the liveness pass runs */
890 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
893 inst->opcode = OP_REGOFFSET;
895 switch (ainfo->storage) {
897 inst->opcode = OP_REGVAR;
898 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
901 case ArgInFloatRegR4:
903 * Since float regs are volatile, we save the arguments to
904 * the stack in the prolog.
909 if (cfg->arch.omit_fp)
910 g_assert_not_reached ();
911 inst->opcode = OP_REGOFFSET;
912 inst->inst_basereg = cfg->frame_reg;
913 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
922 if (!inreg && (ainfo->storage != ArgOnStack)) {
925 inst->opcode = OP_REGOFFSET;
926 inst->inst_basereg = cfg->frame_reg;
927 /* These arguments are saved to the stack in the prolog */
928 switch (ainfo->storage) {
930 if (ainfo->atype == AggregateSingleHFA)
931 size = ainfo->nslots * 4;
933 size = ainfo->nslots * 8;
936 size = sizeof (gpointer);
940 offset = ALIGN_TO (offset, sizeof (gpointer));
942 if (cfg->arch.omit_fp) {
943 inst->inst_offset = offset;
947 inst->inst_offset = - offset;
954 * FIXME: This doesn't work because some variables are allocated during local
958 if (cfg->arch.omit_fp && offset == 16)
962 cfg->stack_offset = offset;
966 mono_arch_create_vars (MonoCompile *cfg)
968 MonoMethodSignature *sig;
971 sig = mono_method_signature (cfg->method);
973 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
975 if (cinfo->ret.storage == ArgAggregate)
976 cfg->ret_var_is_local = TRUE;
977 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
978 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
979 if (G_UNLIKELY (cfg->verbose_level > 1)) {
980 printf ("vret_addr = ");
981 mono_print_ins (cfg->vret_addr);
987 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
991 MONO_INST_NEW (cfg, arg, OP_NOP);
992 arg->sreg1 = tree->dreg;
996 arg->opcode = OP_MOVE;
997 arg->dreg = mono_alloc_ireg (cfg);
999 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, FALSE);
1002 arg->opcode = OP_FMOVE;
1003 arg->dreg = mono_alloc_freg (cfg);
1005 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1007 case ArgInFloatRegR4:
1008 arg->opcode = OP_FCONV_TO_R4;
1009 arg->dreg = mono_alloc_freg (cfg);
1011 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1014 g_assert_not_reached ();
1017 MONO_ADD_INS (cfg->cbb, arg);
1021 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1023 MonoMethodSignature *tmp_sig;
1025 /* Emit the signature cookie just before the implicit arguments */
1027 /* FIXME: Add support for signature tokens to AOT */
1028 cfg->disable_aot = TRUE;
1030 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1033 * mono_ArgIterator_Setup assumes the signature cookie is
1034 * passed first and all the arguments which were before it are
1035 * passed on the stack after the signature. So compensate by
1036 * passing a different signature.
1038 tmp_sig = mono_metadata_signature_dup (call->signature);
1039 tmp_sig->param_count -= call->signature->sentinelpos;
1040 tmp_sig->sentinelpos = 0;
1041 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1043 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1044 sig_arg->dreg = mono_alloc_ireg (cfg);
1045 sig_arg->inst_p0 = tmp_sig;
1046 MONO_ADD_INS (cfg->cbb, sig_arg);
1048 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + cinfo->sig_cookie.offset, sig_arg->dreg);
1052 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1055 MonoMethodSignature *sig;
1056 int i, n, stack_size;
1062 mono_ia64_alloc_stacked_registers (cfg);
1064 sig = call->signature;
1065 n = sig->param_count + sig->hasthis;
1067 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1069 if (cinfo->ret.storage == ArgAggregate) {
1074 * The valuetype is in registers after the call, need to be copied
1075 * to the stack. Save the address to a local here, so the call
1076 * instruction can access it.
1078 local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1079 local->flags |= MONO_INST_VOLATILE;
1080 cfg->arch.ret_var_addr_local = local;
1082 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1083 vtarg->sreg1 = call->vret_var->dreg;
1084 vtarg->dreg = local->dreg;
1085 MONO_ADD_INS (cfg->cbb, vtarg);
1088 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
1089 add_outarg_reg (cfg, call, ArgInIReg, cfg->arch.reg_out0 + cinfo->ret.reg, call->vret_var);
1092 for (i = 0; i < n; ++i) {
1095 ainfo = cinfo->args + i;
1097 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1098 /* Emit the signature cookie just before the implicit arguments */
1099 emit_sig_cookie (cfg, call, cinfo);
1102 in = call->args [i];
1104 if (sig->hasthis && (i == 0))
1105 arg_type = &mono_defaults.object_class->byval_arg;
1107 arg_type = sig->params [i - sig->hasthis];
1109 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1113 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1114 size = sizeof (MonoTypedRef);
1115 align = sizeof (gpointer);
1117 else if (sig->pinvoke)
1118 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1121 * Other backends use mono_type_stack_size (), but that
1122 * aligns the size to 8, which is larger than the size of
1123 * the source, leading to reads of invalid memory if the
1124 * source is at the end of address space.
1126 size = mono_class_value_size (in->klass, &align);
1132 MONO_INST_NEW (cfg, arg, OP_OUTARG_VT);
1133 arg->sreg1 = in->dreg;
1134 arg->klass = in->klass;
1135 arg->backend.size = size;
1136 arg->inst_p0 = call;
1137 arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1138 memcpy (arg->inst_p1, ainfo, sizeof (ArgInfo));
1140 MONO_ADD_INS (cfg->cbb, arg);
1144 switch (ainfo->storage) {
1146 add_outarg_reg (cfg, call, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1149 case ArgInFloatRegR4:
1150 add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, in);
1153 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref)
1154 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1155 else if (arg_type->type == MONO_TYPE_R8 && !arg_type->byref)
1156 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1158 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1161 g_assert_not_reached ();
1166 /* Handle the case where there are no implicit arguments */
1167 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1168 emit_sig_cookie (cfg, call, cinfo);
1171 call->stack_usage = cinfo->stack_usage;
1172 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1176 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1178 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1179 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1180 int size = ins->backend.size;
1182 if (ainfo->storage == ArgAggregate) {
1183 MonoInst *load, *store;
1187 * Part of the structure is passed in registers.
1189 for (i = 0; i < ainfo->nregs; ++i) {
1190 slot = ainfo->reg + i;
1192 if (ainfo->atype == AggregateSingleHFA) {
1193 MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
1194 load->inst_basereg = src->dreg;
1195 load->inst_offset = i * 4;
1196 load->dreg = mono_alloc_freg (cfg);
1198 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1199 } else if (ainfo->atype == AggregateDoubleHFA) {
1200 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1201 load->inst_basereg = src->dreg;
1202 load->inst_offset = i * 8;
1203 load->dreg = mono_alloc_freg (cfg);
1205 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1207 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1208 load->inst_basereg = src->dreg;
1209 load->inst_offset = i * 8;
1210 load->dreg = mono_alloc_ireg (cfg);
1212 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, cfg->arch.reg_out0 + ainfo->reg + i, FALSE);
1214 MONO_ADD_INS (cfg->cbb, load);
1218 * Part of the structure is passed on the stack.
1220 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1221 slot = ainfo->reg + i;
1223 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1224 load->inst_basereg = src->dreg;
1225 load->inst_offset = i * sizeof (gpointer);
1226 load->dreg = mono_alloc_preg (cfg);
1227 MONO_ADD_INS (cfg->cbb, load);
1229 MONO_INST_NEW (cfg, store, OP_STOREI8_MEMBASE_REG);
1230 store->sreg1 = load->dreg;
1231 store->inst_destbasereg = IA64_SP;
1232 store->inst_offset = 16 + ainfo->offset + (slot - 8) * 8;
1233 MONO_ADD_INS (cfg->cbb, store);
1236 mini_emit_memcpy (cfg, IA64_SP, 16 + ainfo->offset, src->dreg, 0, size, 4);
1241 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1243 CallInfo *cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
1245 switch (cinfo->ret.storage) {
1247 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1250 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1253 g_assert_not_reached ();
1258 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1263 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1265 MonoInst *ins, *n, *last_ins = NULL;
1268 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1269 switch (ins->opcode) {
1277 if (ins->dreg == ins->sreg1) {
1278 MONO_DELETE_INS (bb, ins);
1284 * OP_MOVE sreg, dreg
1285 * OP_MOVE dreg, sreg
1287 if (last_ins && last_ins->opcode == OP_MOVE &&
1288 ins->sreg1 == last_ins->dreg &&
1289 ins->dreg == last_ins->sreg1) {
1290 MONO_DELETE_INS (bb, ins);
1296 /* remove unnecessary multiplication with 1 */
1297 if (ins->inst_imm == 1) {
1298 if (ins->dreg != ins->sreg1) {
1299 ins->opcode = OP_MOVE;
1301 MONO_DELETE_INS (bb, ins);
1311 bb->last_ins = last_ins;
1314 int cond_to_ia64_cmp [][3] = {
1315 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1316 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1317 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1318 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1319 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1320 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1321 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1322 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1323 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1324 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1328 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1330 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1333 int cond_to_ia64_cmp_imm [][3] = {
1334 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1335 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1336 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1337 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1338 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1339 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1340 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1341 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1342 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1343 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1347 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1349 /* The condition needs to be reversed */
1350 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1353 #define NEW_INS(cfg,dest,op) do { \
1354 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1355 (dest)->opcode = (op); \
1356 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1357 last_ins = (dest); \
1361 * mono_arch_lowering_pass:
1363 * Converts complex opcodes into simpler ones so that each IR instruction
1364 * corresponds to one machine instruction.
1367 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1369 MonoInst *ins, *n, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1372 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1373 switch (ins->opcode) {
1374 case OP_STOREI1_MEMBASE_IMM:
1375 case OP_STOREI2_MEMBASE_IMM:
1376 case OP_STOREI4_MEMBASE_IMM:
1377 case OP_STOREI8_MEMBASE_IMM:
1378 case OP_STORE_MEMBASE_IMM:
1379 /* There are no store_membase instructions on ia64 */
1380 if (ins->inst_offset == 0) {
1382 } else if (ia64_is_imm14 (ins->inst_offset)) {
1383 NEW_INS (cfg, temp2, OP_ADD_IMM);
1384 temp2->sreg1 = ins->inst_destbasereg;
1385 temp2->inst_imm = ins->inst_offset;
1386 temp2->dreg = mono_alloc_ireg (cfg);
1389 NEW_INS (cfg, temp, OP_I8CONST);
1390 temp->inst_c0 = ins->inst_offset;
1391 temp->dreg = mono_alloc_ireg (cfg);
1393 NEW_INS (cfg, temp2, OP_LADD);
1394 temp2->sreg1 = ins->inst_destbasereg;
1395 temp2->sreg2 = temp->dreg;
1396 temp2->dreg = mono_alloc_ireg (cfg);
1399 switch (ins->opcode) {
1400 case OP_STOREI1_MEMBASE_IMM:
1401 ins->opcode = OP_STOREI1_MEMBASE_REG;
1403 case OP_STOREI2_MEMBASE_IMM:
1404 ins->opcode = OP_STOREI2_MEMBASE_REG;
1406 case OP_STOREI4_MEMBASE_IMM:
1407 ins->opcode = OP_STOREI4_MEMBASE_REG;
1409 case OP_STOREI8_MEMBASE_IMM:
1410 case OP_STORE_MEMBASE_IMM:
1411 ins->opcode = OP_STOREI8_MEMBASE_REG;
1414 g_assert_not_reached ();
1417 if (ins->inst_imm == 0)
1418 ins->sreg1 = IA64_R0;
1420 NEW_INS (cfg, temp3, OP_I8CONST);
1421 temp3->inst_c0 = ins->inst_imm;
1422 temp3->dreg = mono_alloc_ireg (cfg);
1423 ins->sreg1 = temp3->dreg;
1426 ins->inst_offset = 0;
1428 ins->inst_destbasereg = temp2->dreg;
1430 case OP_STOREI1_MEMBASE_REG:
1431 case OP_STOREI2_MEMBASE_REG:
1432 case OP_STOREI4_MEMBASE_REG:
1433 case OP_STOREI8_MEMBASE_REG:
1434 case OP_STORER4_MEMBASE_REG:
1435 case OP_STORER8_MEMBASE_REG:
1436 case OP_STORE_MEMBASE_REG:
1437 /* There are no store_membase instructions on ia64 */
1438 if (ins->inst_offset == 0) {
1441 else if (ia64_is_imm14 (ins->inst_offset)) {
1442 NEW_INS (cfg, temp2, OP_ADD_IMM);
1443 temp2->sreg1 = ins->inst_destbasereg;
1444 temp2->inst_imm = ins->inst_offset;
1445 temp2->dreg = mono_alloc_ireg (cfg);
1448 NEW_INS (cfg, temp, OP_I8CONST);
1449 temp->inst_c0 = ins->inst_offset;
1450 temp->dreg = mono_alloc_ireg (cfg);
1451 NEW_INS (cfg, temp2, OP_LADD);
1452 temp2->sreg1 = ins->inst_destbasereg;
1453 temp2->sreg2 = temp->dreg;
1454 temp2->dreg = mono_alloc_ireg (cfg);
1457 ins->inst_offset = 0;
1458 ins->inst_destbasereg = temp2->dreg;
1460 case OP_LOADI1_MEMBASE:
1461 case OP_LOADU1_MEMBASE:
1462 case OP_LOADI2_MEMBASE:
1463 case OP_LOADU2_MEMBASE:
1464 case OP_LOADI4_MEMBASE:
1465 case OP_LOADU4_MEMBASE:
1466 case OP_LOADI8_MEMBASE:
1467 case OP_LOAD_MEMBASE:
1468 case OP_LOADR4_MEMBASE:
1469 case OP_LOADR8_MEMBASE:
1470 case OP_ATOMIC_EXCHANGE_I4:
1471 case OP_ATOMIC_EXCHANGE_I8:
1472 case OP_ATOMIC_ADD_NEW_I4:
1473 case OP_ATOMIC_ADD_NEW_I8:
1474 case OP_ATOMIC_ADD_IMM_NEW_I4:
1475 case OP_ATOMIC_ADD_IMM_NEW_I8:
1476 /* There are no membase instructions on ia64 */
1477 if (ins->inst_offset == 0) {
1480 else if (ia64_is_imm14 (ins->inst_offset)) {
1481 NEW_INS (cfg, temp2, OP_ADD_IMM);
1482 temp2->sreg1 = ins->inst_basereg;
1483 temp2->inst_imm = ins->inst_offset;
1484 temp2->dreg = mono_alloc_ireg (cfg);
1487 NEW_INS (cfg, temp, OP_I8CONST);
1488 temp->inst_c0 = ins->inst_offset;
1489 temp->dreg = mono_alloc_ireg (cfg);
1490 NEW_INS (cfg, temp2, OP_LADD);
1491 temp2->sreg1 = ins->inst_basereg;
1492 temp2->sreg2 = temp->dreg;
1493 temp2->dreg = mono_alloc_ireg (cfg);
1496 ins->inst_offset = 0;
1497 ins->inst_basereg = temp2->dreg;
1517 case OP_ISHR_UN_IMM:
1518 case OP_LSHR_UN_IMM: {
1519 gboolean is_imm = FALSE;
1520 gboolean switched = FALSE;
1522 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1523 ins->opcode = OP_ZEXT_I1;
1527 switch (ins->opcode) {
1531 is_imm = ia64_is_imm14 (ins->inst_imm);
1536 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1538 /* A = B - IMM -> A = B + (-IMM) */
1539 ins->inst_imm = - ins->inst_imm;
1540 ins->opcode = OP_IADD_IMM;
1551 is_imm = ia64_is_imm8 (ins->inst_imm);
1560 case OP_ISHR_UN_IMM:
1561 case OP_LSHR_UN_IMM:
1562 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1570 ins->sreg2 = ins->sreg1;
1574 ins->opcode = mono_op_imm_to_op (ins->opcode);
1576 if (ins->inst_imm == 0)
1577 ins->sreg2 = IA64_R0;
1579 NEW_INS (cfg, temp, OP_I8CONST);
1580 temp->inst_c0 = ins->inst_imm;
1581 temp->dreg = mono_alloc_ireg (cfg);
1582 ins->sreg2 = temp->dreg;
1586 case OP_COMPARE_IMM:
1587 case OP_ICOMPARE_IMM:
1588 case OP_LCOMPARE_IMM: {
1589 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1595 /* Branch opts can eliminate the branch */
1596 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1597 ins->opcode = OP_NOP;
1602 * The compare_imm instructions have switched up arguments, and
1603 * some of them take an imm between -127 and 128.
1606 cond = mono_opcode_to_cond (next->opcode);
1607 if ((cond == CMP_LT) || (cond == CMP_GE))
1608 imm = ia64_is_imm8 (ins->inst_imm - 1);
1609 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1610 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1612 imm = ia64_is_imm8 (ins->inst_imm);
1615 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1616 ins->sreg2 = ins->sreg1;
1619 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1621 if (ins->inst_imm == 0)
1622 ins->sreg2 = IA64_R0;
1624 NEW_INS (cfg, temp, OP_I8CONST);
1625 temp->inst_c0 = ins->inst_imm;
1626 temp->dreg = mono_alloc_ireg (cfg);
1627 ins->sreg2 = temp->dreg;
1631 if (MONO_IS_COND_BRANCH_OP (next)) {
1632 next->opcode = OP_IA64_BR_COND;
1633 if (! (next->flags & MONO_INST_BRLABEL))
1634 next->inst_target_bb = next->inst_true_bb;
1635 } else if (MONO_IS_COND_EXC (next)) {
1636 next->opcode = OP_IA64_COND_EXC;
1637 } else if (MONO_IS_SETCC (next)) {
1638 next->opcode = OP_IA64_CSET;
1640 printf ("%s\n", mono_inst_name (next->opcode));
1650 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1654 /* Branch opts can eliminate the branch */
1655 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1656 ins->opcode = OP_NOP;
1660 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1662 if (MONO_IS_COND_BRANCH_OP (next)) {
1663 next->opcode = OP_IA64_BR_COND;
1664 if (! (next->flags & MONO_INST_BRLABEL))
1665 next->inst_target_bb = next->inst_true_bb;
1666 } else if (MONO_IS_COND_EXC (next)) {
1667 next->opcode = OP_IA64_COND_EXC;
1668 } else if (MONO_IS_SETCC (next)) {
1669 next->opcode = OP_IA64_CSET;
1671 printf ("%s\n", mono_inst_name (next->opcode));
1682 /* The front end removes the fcompare, so introduce it again */
1683 NEW_INS (cfg, temp, opcode_to_ia64_cmp (ins->opcode, OP_FCOMPARE));
1684 temp->sreg1 = ins->sreg1;
1685 temp->sreg2 = ins->sreg2;
1687 ins->opcode = OP_IA64_CSET;
1693 gboolean found = FALSE;
1694 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1696 /* First the easy cases */
1697 if (ins->inst_imm == 1) {
1698 ins->opcode = OP_MOVE;
1701 for (i = 1; i < 64; ++i)
1702 if (ins->inst_imm == (((gint64)1) << i)) {
1703 ins->opcode = shl_op;
1709 /* This could be optimized */
1712 for (i = 0; i < 64; ++i) {
1713 if (ins->inst_imm & (((gint64)1) << i)) {
1714 NEW_INS (cfg, temp, shl_op);
1715 temp->dreg = mono_alloc_ireg (cfg);
1716 temp->sreg1 = ins->sreg1;
1720 sum_reg = temp->dreg;
1722 NEW_INS (cfg, temp2, OP_LADD);
1723 temp2->dreg = mono_alloc_ireg (cfg);
1724 temp2->sreg1 = sum_reg;
1725 temp2->sreg2 = temp->dreg;
1726 sum_reg = temp2->dreg;
1730 ins->opcode = OP_MOVE;
1731 ins->sreg1 = sum_reg;
1735 case OP_LCONV_TO_OVF_U4:
1736 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1737 temp->sreg1 = ins->sreg1;
1738 temp->sreg2 = IA64_R0;
1740 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1741 temp->inst_p1 = (char*)"OverflowException";
1743 ins->opcode = OP_MOVE;
1745 case OP_LCONV_TO_OVF_I4_UN:
1746 NEW_INS (cfg, temp, OP_ICONST);
1747 temp->inst_c0 = 0x7fffffff;
1748 temp->dreg = mono_alloc_ireg (cfg);
1750 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1751 temp2->sreg1 = ins->sreg1;
1752 temp2->sreg2 = temp->dreg;
1754 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1755 temp->inst_p1 = (char*)"OverflowException";
1757 ins->opcode = OP_MOVE;
1759 case OP_FCONV_TO_I4:
1760 case OP_FCONV_TO_I2:
1761 case OP_FCONV_TO_U2:
1762 case OP_FCONV_TO_I1:
1763 case OP_FCONV_TO_U1:
1764 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1765 temp->sreg1 = ins->sreg1;
1766 temp->dreg = ins->dreg;
1768 switch (ins->opcode) {
1769 case OP_FCONV_TO_I4:
1770 ins->opcode = OP_SEXT_I4;
1772 case OP_FCONV_TO_I2:
1773 ins->opcode = OP_SEXT_I2;
1775 case OP_FCONV_TO_U2:
1776 ins->opcode = OP_ZEXT_I4;
1778 case OP_FCONV_TO_I1:
1779 ins->opcode = OP_SEXT_I1;
1781 case OP_FCONV_TO_U1:
1782 ins->opcode = OP_ZEXT_I1;
1785 g_assert_not_reached ();
1787 ins->sreg1 = ins->dreg;
1795 bb->last_ins = last_ins;
1797 bb->max_vreg = cfg->next_vreg;
1801 * emit_load_volatile_arguments:
1803 * Load volatile arguments from the stack to the original input registers.
1804 * Required before a tail call.
1806 static Ia64CodegenState
1807 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1809 MonoMethod *method = cfg->method;
1810 MonoMethodSignature *sig;
1815 /* FIXME: Generate intermediate code instead */
1817 sig = mono_method_signature (method);
1819 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
1821 /* This is the opposite of the code in emit_prolog */
1822 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1823 ArgInfo *ainfo = cinfo->args + i;
1824 gint32 stack_offset;
1827 ins = cfg->args [i];
1829 if (sig->hasthis && (i == 0))
1830 arg_type = &mono_defaults.object_class->byval_arg;
1832 arg_type = sig->params [i - sig->hasthis];
1834 arg_type = mono_type_get_underlying_type (arg_type);
1836 stack_offset = ainfo->offset + ARGS_OFFSET;
1838 /* Save volatile arguments to the stack */
1839 if (ins->opcode != OP_REGVAR) {
1840 switch (ainfo->storage) {
1843 /* FIXME: big offsets */
1844 g_assert (ins->opcode == OP_REGOFFSET);
1845 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1846 if (arg_type->byref)
1847 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1849 switch (arg_type->type) {
1851 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1854 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1857 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1869 if (ins->opcode == OP_REGVAR) {
1870 /* Argument allocated to (non-volatile) register */
1871 switch (ainfo->storage) {
1873 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1874 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1877 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1878 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1889 static Ia64CodegenState
1890 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1895 /* Move return value to the target register */
1896 switch (ins->opcode) {
1898 case OP_VOIDCALL_REG:
1899 case OP_VOIDCALL_MEMBASE:
1903 case OP_CALL_MEMBASE:
1906 case OP_LCALL_MEMBASE:
1907 g_assert (ins->dreg == IA64_R8);
1911 case OP_FCALL_MEMBASE:
1912 g_assert (ins->dreg == 8);
1913 if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4)
1914 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
1918 case OP_VCALL_MEMBASE:
1921 case OP_VCALL2_MEMBASE: {
1924 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
1925 storage = cinfo->ret.storage;
1927 if (storage == ArgAggregate) {
1928 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
1930 /* Load address of stack space allocated for the return value */
1931 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
1932 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
1933 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
1935 for (i = 0; i < cinfo->ret.nregs; ++i) {
1936 switch (cinfo->ret.atype) {
1937 case AggregateNormal:
1938 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1940 case AggregateSingleHFA:
1941 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
1943 case AggregateDoubleHFA:
1944 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1947 g_assert_not_reached ();
1954 g_assert_not_reached ();
1960 #define add_patch_info(cfg,code,patch_type,data) do { \
1961 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
1964 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
1965 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1967 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
1969 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
1970 ia64_br_cond_pred (code, (predicate), 0); \
1973 static Ia64CodegenState
1974 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
1976 add_patch_info (cfg, code, patch_type, data);
1978 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
1980 /* mono_arch_patch_callsite will patch this */
1981 /* mono_arch_nullify_class_init_trampoline will patch this */
1982 ia64_movl (code, GP_SCRATCH_REG, 0);
1983 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
1984 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
1985 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
1986 ia64_br_call_reg (code, IA64_B0, IA64_B6);
1989 /* Can't use a direct call since the displacement might be too small */
1990 /* mono_arch_patch_callsite will patch this */
1991 ia64_movl (code, GP_SCRATCH_REG, 0);
1992 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
1993 ia64_br_call_reg (code, IA64_B0, IA64_B6);
1999 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2002 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2007 Ia64CodegenState code;
2008 guint8 *code_start = cfg->native_code + cfg->code_len;
2009 MonoInst *last_ins = NULL;
2010 guint last_offset = 0;
2013 if (cfg->opt & MONO_OPT_LOOP) {
2017 if (cfg->verbose_level > 2)
2018 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2020 cpos = bb->max_offset;
2022 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2026 offset = code_start - cfg->native_code;
2028 ia64_codegen_init (code, code_start);
2031 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2035 MONO_BB_FOR_EACH_INS (bb, ins) {
2036 offset = code.buf - cfg->native_code;
2038 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2040 while (offset + max_len + 16 > cfg->code_size) {
2041 ia64_codegen_close (code);
2043 offset = code.buf - cfg->native_code;
2045 cfg->code_size *= 2;
2046 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2047 code_start = cfg->native_code + offset;
2048 mono_jit_stats.code_reallocs++;
2050 ia64_codegen_init (code, code_start);
2053 mono_debug_record_line_number (cfg, ins, offset);
2055 switch (ins->opcode) {
2058 if (ia64_is_imm14 (ins->inst_c0))
2059 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2061 ia64_movl (code, ins->dreg, ins->inst_c0);
2064 add_patch_info (cfg, code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2065 ia64_movl (code, ins->dreg, 0);
2068 ia64_mov (code, ins->dreg, ins->sreg1);
2071 case OP_IA64_BR_COND: {
2073 if (ins->opcode == OP_IA64_BR_COND)
2075 if (ins->flags & MONO_INST_BRLABEL) {
2076 if (ins->inst_i0->inst_c0) {
2079 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2080 ia64_br_cond_pred (code, pred, 0);
2083 if (ins->inst_target_bb->native_offset) {
2084 guint8 *pos = code.buf + code.nins;
2086 ia64_br_cond_pred (code, pred, 0);
2087 ia64_begin_bundle (code);
2088 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2090 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2091 ia64_br_cond_pred (code, pred, 0);
2097 ia64_begin_bundle (code);
2098 ins->inst_c0 = code.buf - cfg->native_code;
2101 case OP_RELAXED_NOP:
2103 case OP_DUMMY_STORE:
2104 case OP_NOT_REACHED:
2108 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2109 ia64_br_cond_reg (code, IA64_B6);
2113 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2117 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2121 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2125 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2129 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2133 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2137 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2141 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2145 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2148 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2149 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2152 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2155 /* p6 and p7 is set if there is signed/unsigned overflow */
2157 /* Set p8-p9 == (sreg2 > 0) */
2158 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2160 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2162 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2163 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2164 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2165 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2167 /* res <u sreg1 => unsigned overflow */
2168 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2170 /* FIXME: Predicate this since this is a side effect */
2171 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2174 /* p6 and p7 is set if there is signed/unsigned overflow */
2176 /* Set p8-p9 == (sreg2 > 0) */
2177 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2179 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2181 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2182 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2183 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2184 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2186 /* sreg1 <u sreg2 => unsigned overflow */
2187 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2189 /* FIXME: Predicate this since this is a side effect */
2190 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2193 /* Same as OP_IADDCC */
2194 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2196 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2198 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2199 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2201 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2203 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2206 /* Same as OP_ISUBCC */
2208 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2210 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2212 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2213 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2215 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2217 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2222 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2227 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2231 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2235 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2240 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2245 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2247 case OP_ISHR_UN_IMM:
2248 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2249 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2251 case OP_LSHR_UN_IMM:
2252 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2255 /* Based on gcc code */
2256 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2257 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2258 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2259 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2262 case OP_STOREI1_MEMBASE_REG:
2263 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2265 case OP_STOREI2_MEMBASE_REG:
2266 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2268 case OP_STOREI4_MEMBASE_REG:
2269 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2271 case OP_STOREI8_MEMBASE_REG:
2272 case OP_STORE_MEMBASE_REG:
2273 if (ins->inst_offset != 0) {
2274 /* This is generated by local regalloc */
2275 if (ia64_is_imm14 (ins->inst_offset)) {
2276 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2278 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2279 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2281 ins->inst_destbasereg = GP_SCRATCH_REG;
2283 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2286 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2287 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2289 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2290 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2292 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2293 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2295 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2296 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2299 case OP_LOADU1_MEMBASE:
2300 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2302 case OP_LOADU2_MEMBASE:
2303 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2305 case OP_LOADU4_MEMBASE:
2306 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2308 case OP_LOADI1_MEMBASE:
2309 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2310 ia64_sxt1 (code, ins->dreg, ins->dreg);
2312 case OP_LOADI2_MEMBASE:
2313 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2314 ia64_sxt2 (code, ins->dreg, ins->dreg);
2316 case OP_LOADI4_MEMBASE:
2317 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2318 ia64_sxt4 (code, ins->dreg, ins->dreg);
2320 case OP_LOAD_MEMBASE:
2321 case OP_LOADI8_MEMBASE:
2322 if (ins->inst_offset != 0) {
2323 /* This is generated by local regalloc */
2324 if (ia64_is_imm14 (ins->inst_offset)) {
2325 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2327 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2328 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2330 ins->inst_basereg = GP_SCRATCH_REG;
2332 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2335 case OP_IA64_LOADU1_MEMBASE_INC:
2336 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2338 case OP_IA64_LOADU2_MEMBASE_INC:
2339 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2341 case OP_IA64_LOADU4_MEMBASE_INC:
2342 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2344 case OP_IA64_LOADI8_MEMBASE_INC:
2345 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2349 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2352 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2355 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2358 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2361 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2364 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2367 /* Compare opcodes */
2368 case OP_IA64_CMP4_EQ:
2369 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2371 case OP_IA64_CMP4_NE:
2372 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2374 case OP_IA64_CMP4_LE:
2375 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2377 case OP_IA64_CMP4_LT:
2378 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2380 case OP_IA64_CMP4_GE:
2381 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2383 case OP_IA64_CMP4_GT:
2384 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2386 case OP_IA64_CMP4_LT_UN:
2387 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2389 case OP_IA64_CMP4_LE_UN:
2390 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2392 case OP_IA64_CMP4_GT_UN:
2393 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2395 case OP_IA64_CMP4_GE_UN:
2396 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2398 case OP_IA64_CMP_EQ:
2399 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2401 case OP_IA64_CMP_NE:
2402 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2404 case OP_IA64_CMP_LE:
2405 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2407 case OP_IA64_CMP_LT:
2408 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2410 case OP_IA64_CMP_GE:
2411 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2413 case OP_IA64_CMP_GT:
2414 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2416 case OP_IA64_CMP_GT_UN:
2417 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2419 case OP_IA64_CMP_LT_UN:
2420 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2422 case OP_IA64_CMP_GE_UN:
2423 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2425 case OP_IA64_CMP_LE_UN:
2426 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2428 case OP_IA64_CMP4_EQ_IMM:
2429 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2431 case OP_IA64_CMP4_NE_IMM:
2432 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2434 case OP_IA64_CMP4_LE_IMM:
2435 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2437 case OP_IA64_CMP4_LT_IMM:
2438 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2440 case OP_IA64_CMP4_GE_IMM:
2441 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2443 case OP_IA64_CMP4_GT_IMM:
2444 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2446 case OP_IA64_CMP4_LT_UN_IMM:
2447 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2449 case OP_IA64_CMP4_LE_UN_IMM:
2450 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2452 case OP_IA64_CMP4_GT_UN_IMM:
2453 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2455 case OP_IA64_CMP4_GE_UN_IMM:
2456 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2458 case OP_IA64_CMP_EQ_IMM:
2459 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2461 case OP_IA64_CMP_NE_IMM:
2462 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2464 case OP_IA64_CMP_LE_IMM:
2465 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2467 case OP_IA64_CMP_LT_IMM:
2468 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2470 case OP_IA64_CMP_GE_IMM:
2471 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2473 case OP_IA64_CMP_GT_IMM:
2474 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2476 case OP_IA64_CMP_GT_UN_IMM:
2477 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2479 case OP_IA64_CMP_LT_UN_IMM:
2480 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2482 case OP_IA64_CMP_GE_UN_IMM:
2483 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2485 case OP_IA64_CMP_LE_UN_IMM:
2486 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2488 case OP_IA64_FCMP_EQ:
2489 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2491 case OP_IA64_FCMP_NE:
2492 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2494 case OP_IA64_FCMP_LT:
2495 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2497 case OP_IA64_FCMP_GT:
2498 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2500 case OP_IA64_FCMP_LE:
2501 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2503 case OP_IA64_FCMP_GE:
2504 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2506 case OP_IA64_FCMP_GT_UN:
2507 ia64_fcmp_gt_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_LT_UN:
2511 ia64_fcmp_lt_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_GE_UN:
2515 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2516 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2518 case OP_IA64_FCMP_LE_UN:
2519 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2520 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2523 case OP_COND_EXC_IOV:
2524 case OP_COND_EXC_OV:
2525 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2527 case OP_COND_EXC_IC:
2529 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2531 case OP_IA64_COND_EXC:
2532 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2535 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2536 ia64_no_stop (code);
2537 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2539 case OP_ICONV_TO_I1:
2540 case OP_LCONV_TO_I1:
2541 /* FIXME: Is this needed ? */
2542 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2544 case OP_ICONV_TO_I2:
2545 case OP_LCONV_TO_I2:
2546 /* FIXME: Is this needed ? */
2547 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2549 case OP_LCONV_TO_I4:
2550 /* FIXME: Is this needed ? */
2551 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2553 case OP_ICONV_TO_U1:
2554 case OP_LCONV_TO_U1:
2555 /* FIXME: Is this needed */
2556 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2558 case OP_ICONV_TO_U2:
2559 case OP_LCONV_TO_U2:
2560 /* FIXME: Is this needed */
2561 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2563 case OP_LCONV_TO_U4:
2564 /* FIXME: Is this needed */
2565 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2567 case OP_ICONV_TO_I8:
2569 case OP_LCONV_TO_I8:
2571 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2573 case OP_LCONV_TO_U8:
2575 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2582 double d = *(double *)ins->inst_p0;
2584 if ((d == 0.0) && (mono_signbit (d) == 0))
2585 ia64_fmov (code, ins->dreg, 0);
2587 ia64_fmov (code, ins->dreg, 1);
2589 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2590 ia64_movl (code, GP_SCRATCH_REG, 0);
2591 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2596 float f = *(float *)ins->inst_p0;
2598 if ((f == 0.0) && (mono_signbit (f) == 0))
2599 ia64_fmov (code, ins->dreg, 0);
2601 ia64_fmov (code, ins->dreg, 1);
2603 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2604 ia64_movl (code, GP_SCRATCH_REG, 0);
2605 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2610 ia64_fmov (code, ins->dreg, ins->sreg1);
2612 case OP_STORER8_MEMBASE_REG:
2613 if (ins->inst_offset != 0) {
2614 /* This is generated by local regalloc */
2615 if (ia64_is_imm14 (ins->inst_offset)) {
2616 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2618 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2619 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2621 ins->inst_destbasereg = GP_SCRATCH_REG;
2623 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2625 case OP_STORER4_MEMBASE_REG:
2626 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2627 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2629 case OP_LOADR8_MEMBASE:
2630 if (ins->inst_offset != 0) {
2631 /* This is generated by local regalloc */
2632 if (ia64_is_imm14 (ins->inst_offset)) {
2633 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2635 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2636 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2638 ins->inst_basereg = GP_SCRATCH_REG;
2640 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2642 case OP_LOADR4_MEMBASE:
2643 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2644 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2646 case OP_ICONV_TO_R4:
2647 case OP_LCONV_TO_R4:
2648 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2649 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2650 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2652 case OP_ICONV_TO_R8:
2653 case OP_LCONV_TO_R8:
2654 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2655 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2656 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2658 case OP_FCONV_TO_R4:
2659 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2661 case OP_FCONV_TO_I8:
2663 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2664 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2667 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2670 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2673 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2676 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2680 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2681 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2683 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2684 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2685 /* Positive infinity */
2686 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2687 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2688 /* Negative infinity */
2689 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2690 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2695 /* ensure ins->sreg1 is not NULL */
2696 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2699 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2700 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2708 call = (MonoCallInst*)ins;
2710 if (ins->flags & MONO_INST_HAS_METHOD)
2711 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2713 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2715 code = emit_move_return_value (cfg, ins, code);
2723 case OP_VOIDCALL_REG: {
2724 MonoCallInst *call = (MonoCallInst*)ins;
2729 * mono_arch_find_this_arg () needs to find the this argument in a global
2732 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2733 out_reg = cfg->arch.reg_out0;
2734 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
2736 ia64_mov (code, IA64_R10, out_reg);
2739 ia64_mov (code, IA64_R8, ins->sreg1);
2740 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2741 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2742 ia64_ld8 (code, IA64_GP, IA64_R8);
2743 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2745 code = emit_move_return_value (cfg, ins, code);
2748 case OP_FCALL_MEMBASE:
2749 case OP_LCALL_MEMBASE:
2750 case OP_VCALL_MEMBASE:
2751 case OP_VCALL2_MEMBASE:
2752 case OP_VOIDCALL_MEMBASE:
2753 case OP_CALL_MEMBASE: {
2754 MonoCallInst *call = (MonoCallInst*)ins;
2759 * There are no membase instructions on ia64, but we can't
2760 * lower this since get_vcall_slot_addr () needs to decode it.
2763 /* Keep this in synch with get_vcall_slot_addr */
2764 ia64_mov (code, IA64_R11, ins->sreg1);
2765 if (ia64_is_imm14 (ins->inst_offset))
2766 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2768 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2769 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2772 if (call->method && ins->inst_offset < 0) {
2774 * This is a possible IMT call so save the IMT method in a global
2775 * register where mono_arch_find_imt_method () and its friends can
2778 ia64_movl (code, IA64_R9, call->method);
2782 * mono_arch_find_this_arg () needs to find the this argument in a global
2785 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2786 out_reg = cfg->arch.reg_out0;
2787 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
2789 ia64_mov (code, IA64_R10, out_reg);
2791 ia64_begin_bundle (code);
2792 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2794 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2796 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2799 * This nop will tell get_vcall_slot_addr that this is a virtual
2802 ia64_nop_i (code, 0x12345);
2804 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2806 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2808 code = emit_move_return_value (cfg, ins, code);
2813 * Keep in sync with the code in emit_epilog.
2816 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2819 g_assert (!cfg->method->save_lmf);
2821 /* Load arguments into their original registers */
2822 code = emit_load_volatile_arguments (cfg, code);
2824 if (cfg->arch.stack_alloc_size) {
2825 if (cfg->arch.omit_fp) {
2826 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2827 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2829 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2830 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2834 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2836 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2837 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2839 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2840 ia64_movl (code, GP_SCRATCH_REG, 0);
2841 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2842 ia64_br_cond_reg (code, IA64_B6);
2847 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
2853 /* FIXME: Sigaltstack support */
2855 /* keep alignment */
2856 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2857 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2858 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2860 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2862 ia64_mov (code, ins->dreg, IA64_SP);
2864 /* An area at sp is reserved by the ABI for parameter passing */
2865 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2866 if (ia64_is_adds_imm (abi_offset))
2867 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2869 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2870 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2873 if (ins->flags & MONO_INST_INIT) {
2875 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2877 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2880 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2881 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2882 ia64_br_cond_pred (code, 8, -2);
2884 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2886 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2891 case OP_LOCALLOC_IMM: {
2894 /* FIXME: Sigaltstack support */
2896 gssize size = ins->inst_imm;
2897 size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
2899 if (ia64_is_adds_imm (size))
2900 ia64_adds_imm (code, GP_SCRATCH_REG, size, IA64_R0);
2902 ia64_movl (code, GP_SCRATCH_REG, size);
2904 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2905 ia64_mov (code, ins->dreg, IA64_SP);
2907 /* An area at sp is reserved by the ABI for parameter passing */
2908 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
2909 if (ia64_is_adds_imm (abi_offset))
2910 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2912 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2913 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2916 if (ins->flags & MONO_INST_INIT) {
2918 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2920 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2923 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2924 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2925 ia64_br_cond_pred (code, 8, -2);
2927 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2929 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2935 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2936 ia64_ld8 (code, ins->dreg, ins->dreg);
2939 /* Synchronization */
2940 case OP_MEMORY_BARRIER:
2943 case OP_ATOMIC_ADD_IMM_NEW_I4:
2944 g_assert (ins->inst_offset == 0);
2945 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2946 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2948 case OP_ATOMIC_ADD_IMM_NEW_I8:
2949 g_assert (ins->inst_offset == 0);
2950 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2951 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2953 case OP_ATOMIC_EXCHANGE_I4:
2954 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2955 ia64_sxt4 (code, ins->dreg, ins->dreg);
2957 case OP_ATOMIC_EXCHANGE_I8:
2958 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2960 case OP_ATOMIC_ADD_NEW_I4: {
2961 guint8 *label, *buf;
2963 /* From libatomic_ops */
2966 ia64_begin_bundle (code);
2967 label = code.buf + code.nins;
2968 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2969 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2970 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2971 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2972 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2973 buf = code.buf + code.nins;
2974 ia64_br_cond_pred (code, 7, 0);
2975 ia64_begin_bundle (code);
2976 ia64_patch (buf, label);
2977 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2980 case OP_ATOMIC_ADD_NEW_I8: {
2981 guint8 *label, *buf;
2983 /* From libatomic_ops */
2986 ia64_begin_bundle (code);
2987 label = code.buf + code.nins;
2988 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2989 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2990 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2991 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2992 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2993 buf = code.buf + code.nins;
2994 ia64_br_cond_pred (code, 7, 0);
2995 ia64_begin_bundle (code);
2996 ia64_patch (buf, label);
2997 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3001 /* Exception handling */
3002 case OP_CALL_HANDLER:
3004 * Using a call instruction would mess up the register stack, so
3005 * save the return address to a register and use a
3008 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3009 ia64_mov (code, IA64_R15, IA64_R0);
3010 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3011 /* Add the length of OP_CALL_HANDLER */
3012 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3013 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3014 ia64_movl (code, GP_SCRATCH_REG2, 0);
3015 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3016 ia64_br_cond_reg (code, IA64_B6);
3017 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3019 case OP_START_HANDLER: {
3021 * We receive the return address in GP_SCRATCH_REG.
3023 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3026 * R15 determines our caller. It is used since it is writable using
3028 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3029 * R15 != 0 means we are called by call_filter ().
3031 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3032 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3034 ia64_br_cond_pred (code, 6, 6);
3037 * Called by call_filter:
3038 * Allocate a new stack frame, and set the fp register from the
3039 * value passed in by the caller.
3040 * We allocate a similar frame as is done by the prolog, so
3041 * if an exception is thrown while executing the filter, the
3042 * unwinder can unwind through the filter frame using the unwind
3043 * info for the prolog.
3045 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);
3046 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3047 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3048 ia64_mov (code, cfg->frame_reg, IA64_R15);
3049 /* Signal to endfilter that we are called by call_filter */
3050 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3052 /* Branch target: */
3053 if (ia64_is_imm14 (spvar->inst_offset))
3054 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3056 ia64_movl (code, GP_SCRATCH_REG2, spvar->inst_offset);
3057 ia64_add (code, GP_SCRATCH_REG2, cfg->frame_reg, GP_SCRATCH_REG2);
3060 /* Save the return address */
3061 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3062 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3067 case OP_ENDFILTER: {
3068 /* FIXME: Return the value in ENDFILTER */
3069 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3071 /* Load the return address */
3072 if (ia64_is_imm14 (spvar->inst_offset)) {
3073 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3075 ia64_movl (code, GP_SCRATCH_REG, spvar->inst_offset);
3076 ia64_add (code, GP_SCRATCH_REG, cfg->frame_reg, GP_SCRATCH_REG);
3078 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3081 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3082 ia64_br_cond_pred (code, 7, 4);
3084 /* Called by call_filter */
3086 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3087 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3088 ia64_br_ret_reg (code, IA64_B0);
3090 /* Called by CALL_HANDLER */
3091 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3092 ia64_br_cond_reg (code, IA64_B6);
3096 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3097 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3098 (gpointer)"mono_arch_throw_exception");
3101 * This might be the last instruction in the method, so add a dummy
3102 * instruction so the unwinder will work.
3104 ia64_break_i (code, 0);
3107 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3108 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3109 (gpointer)"mono_arch_rethrow_exception");
3111 ia64_break_i (code, 0);
3115 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3116 g_assert_not_reached ();
3119 if ((code.buf - cfg->native_code - offset) > max_len) {
3120 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3121 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3122 g_assert_not_reached ();
3128 last_offset = offset;
3131 ia64_codegen_close (code);
3133 cfg->code_len = code.buf - cfg->native_code;
3137 mono_arch_register_lowlevel_calls (void)
3141 static Ia64InsType ins_types_in_template [32][3] = {
3142 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3143 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3144 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3145 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3146 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3147 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3150 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3151 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3152 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3153 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3154 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3155 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3156 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3157 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3158 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3159 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3160 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3161 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3164 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3165 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3166 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3167 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3170 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3171 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3176 static gboolean stops_in_template [32][3] = {
3177 { FALSE, FALSE, FALSE },
3178 { FALSE, FALSE, TRUE },
3179 { FALSE, TRUE, FALSE },
3180 { FALSE, TRUE, TRUE },
3181 { FALSE, FALSE, FALSE },
3182 { FALSE, FALSE, TRUE },
3183 { FALSE, FALSE, FALSE },
3184 { FALSE, FALSE, FALSE },
3186 { FALSE, FALSE, FALSE },
3187 { FALSE, FALSE, TRUE },
3188 { TRUE, FALSE, FALSE },
3189 { TRUE, FALSE, TRUE },
3190 { FALSE, FALSE, FALSE },
3191 { FALSE, FALSE, TRUE },
3192 { FALSE, FALSE, FALSE },
3193 { FALSE, FALSE, TRUE },
3195 { FALSE, FALSE, FALSE },
3196 { FALSE, FALSE, TRUE },
3197 { FALSE, FALSE, FALSE },
3198 { FALSE, FALSE, TRUE },
3199 { FALSE, FALSE, FALSE },
3200 { FALSE, FALSE, FALSE },
3201 { FALSE, FALSE, FALSE },
3202 { FALSE, FALSE, TRUE },
3204 { FALSE, FALSE, FALSE },
3205 { FALSE, FALSE, TRUE },
3206 { FALSE, FALSE, FALSE },
3207 { FALSE, FALSE, FALSE },
3208 { FALSE, FALSE, FALSE },
3209 { FALSE, FALSE, TRUE },
3210 { FALSE, FALSE, FALSE },
3211 { FALSE, FALSE, FALSE }
3214 static int last_stop_in_template [32] = {
3215 -1, 2, 1, 2, -1, 2, -1, -1,
3216 -1, 2, 0, 2, -1, 2, -1, 2,
3217 -1, 2, -1, 2, -1, -1, -1, 2,
3218 -1, 2, -1, -1, -1, 2, -1, -1
3221 static guint64 nops_for_ins_types [6] = {
3230 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3237 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3239 #define DEBUG_INS_SCHED(a)
3243 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3245 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3246 guint8 *deps = code->dep_info;
3247 gboolean need_stop, no_stop;
3249 for (i = 0; i < code->nins; ++i)
3253 current_deps_start = 0;
3254 current_ins_start = 0;
3255 deps_start [ins_index] = current_ins_start;
3258 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3259 while (pos < code->dep_info_pos) {
3261 switch (deps [pos]) {
3262 case IA64_END_OF_INS:
3264 current_ins_start = pos + 2;
3265 deps_start [ins_index] = current_ins_start;
3267 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3272 reg = deps [pos + 1];
3274 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3275 for (i = current_deps_start; i < current_ins_start; i += 2)
3276 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3280 reg = code->dep_info [pos + 1];
3282 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3283 for (i = current_deps_start; i < current_ins_start; i += 2)
3284 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3288 reg = deps [pos + 1];
3290 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3291 for (i = current_deps_start; i < current_ins_start; i += 2)
3292 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3295 case IA64_READ_PR_BRANCH:
3296 reg = deps [pos + 1];
3298 /* Writes to prs by non-float instructions are visible to branches */
3299 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3300 for (i = current_deps_start; i < current_ins_start; i += 2)
3301 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3305 reg = code->dep_info [pos + 1];
3307 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3308 for (i = current_deps_start; i < current_ins_start; i += 2)
3309 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3312 case IA64_WRITE_PR_FLOAT:
3313 reg = code->dep_info [pos + 1];
3315 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3316 for (i = current_deps_start; i < current_ins_start; i += 2)
3317 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3321 reg = deps [pos + 1];
3323 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3324 for (i = current_deps_start; i < current_ins_start; i += 2)
3325 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3329 reg = code->dep_info [pos + 1];
3331 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3332 for (i = current_deps_start; i < current_ins_start; i += 2)
3333 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3336 case IA64_READ_BR_BRANCH:
3337 reg = deps [pos + 1];
3339 /* Writes to brs are visible to branches */
3340 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3343 reg = deps [pos + 1];
3345 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3346 for (i = current_deps_start; i < current_ins_start; i += 2)
3347 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3351 reg = code->dep_info [pos + 1];
3353 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3354 for (i = current_deps_start; i < current_ins_start; i += 2)
3355 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3359 reg = deps [pos + 1];
3361 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3362 for (i = current_deps_start; i < current_ins_start; i += 2)
3363 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3367 reg = code->dep_info [pos + 1];
3369 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3370 for (i = current_deps_start; i < current_ins_start; i += 2)
3371 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3376 * Explicitly indicate that a stop is not required. Useful for
3377 * example when two predicated instructions with negated predicates
3378 * write the same registers.
3383 g_assert_not_reached ();
3387 if (need_stop && !no_stop) {
3388 g_assert (ins_index > 0);
3389 stops [ins_index - 1] = 1;
3391 DEBUG_INS_SCHED (printf ("STOP\n"));
3392 current_deps_start = current_ins_start;
3394 /* Skip remaining deps for this instruction */
3395 while (deps [pos] != IA64_END_OF_INS)
3400 if (code->nins > 0) {
3401 /* No dependency info for the last instruction */
3402 stops [code->nins - 1] = 1;
3405 deps_start [code->nins] = code->dep_info_pos;
3409 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3411 int stop_pos, i, deps_to_shift, dep_shift;
3413 g_assert (n <= code->nins);
3415 // if (n > 1) printf ("FOUND: %ld.\n", template);
3417 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3419 stop_pos = last_stop_in_template [template] + 1;
3423 /* Compute the number of 'real' instructions before the stop */
3424 deps_to_shift = stop_pos;
3425 if (stop_pos >= 3 && (nops & (1 << 2)))
3427 if (stop_pos >= 2 && (nops & (1 << 1)))
3429 if (stop_pos >= 1 && (nops & (1 << 0)))
3433 * We have to keep some dependencies whose instructions have been shifted
3434 * out of the buffer. So nullify the end_of_ins markers in the dependency
3437 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3438 if (code->dep_info [i] == IA64_END_OF_INS)
3439 code->dep_info [i] = IA64_NONE;
3441 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3442 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3443 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3445 dep_shift = deps_start [deps_to_shift];
3446 for (i = 0; i < code->nins + 1 - n; ++i)
3447 deps_start [i] = deps_start [n + i] - dep_shift;
3449 /* Determine the exact positions of instructions with unwind ops */
3450 if (code->unw_op_count) {
3452 int curr_ins, curr_ins_pos;
3455 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3456 for (i = 0; i < 3; ++i) {
3457 if (! (nops & (1 << i))) {
3458 ins_pos [curr_ins] = curr_ins_pos + i;
3463 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3464 if (code->unw_ops_pos [i] < n) {
3465 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3466 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3469 if (code->unw_op_pos < code->unw_op_count)
3470 code->unw_op_pos += n;
3473 if (n == code->nins) {
3478 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3479 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3480 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3486 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3488 int i, ins_type, template, nins_to_emit;
3489 int deps_start [16];
3494 * We implement a simple scheduler which tries to put three instructions
3495 * per bundle, then two, then one.
3497 ia64_analyze_deps (code, deps_start, stops);
3499 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3500 /* Find a suitable template */
3501 for (template = 0; template < 32; ++template) {
3502 if (stops_in_template [template][0] != stops [0] ||
3503 stops_in_template [template][1] != stops [1] ||
3504 stops_in_template [template][2] != stops [2])
3508 for (i = 0; i < 3; ++i) {
3509 ins_type = ins_types_in_template [template][i];
3510 switch (code->itypes [i]) {
3511 case IA64_INS_TYPE_A:
3512 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3515 found &= (ins_type == code->itypes [i]);
3521 found = debug_ins_sched ();
3524 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3530 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3531 /* Wait for more instructions */
3534 /* If it didn't work out, try putting two instructions into one bundle */
3535 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3536 /* Try a nop at the end */
3537 for (template = 0; template < 32; ++template) {
3538 if (stops_in_template [template][0] != stops [0] ||
3539 ((stops_in_template [template][1] != stops [1]) &&
3540 (stops_in_template [template][2] != stops [1])))
3544 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3545 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3548 if (!debug_ins_sched ())
3551 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);
3556 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3557 /* Wait for more instructions */
3560 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3561 /* Try a nop in the middle */
3562 for (template = 0; template < 32; ++template) {
3563 if (((stops_in_template [template][0] != stops [0]) &&
3564 (stops_in_template [template][1] != stops [0])) ||
3565 stops_in_template [template][2] != stops [1])
3568 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3569 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3572 if (!debug_ins_sched ())
3575 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);
3580 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3581 /* Try a nop at the beginning */
3582 for (template = 0; template < 32; ++template) {
3583 if ((stops_in_template [template][1] != stops [0]) ||
3584 (stops_in_template [template][2] != stops [1]))
3587 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3588 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3591 if (!debug_ins_sched ())
3594 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);
3599 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3600 /* Wait for more instructions */
3604 nins_to_emit = code->nins;
3608 while (nins_to_emit > 0) {
3609 if (!debug_ins_sched ())
3611 switch (code->itypes [0]) {
3612 case IA64_INS_TYPE_A:
3614 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3616 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3618 case IA64_INS_TYPE_I:
3620 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3622 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3624 case IA64_INS_TYPE_M:
3626 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3628 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3630 case IA64_INS_TYPE_B:
3632 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3634 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3636 case IA64_INS_TYPE_F:
3638 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3640 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3642 case IA64_INS_TYPE_LX:
3643 if (stops [0] || stops [1])
3644 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3646 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3650 g_assert_not_reached ();
3656 unw_dyn_region_info_t*
3657 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3659 unw_dyn_region_info_t *r;
3661 g_assert (code->nins == 0);
3662 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3663 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3664 r->op_count = code->unw_op_count;
3665 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3666 code->unw_op_count = 0;
3667 code->unw_op_pos = 0;
3668 code->region_start = code->buf;
3674 ia64_patch (unsigned char* code, gpointer target)
3677 guint64 instructions [3];
3678 guint8 gen_buf [16];
3679 Ia64CodegenState gen;
3684 * code encodes both the position inside the buffer and code.nins when
3685 * the instruction was emitted.
3687 ins_to_skip = (guint64)code % 16;
3688 code = (unsigned char*)((guint64)code & ~15);
3691 * Search for the first instruction which is 'patchable', skipping
3692 * ins_to_skip instructions.
3697 template = ia64_bundle_template (code);
3698 instructions [0] = ia64_bundle_ins1 (code);
3699 instructions [1] = ia64_bundle_ins2 (code);
3700 instructions [2] = ia64_bundle_ins3 (code);
3702 ia64_codegen_init (gen, gen_buf);
3705 for (i = 0; i < 3; ++i) {
3706 guint64 ins = instructions [i];
3707 int opcode = ia64_ins_opcode (ins);
3709 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3717 switch (ins_types_in_template [template][i]) {
3718 case IA64_INS_TYPE_A:
3719 case IA64_INS_TYPE_M:
3720 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3722 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3723 instructions [i] = gen.instructions [0];
3729 case IA64_INS_TYPE_B:
3730 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3732 gint64 disp = ((guint8*)target - code) >> 4;
3735 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3737 instructions [i] = gen.instructions [0];
3740 else if (opcode == 5) {
3742 gint64 disp = ((guint8*)target - code) >> 4;
3745 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3746 instructions [i] = gen.instructions [0];
3752 case IA64_INS_TYPE_LX:
3756 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3758 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3759 instructions [1] = gen.instructions [0];
3760 instructions [2] = gen.instructions [1];
3773 ia64_codegen_init (gen, code);
3774 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3784 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3786 MonoJumpInfo *patch_info;
3788 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3789 unsigned char *ip = patch_info->ip.i + code;
3790 const unsigned char *target;
3792 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3794 if (patch_info->type == MONO_PATCH_INFO_NONE)
3796 if (mono_compile_aot) {
3800 ia64_patch (ip, (gpointer)target);
3805 mono_arch_emit_prolog (MonoCompile *cfg)
3807 MonoMethod *method = cfg->method;
3808 MonoMethodSignature *sig;
3810 int alloc_size, pos, i;
3811 Ia64CodegenState code;
3814 sig = mono_method_signature (method);
3817 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
3819 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3821 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3822 cfg->code_size += 1024;
3823 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3824 cfg->code_size += 1024;
3826 cfg->native_code = g_malloc (cfg->code_size);
3828 ia64_codegen_init (code, cfg->native_code);
3830 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3831 if (cfg->param_area)
3832 alloc_size += cfg->param_area;
3836 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3838 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3839 /* Force sp to be saved/restored */
3840 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3842 cfg->arch.stack_alloc_size = alloc_size;
3846 if (method->save_lmf) {
3847 /* No LMF on IA64 */
3852 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3853 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);
3854 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3855 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3857 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3858 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3859 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3860 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3861 ia64_mov (code, cfg->frame_reg, IA64_SP);
3865 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3866 int pagesize = getpagesize ();
3868 if (alloc_size >= pagesize) {
3869 gint32 remaining_size = alloc_size;
3871 /* Generate stack touching code */
3872 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3873 while (remaining_size >= pagesize) {
3874 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3875 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3876 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3877 remaining_size -= pagesize;
3881 if (ia64_is_imm14 (-alloc_size)) {
3882 if (cfg->arch.omit_fp)
3883 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3884 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3887 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3888 if (cfg->arch.omit_fp)
3889 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3890 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3894 ia64_begin_bundle (code);
3896 /* Initialize unwind info */
3897 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3899 if (sig->ret->type != MONO_TYPE_VOID) {
3900 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3901 /* Save volatile arguments to the stack */
3906 /* Keep this in sync with emit_load_volatile_arguments */
3907 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3908 ArgInfo *ainfo = cinfo->args + i;
3909 gint32 stack_offset;
3912 inst = cfg->args [i];
3914 if (sig->hasthis && (i == 0))
3915 arg_type = &mono_defaults.object_class->byval_arg;
3917 arg_type = sig->params [i - sig->hasthis];
3919 arg_type = mono_type_get_underlying_type (arg_type);
3921 stack_offset = ainfo->offset + ARGS_OFFSET;
3924 * FIXME: Native code might pass non register sized integers
3925 * without initializing the upper bits.
3927 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && !arg_type->byref && ainfo->storage == ArgInIReg) {
3928 int reg = cfg->arch.reg_in0 + ainfo->reg;
3930 switch (mono_type_to_load_membase (cfg, arg_type)) {
3931 case OP_LOADI1_MEMBASE:
3932 ia64_sxt1 (code, reg, reg);
3934 case OP_LOADU1_MEMBASE:
3935 ia64_zxt1 (code, reg, reg);
3937 case OP_LOADI2_MEMBASE:
3938 ia64_sxt2 (code, reg, reg);
3940 case OP_LOADU2_MEMBASE:
3941 ia64_zxt2 (code, reg, reg);
3948 /* Save volatile arguments to the stack */
3949 if (inst->opcode != OP_REGVAR) {
3950 switch (ainfo->storage) {
3953 case ArgInFloatRegR4:
3954 g_assert (inst->opcode == OP_REGOFFSET);
3955 if (ia64_is_adds_imm (inst->inst_offset))
3956 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3958 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3959 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3961 if (arg_type->byref)
3962 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3964 switch (arg_type->type) {
3966 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3969 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3972 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3980 if (ainfo->nslots != ainfo->nregs)
3983 g_assert (inst->opcode == OP_REGOFFSET);
3984 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3985 for (i = 0; i < ainfo->nregs; ++i) {
3986 switch (ainfo->atype) {
3987 case AggregateNormal:
3988 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3990 case AggregateSingleHFA:
3991 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3993 case AggregateDoubleHFA:
3994 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4002 g_assert_not_reached ();
4006 if (inst->opcode == OP_REGVAR) {
4007 /* Argument allocated to (non-volatile) register */
4008 switch (ainfo->storage) {
4010 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4011 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4014 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4015 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4023 if (method->save_lmf) {
4024 /* No LMF on IA64 */
4027 ia64_codegen_close (code);
4029 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4030 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4032 cfg->code_len = code.buf - cfg->native_code;
4034 g_assert (cfg->code_len < cfg->code_size);
4036 cfg->arch.prolog_end_offset = cfg->code_len;
4042 mono_arch_emit_epilog (MonoCompile *cfg)
4044 MonoMethod *method = cfg->method;
4046 int max_epilog_size = 16 * 4;
4047 Ia64CodegenState code;
4052 if (mono_jit_trace_calls != NULL)
4053 max_epilog_size += 1024;
4055 cfg->arch.epilog_begin_offset = cfg->code_len;
4057 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4058 cfg->code_size *= 2;
4059 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4060 mono_jit_stats.code_reallocs++;
4063 /* FIXME: Emit unwind info */
4065 buf = cfg->native_code + cfg->code_len;
4067 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4068 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4070 ia64_codegen_init (code, buf);
4072 /* the code restoring the registers must be kept in sync with OP_JMP */
4075 if (method->save_lmf) {
4076 /* No LMF on IA64 */
4079 /* Load returned vtypes into registers if needed */
4080 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4081 ainfo = &cinfo->ret;
4082 switch (ainfo->storage) {
4084 if (ainfo->nslots != ainfo->nregs)
4087 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4088 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4089 for (i = 0; i < ainfo->nregs; ++i) {
4090 switch (ainfo->atype) {
4091 case AggregateNormal:
4092 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4094 case AggregateSingleHFA:
4095 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4097 case AggregateDoubleHFA:
4098 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4101 g_assert_not_reached ();
4109 ia64_begin_bundle (code);
4111 code.region_start = cfg->native_code;
4113 /* Label the unwind state at the start of the exception throwing region */
4114 //ia64_unw_label_state (code, 1234);
4116 if (cfg->arch.stack_alloc_size) {
4117 if (cfg->arch.omit_fp) {
4118 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4119 ia64_unw_pop_frames (code, 1);
4120 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4122 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4123 ia64_unw_pop_frames (code, 1);
4124 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4128 ia64_unw_pop_frames (code, 1);
4129 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4132 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4133 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4134 ia64_br_ret_reg (code, IA64_B0);
4136 ia64_codegen_close (code);
4138 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4139 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4141 cfg->code_len = code.buf - cfg->native_code;
4143 g_assert (cfg->code_len < cfg->code_size);
4147 mono_arch_emit_exceptions (MonoCompile *cfg)
4149 MonoJumpInfo *patch_info;
4151 Ia64CodegenState code;
4152 gboolean empty = TRUE;
4153 //unw_dyn_region_info_t *r_exceptions;
4154 MonoClass *exc_classes [16];
4155 guint8 *exc_throw_start [16], *exc_throw_end [16];
4156 guint32 code_size = 0;
4158 /* Compute needed space */
4159 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4160 if (patch_info->type == MONO_PATCH_INFO_EXC)
4162 if (patch_info->type == MONO_PATCH_INFO_R8)
4163 code_size += 8 + 7; /* sizeof (double) + alignment */
4164 if (patch_info->type == MONO_PATCH_INFO_R4)
4165 code_size += 4 + 7; /* sizeof (float) + alignment */
4171 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4172 cfg->code_size *= 2;
4173 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4174 mono_jit_stats.code_reallocs++;
4177 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4179 /* The unwind state here is the same as before the epilog */
4180 //ia64_unw_copy_state (code, 1234);
4182 /* add code to raise exceptions */
4183 /* FIXME: Optimize this */
4185 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4186 switch (patch_info->type) {
4187 case MONO_PATCH_INFO_EXC: {
4188 MonoClass *exc_class;
4191 guint64 exc_token_index;
4193 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4194 g_assert (exc_class);
4195 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4196 throw_ip = cfg->native_code + patch_info->ip.i;
4198 ia64_begin_bundle (code);
4200 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4202 /* Find a throw sequence for the same exception class */
4203 for (i = 0; i < nthrows; ++i)
4204 if (exc_classes [i] == exc_class)
4208 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4210 if (ia64_is_adds_imm (offset))
4211 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4213 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4215 buf = code.buf + code.nins;
4216 ia64_br_cond_pred (code, 0, 0);
4217 ia64_begin_bundle (code);
4218 ia64_patch (buf, exc_throw_start [i]);
4220 patch_info->type = MONO_PATCH_INFO_NONE;
4225 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4227 ia64_begin_bundle (code);
4230 exc_classes [nthrows] = exc_class;
4231 exc_throw_start [nthrows] = code.buf;
4235 if (ia64_is_adds_imm (exc_token_index))
4236 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4238 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4240 patch_info->data.name = "mono_arch_throw_corlib_exception";
4241 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4242 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4245 ia64_movl (code, GP_SCRATCH_REG, 0);
4246 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4247 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4248 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4250 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4252 /* Patch up the throw offset */
4253 ia64_begin_bundle (code);
4255 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4258 exc_throw_end [nthrows] = code.buf;
4272 /* The unwinder needs this to work */
4273 ia64_break_i (code, 0);
4275 ia64_codegen_close (code);
4278 //r_exceptions = mono_ia64_create_unwind_region (&code);
4279 //cfg->arch.r_epilog = r_exceptions;
4281 cfg->code_len = code.buf - cfg->native_code;
4283 g_assert (cfg->code_len < cfg->code_size);
4287 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4289 Ia64CodegenState code;
4290 CallInfo *cinfo = NULL;
4291 MonoMethodSignature *sig;
4293 int i, n, stack_area = 0;
4295 ia64_codegen_init (code, p);
4297 /* Keep this in sync with mono_arch_get_argument_info */
4299 if (enable_arguments) {
4300 /* Allocate a new area on the stack and save arguments there */
4301 sig = mono_method_signature (cfg->method);
4303 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4305 n = sig->param_count + sig->hasthis;
4307 stack_area = ALIGN_TO (n * 8, 16);
4310 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4312 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4314 /* FIXME: Allocate out registers */
4316 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4318 /* Required by the ABI */
4319 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4321 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4322 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4324 /* Save arguments to the stack */
4325 for (i = 0; i < n; ++i) {
4326 ins = cfg->args [i];
4328 if (ins->opcode == OP_REGVAR) {
4329 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4330 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4331 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4334 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4335 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4336 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4337 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4338 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4339 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4344 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4347 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4349 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4350 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4352 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4354 if (enable_arguments && stack_area) {
4355 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4357 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4359 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4362 ia64_codegen_close (code);
4368 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4370 Ia64CodegenState code;
4371 CallInfo *cinfo = NULL;
4372 MonoMethod *method = cfg->method;
4373 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4375 ia64_codegen_init (code, p);
4377 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4379 /* Save return value + pass it to func */
4380 switch (cinfo->ret.storage) {
4384 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4385 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4388 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4389 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4390 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4391 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4393 case ArgValuetypeAddrInIReg:
4394 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4403 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4404 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4405 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4407 /* Restore return value */
4408 switch (cinfo->ret.storage) {
4412 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4415 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4416 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4418 case ArgValuetypeAddrInIReg:
4426 ia64_codegen_close (code);
4432 mono_arch_save_unwind_info (MonoCompile *cfg)
4436 /* FIXME: Unregister this for dynamic methods */
4438 di = g_malloc0 (sizeof (unw_dyn_info_t));
4439 di->start_ip = (unw_word_t) cfg->native_code;
4440 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4442 di->format = UNW_INFO_FORMAT_DYNAMIC;
4443 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4444 di->u.pi.regions = cfg->arch.r_pro;
4446 _U_dyn_register (di);
4450 unw_dyn_region_info_t *region = di->u.pi.regions;
4452 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4454 printf (" [Region: %d]\n", region->insn_count);
4455 region = region->next;
4462 mono_arch_flush_icache (guint8 *code, gint size)
4464 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4465 guint8* end = (guint8*)((guint64)code + size);
4467 #ifdef __INTEL_COMPILER
4468 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4475 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4476 /* FIXME: This could be increased to 128 on some cpus */
4483 mono_arch_flush_register_windows (void)
4485 /* Not needed because of libunwind */
4489 mono_arch_is_inst_imm (gint64 imm)
4491 /* The lowering pass will take care of it */
4497 * Determine whenever the trap whose info is in SIGINFO is caused by
4501 mono_arch_is_int_overflow (void *sigctx, void *info)
4503 /* Division is emulated with explicit overflow checks */
4508 mono_arch_get_patch_offset (guint8 *code)
4516 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4518 guint8 *bundle2 = code - 48;
4519 guint8 *bundle3 = code - 32;
4520 guint8 *bundle4 = code - 16;
4521 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4522 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4523 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4524 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4525 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4526 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4527 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4528 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4529 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4532 * Virtual calls are made with:
4534 * [MII] ld8 r31=[r8]
4538 * mov.sptk b6=r31,0x2000000000f32a80
4545 * br.call.sptk.few b0=b6;;
4548 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4549 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4550 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4551 (ins31 == IA64_NOP_M) &&
4552 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4553 (ins33 == IA64_NOP_I) &&
4554 (ins41 == IA64_NOP_M) &&
4555 (ins42 == IA64_NOP_I) &&
4556 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4557 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4558 g_assert (ins21 == IA64_NOP_M);
4559 g_assert (ins23 == IA64_NOP_I);
4560 g_assert (ia64_ins_opcode (ins22) == 0);
4561 g_assert (ia64_ins_x3 (ins22) == 7);
4562 g_assert (ia64_ins_x (ins22) == 0);
4563 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4565 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4567 return regs [IA64_R11];
4574 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4578 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4581 return (gpointer*)(gpointer)((char*)vt + displacement);
4585 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4592 static gboolean tls_offset_inited = FALSE;
4595 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4597 if (!tls_offset_inited) {
4598 tls_offset_inited = TRUE;
4600 appdomain_tls_offset = mono_domain_get_tls_offset ();
4601 thread_tls_offset = mono_thread_get_tls_offset ();
4606 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4610 #ifdef MONO_ARCH_HAVE_IMT
4613 * LOCKING: called with the domain lock held
4616 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4617 gpointer fail_tramp)
4621 guint8 *start, *buf;
4622 Ia64CodegenState code;
4624 g_assert (!fail_tramp);
4627 buf = g_malloc0 (size);
4628 ia64_codegen_init (code, buf);
4630 /* IA64_R9 contains the IMT method */
4632 for (i = 0; i < count; ++i) {
4633 MonoIMTCheckItem *item = imt_entries [i];
4634 ia64_begin_bundle (code);
4635 item->code_target = (guint8*)code.buf + code.nins;
4636 if (item->is_equals) {
4637 if (item->check_target_idx) {
4638 if (!item->compare_done) {
4639 ia64_movl (code, GP_SCRATCH_REG, item->key);
4640 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4642 item->jmp_code = (guint8*)code.buf + code.nins;
4643 ia64_br_cond_pred (code, 7, 0);
4645 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4646 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4647 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4648 ia64_br_cond_reg (code, IA64_B6);
4650 /* enable the commented code to assert on wrong method */
4651 #if ENABLE_WRONG_METHOD_CHECK
4652 g_assert_not_reached ();
4654 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4655 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4656 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4657 ia64_br_cond_reg (code, IA64_B6);
4658 #if ENABLE_WRONG_METHOD_CHECK
4659 g_assert_not_reached ();
4663 ia64_movl (code, GP_SCRATCH_REG, item->key);
4664 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4665 item->jmp_code = (guint8*)code.buf + code.nins;
4666 ia64_br_cond_pred (code, 6, 0);
4669 /* patch the branches to get to the target items */
4670 for (i = 0; i < count; ++i) {
4671 MonoIMTCheckItem *item = imt_entries [i];
4672 if (item->jmp_code) {
4673 if (item->check_target_idx) {
4674 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4679 ia64_codegen_close (code);
4680 g_assert (code.buf - buf <= size);
4682 size = code.buf - buf;
4683 start = mono_code_manager_reserve (domain->code_mp, size);
4684 memcpy (start, buf, size);
4686 mono_arch_flush_icache (start, size);
4688 mono_stats.imt_thunks_size += size;
4694 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4696 return regs [IA64_R9];
4700 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
4702 /* Done by the implementation of the CALL_MEMBASE opcodes */
4707 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
4709 return (gpointer)regs [IA64_R10];
4713 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4715 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4719 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
4725 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4727 MonoInst *ins = NULL;
4729 if (cmethod->klass->image == mono_defaults.corlib &&
4730 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4731 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4734 * We don't use the generic version in mini_emit_inst_for_method () since we
4735 * ia64 has atomic_add_imm opcodes.
4737 if (strcmp (cmethod->name, "Increment") == 0) {
4740 if (fsig->params [0]->type == MONO_TYPE_I4)
4741 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4742 else if (fsig->params [0]->type == MONO_TYPE_I8)
4743 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4745 g_assert_not_reached ();
4746 MONO_INST_NEW (cfg, ins, opcode);
4747 ins->dreg = mono_alloc_preg (cfg);
4749 ins->inst_basereg = args [0]->dreg;
4750 ins->inst_offset = 0;
4751 MONO_ADD_INS (cfg->cbb, ins);
4752 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4755 if (fsig->params [0]->type == MONO_TYPE_I4)
4756 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4757 else if (fsig->params [0]->type == MONO_TYPE_I8)
4758 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4760 g_assert_not_reached ();
4761 MONO_INST_NEW (cfg, ins, opcode);
4762 ins->dreg = mono_alloc_preg (cfg);
4764 ins->inst_basereg = args [0]->dreg;
4765 ins->inst_offset = 0;
4766 MONO_ADD_INS (cfg->cbb, ins);
4767 } else if (strcmp (cmethod->name, "Add") == 0) {
4769 gboolean is_imm = FALSE;
4772 if ((args [1]->opcode == OP_ICONST) || (args [1]->opcode == OP_I8CONST)) {
4773 imm = (args [1]->opcode == OP_ICONST) ? args [1]->inst_c0 : args [1]->inst_l;
4775 is_imm = (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
4779 if (fsig->params [0]->type == MONO_TYPE_I4)
4780 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4781 else if (fsig->params [0]->type == MONO_TYPE_I8)
4782 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4784 g_assert_not_reached ();
4786 MONO_INST_NEW (cfg, ins, opcode);
4787 ins->dreg = mono_alloc_ireg (cfg);
4788 ins->inst_basereg = args [0]->dreg;
4789 ins->inst_offset = 0;
4790 ins->inst_imm = imm;
4791 ins->type = (opcode == OP_ATOMIC_ADD_IMM_NEW_I4) ? STACK_I4 : STACK_I8;
4793 if (fsig->params [0]->type == MONO_TYPE_I4)
4794 opcode = OP_ATOMIC_ADD_NEW_I4;
4795 else if (fsig->params [0]->type == MONO_TYPE_I8)
4796 opcode = OP_ATOMIC_ADD_NEW_I8;
4798 g_assert_not_reached ();
4800 MONO_INST_NEW (cfg, ins, opcode);
4801 ins->dreg = mono_alloc_ireg (cfg);
4802 ins->inst_basereg = args [0]->dreg;
4803 ins->inst_offset = 0;
4804 ins->sreg2 = args [1]->dreg;
4805 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
4807 MONO_ADD_INS (cfg->cbb, ins);
4815 mono_arch_print_tree (MonoInst *tree, int arity)
4820 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4824 if (appdomain_tls_offset == -1)
4827 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4828 ins->inst_offset = appdomain_tls_offset;
4832 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4836 if (thread_tls_offset == -1)
4839 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4840 ins->inst_offset = thread_tls_offset;
4845 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4847 /* FIXME: implement */
4848 g_assert_not_reached ();