2 * mini-ia64.c: IA64 backend for the Mono code generator
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2003 Ximian, Inc.
15 #ifdef __INTEL_COMPILER
16 #include <ia64intrin.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/utils/mono-math.h>
26 #include "mini-ia64.h"
29 #include "jit-icalls.h"
31 static gint appdomain_tls_offset = -1;
32 static gint thread_tls_offset = -1;
34 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
36 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
39 * IA64 register usage:
40 * - local registers are used for global register allocation
41 * - r8..r11, r14..r30 is used for local register allocation
42 * - r31 is a scratch register used within opcode implementations
43 * - FIXME: Use out registers as well
44 * - the first three locals are used for saving ar.pfst, b0, and sp
45 * - compare instructions allways set p6 and p7
49 * There are a lot of places where generated code is disassembled/patched.
50 * The automatic bundling of instructions done by the code generation macros
51 * could complicate things, so it is best to call
52 * ia64_codegen_set_one_ins_per_bundle () at those places.
55 #define ARGS_OFFSET 16
57 #define GP_SCRATCH_REG 31
58 #define GP_SCRATCH_REG2 30
59 #define FP_SCRATCH_REG 32
60 #define FP_SCRATCH_REG2 33
62 #define LOOP_ALIGNMENT 8
63 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
65 static const char* gregs [] = {
66 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
67 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
68 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
69 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
70 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
71 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
72 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
73 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
74 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
75 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
76 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
77 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
78 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
82 mono_arch_regname (int reg)
90 static const char* fregs [] = {
91 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
92 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
93 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
94 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
95 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
96 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
97 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
98 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
99 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
100 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
101 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
102 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
103 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
107 mono_arch_fregname (int reg)
115 G_GNUC_UNUSED static void
120 G_GNUC_UNUSED static gboolean
123 static int count = 0;
126 if (count == atoi (getenv ("COUNT"))) {
130 if (count > atoi (getenv ("COUNT"))) {
138 debug_ins_sched (void)
141 return debug_count ();
151 return debug_count ();
158 ia64_patch (unsigned char* code, gpointer target);
165 ArgValuetypeAddrInIReg,
183 /* Only if storage == ArgAggregate */
193 gboolean need_stack_align;
199 #define DEBUG(a) if (cfg->verbose_level > 1) a
201 #define NEW_ICONST(cfg,dest,val) do { \
202 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
203 (dest)->opcode = OP_ICONST; \
204 (dest)->inst_c0 = (val); \
205 (dest)->type = STACK_I4; \
211 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
213 ainfo->offset = *stack_size;
215 if (*gr >= PARAM_REGS) {
216 ainfo->storage = ArgOnStack;
217 (*stack_size) += sizeof (gpointer);
220 ainfo->storage = ArgInIReg;
226 #define FLOAT_PARAM_REGS 8
229 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
231 ainfo->offset = *stack_size;
233 if (*gr >= PARAM_REGS) {
234 ainfo->storage = ArgOnStack;
235 (*stack_size) += sizeof (gpointer);
238 ainfo->storage = is_double ? ArgInFloatReg : ArgInFloatRegR4;
239 ainfo->reg = 8 + *fr;
246 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
248 guint32 *gr, guint32 *fr, guint32 *stack_size)
252 MonoMarshalType *info;
253 gboolean is_hfa = TRUE;
254 guint32 hfa_type = 0;
256 klass = mono_class_from_mono_type (type);
257 if (type->type == MONO_TYPE_TYPEDBYREF)
258 size = 3 * sizeof (gpointer);
259 else if (sig->pinvoke)
260 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
262 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
264 if (!sig->pinvoke || (size == 0)) {
265 /* Allways pass in memory */
266 ainfo->offset = *stack_size;
267 *stack_size += ALIGN_TO (size, 8);
268 ainfo->storage = ArgOnStack;
273 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
274 info = mono_marshal_load_type_info (klass);
276 for (i = 0; i < info->num_fields; ++i) {
277 guint32 ftype = info->fields [i].field->type->type;
278 if (!(info->fields [i].field->type->byref) &&
279 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
282 else if (hfa_type != ftype)
291 ainfo->storage = ArgAggregate;
292 ainfo->atype = AggregateNormal;
295 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
297 if (info->num_fields <= 8) {
299 ainfo->nregs = info->num_fields;
300 ainfo->nslots = ainfo->nregs;
306 if ((*fr) + info->num_fields > 8)
309 ainfo->reg = 8 + (*fr);
310 ainfo->nregs = info->num_fields;
311 ainfo->nslots = ainfo->nregs;
312 (*fr) += info->num_fields;
313 if (ainfo->atype == AggregateSingleHFA) {
315 * FIXME: Have to keep track of the parameter slot number, which is
316 * not the same as *gr.
318 (*gr) += ALIGN_TO (info->num_fields, 2) / 2;
320 (*gr) += info->num_fields;
326 /* This also handles returning of TypedByRef used by some icalls */
329 ainfo->reg = IA64_R8;
330 ainfo->nregs = (size + 7) / 8;
331 ainfo->nslots = ainfo->nregs;
338 ainfo->offset = *stack_size;
339 ainfo->nslots = (size + 7) / 8;
341 if (((*gr) + ainfo->nslots) <= 8) {
342 /* Fits entirely in registers */
343 ainfo->nregs = ainfo->nslots;
344 (*gr) += ainfo->nregs;
348 ainfo->nregs = 8 - (*gr);
350 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
356 * Obtain information about a call according to the calling convention.
357 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
358 * Gude" document for more information.
361 get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
365 int n = sig->hasthis + sig->param_count;
366 guint32 stack_size = 0;
368 MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
371 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
373 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
380 ret_type = mono_type_get_underlying_type (sig->ret);
381 ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
382 switch (ret_type->type) {
383 case MONO_TYPE_BOOLEAN:
394 case MONO_TYPE_FNPTR:
395 case MONO_TYPE_CLASS:
396 case MONO_TYPE_OBJECT:
397 case MONO_TYPE_SZARRAY:
398 case MONO_TYPE_ARRAY:
399 case MONO_TYPE_STRING:
400 cinfo->ret.storage = ArgInIReg;
401 cinfo->ret.reg = IA64_R8;
405 cinfo->ret.storage = ArgInIReg;
406 cinfo->ret.reg = IA64_R8;
410 cinfo->ret.storage = ArgInFloatReg;
413 case MONO_TYPE_GENERICINST:
414 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
415 cinfo->ret.storage = ArgInIReg;
416 cinfo->ret.reg = IA64_R8;
420 case MONO_TYPE_VALUETYPE:
421 case MONO_TYPE_TYPEDBYREF: {
422 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
424 if (sig->ret->byref) {
425 /* This seems to happen with ldfld wrappers */
426 cinfo->ret.storage = ArgInIReg;
428 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
429 if (cinfo->ret.storage == ArgOnStack)
430 /* The caller passes the address where the value is stored */
431 add_general (&gr, &stack_size, &cinfo->ret);
432 if (cinfo->ret.storage == ArgInIReg)
433 cinfo->ret.storage = ArgValuetypeAddrInIReg;
438 cinfo->ret.storage = ArgNone;
441 g_error ("Can't handle as return value 0x%x", sig->ret->type);
447 add_general (&gr, &stack_size, cinfo->args + 0);
449 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
451 fr = FLOAT_PARAM_REGS;
453 /* Emit the signature cookie just before the implicit arguments */
454 add_general (&gr, &stack_size, &cinfo->sig_cookie);
457 for (i = 0; i < sig->param_count; ++i) {
458 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
461 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
462 /* We allways pass the sig cookie on the stack for simplicity */
464 * Prevent implicit arguments + the sig cookie from being passed
468 fr = FLOAT_PARAM_REGS;
470 /* Emit the signature cookie just before the implicit arguments */
471 add_general (&gr, &stack_size, &cinfo->sig_cookie);
474 if (sig->params [i]->byref) {
475 add_general (&gr, &stack_size, ainfo);
478 ptype = mono_type_get_underlying_type (sig->params [i]);
479 ptype = mini_get_basic_type_from_generic (gsctx, ptype);
480 switch (ptype->type) {
481 case MONO_TYPE_BOOLEAN:
484 add_general (&gr, &stack_size, ainfo);
489 add_general (&gr, &stack_size, ainfo);
493 add_general (&gr, &stack_size, ainfo);
498 case MONO_TYPE_FNPTR:
499 case MONO_TYPE_CLASS:
500 case MONO_TYPE_OBJECT:
501 case MONO_TYPE_STRING:
502 case MONO_TYPE_SZARRAY:
503 case MONO_TYPE_ARRAY:
504 add_general (&gr, &stack_size, ainfo);
506 case MONO_TYPE_GENERICINST:
507 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
508 add_general (&gr, &stack_size, ainfo);
512 case MONO_TYPE_VALUETYPE:
513 case MONO_TYPE_TYPEDBYREF:
515 /* We allways pass valuetypes on the stack */
516 add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
520 add_general (&gr, &stack_size, ainfo);
523 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
526 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
529 g_assert_not_reached ();
533 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
535 fr = FLOAT_PARAM_REGS;
537 /* Emit the signature cookie just before the implicit arguments */
538 add_general (&gr, &stack_size, &cinfo->sig_cookie);
541 cinfo->stack_usage = stack_size;
542 cinfo->reg_usage = gr;
543 cinfo->freg_usage = fr;
548 * mono_arch_get_argument_info:
549 * @csig: a method signature
550 * @param_count: the number of parameters to consider
551 * @arg_info: an array to store the result infos
553 * Gathers information on parameters such as size, alignment and
554 * padding. arg_info should be large enought to hold param_count + 1 entries.
556 * Returns the size of the argument area on the stack.
559 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
562 CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
563 guint32 args_size = cinfo->stack_usage;
565 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
567 arg_info [0].offset = 0;
570 for (k = 0; k < param_count; k++) {
571 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
573 arg_info [k + 1].size = 0;
582 * Initialize the cpu to execute managed code.
585 mono_arch_cpu_init (void)
590 * Initialize architecture specific code.
593 mono_arch_init (void)
598 * Cleanup architecture specific code.
601 mono_arch_cleanup (void)
606 * This function returns the optimizations supported on this cpu.
609 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
617 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
621 MonoMethodSignature *sig;
622 MonoMethodHeader *header;
625 header = mono_method_get_header (cfg->method);
627 sig = mono_method_signature (cfg->method);
629 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
631 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
632 MonoInst *ins = cfg->args [i];
634 ArgInfo *ainfo = &cinfo->args [i];
636 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
639 if (ainfo->storage == ArgInIReg) {
640 /* The input registers are non-volatile */
641 ins->opcode = OP_REGVAR;
642 ins->dreg = 32 + ainfo->reg;
646 for (i = 0; i < cfg->num_varinfo; i++) {
647 MonoInst *ins = cfg->varinfo [i];
648 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
651 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
654 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
655 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
658 if (mono_is_regsize_var (ins->inst_vtype)) {
659 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
660 g_assert (i == vmv->idx);
661 vars = g_list_prepend (vars, vmv);
665 vars = mono_varlist_sort (cfg, vars, 0);
671 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
674 guint32 reserved_regs;
675 MonoMethodHeader *header;
677 if (cfg->arch.reg_local0 > 0)
681 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
683 header = mono_method_get_header (cfg->method);
685 /* Some registers are reserved for use by the prolog/epilog */
686 reserved_regs = header->num_clauses ? 4 : 3;
688 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
689 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
690 /* One registers is needed by instrument_epilog to save the return value */
692 if (cinfo->reg_usage < 2)
693 /* Number of arguments passed to function call in instrument_prolog */
694 cinfo->reg_usage = 2;
697 cfg->arch.reg_in0 = 32;
698 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
699 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
701 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
702 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
703 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
706 * Frames without handlers save sp to fp, frames with handlers save it into
707 * a dedicated register.
709 if (header->num_clauses)
710 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
712 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
714 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
715 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
716 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
720 * Need to allocate at least 2 out register for use by OP_THROW / the system
721 * exception throwing code.
723 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
727 mono_arch_get_global_int_regs (MonoCompile *cfg)
732 mono_ia64_alloc_stacked_registers (cfg);
734 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
737 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
744 * mono_arch_regalloc_cost:
746 * Return the cost, in number of memory references, of the action of
747 * allocating the variable VMV into a register during global register
751 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
753 /* FIXME: Increase costs linearly to avoid using all local registers */
759 mono_arch_allocate_vars (MonoCompile *cfg)
761 MonoMethodSignature *sig;
762 MonoMethodHeader *header;
765 guint32 locals_stack_size, locals_stack_align;
769 header = mono_method_get_header (cfg->method);
771 sig = mono_method_signature (cfg->method);
773 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
776 * Determine whenever the frame pointer can be eliminated.
777 * FIXME: Remove some of the restrictions.
779 cfg->arch.omit_fp = TRUE;
781 if (!debug_omit_fp ())
782 cfg->arch.omit_fp = FALSE;
784 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
785 cfg->arch.omit_fp = FALSE;
786 if (header->num_clauses)
787 cfg->arch.omit_fp = FALSE;
789 cfg->arch.omit_fp = FALSE;
790 if ((sig->ret->type != MONO_TYPE_VOID) && (cinfo->ret.storage == ArgAggregate))
791 cfg->arch.omit_fp = FALSE;
792 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
793 cfg->arch.omit_fp = FALSE;
794 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
795 ArgInfo *ainfo = &cinfo->args [i];
797 if (ainfo->storage == ArgOnStack) {
799 * The stack offset can only be determined when the frame
802 cfg->arch.omit_fp = FALSE;
806 mono_ia64_alloc_stacked_registers (cfg);
809 * We use the ABI calling conventions for managed code as well.
810 * Exception: valuetypes are never passed or returned in registers.
813 if (cfg->arch.omit_fp) {
814 cfg->flags |= MONO_CFG_HAS_SPILLUP;
815 cfg->frame_reg = IA64_SP;
816 offset = ARGS_OFFSET;
819 /* Locals are allocated backwards from %fp */
820 cfg->frame_reg = cfg->arch.reg_fp;
824 if (cfg->method->save_lmf) {
828 if (sig->ret->type != MONO_TYPE_VOID) {
829 switch (cinfo->ret.storage) {
831 cfg->ret->opcode = OP_REGVAR;
832 cfg->ret->inst_c0 = cinfo->ret.reg;
835 cfg->ret->opcode = OP_REGVAR;
836 cfg->ret->inst_c0 = cinfo->ret.reg;
838 case ArgValuetypeAddrInIReg:
839 cfg->vret_addr->opcode = OP_REGVAR;
840 cfg->vret_addr->dreg = cfg->arch.reg_in0 + cinfo->ret.reg;
843 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
844 if (cfg->arch.omit_fp)
845 g_assert_not_reached ();
846 offset = ALIGN_TO (offset, 8);
847 offset += cinfo->ret.nslots * 8;
848 cfg->ret->opcode = OP_REGOFFSET;
849 cfg->ret->inst_basereg = cfg->frame_reg;
850 cfg->ret->inst_offset = - offset;
853 g_assert_not_reached ();
855 cfg->ret->dreg = cfg->ret->inst_c0;
858 /* Allocate locals */
859 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
860 if (locals_stack_align) {
861 offset = ALIGN_TO (offset, locals_stack_align);
863 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
864 if (offsets [i] != -1) {
865 MonoInst *inst = cfg->varinfo [i];
866 inst->opcode = OP_REGOFFSET;
867 inst->inst_basereg = cfg->frame_reg;
868 if (cfg->arch.omit_fp)
869 inst->inst_offset = (offset + offsets [i]);
871 inst->inst_offset = - (offset + offsets [i]);
872 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
875 offset += locals_stack_size;
877 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
878 if (cfg->arch.omit_fp)
879 g_assert_not_reached ();
880 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
881 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
884 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
885 inst = cfg->args [i];
886 if (inst->opcode != OP_REGVAR) {
887 ArgInfo *ainfo = &cinfo->args [i];
888 gboolean inreg = TRUE;
891 if (sig->hasthis && (i == 0))
892 arg_type = &mono_defaults.object_class->byval_arg;
894 arg_type = sig->params [i - sig->hasthis];
896 /* FIXME: VOLATILE is only set if the liveness pass runs */
897 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
900 inst->opcode = OP_REGOFFSET;
902 switch (ainfo->storage) {
904 inst->opcode = OP_REGVAR;
905 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
908 case ArgInFloatRegR4:
910 * Since float regs are volatile, we save the arguments to
911 * the stack in the prolog.
916 if (cfg->arch.omit_fp)
917 g_assert_not_reached ();
918 inst->opcode = OP_REGOFFSET;
919 inst->inst_basereg = cfg->frame_reg;
920 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
929 if (!inreg && (ainfo->storage != ArgOnStack)) {
932 inst->opcode = OP_REGOFFSET;
933 inst->inst_basereg = cfg->frame_reg;
934 /* These arguments are saved to the stack in the prolog */
935 switch (ainfo->storage) {
937 if (ainfo->atype == AggregateSingleHFA)
938 size = ainfo->nslots * 4;
940 size = ainfo->nslots * 8;
943 size = sizeof (gpointer);
947 offset = ALIGN_TO (offset, sizeof (gpointer));
949 if (cfg->arch.omit_fp) {
950 inst->inst_offset = offset;
954 inst->inst_offset = - offset;
961 * FIXME: This doesn't work because some variables are allocated during local
965 if (cfg->arch.omit_fp && offset == 16)
969 cfg->stack_offset = offset;
973 mono_arch_create_vars (MonoCompile *cfg)
975 MonoMethodSignature *sig;
978 sig = mono_method_signature (cfg->method);
980 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
982 if (cinfo->ret.storage == ArgAggregate)
983 cfg->ret_var_is_local = TRUE;
984 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
985 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
986 if (G_UNLIKELY (cfg->verbose_level > 1)) {
987 printf ("vret_addr = ");
988 mono_print_ins (cfg->vret_addr);
994 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
998 arg->opcode = OP_OUTARG_REG;
999 arg->inst_left = tree;
1000 arg->inst_right = (MonoInst*)call;
1001 arg->backend.reg3 = reg;
1002 call->used_iregs |= 1 << reg;
1005 arg->opcode = OP_OUTARG_FREG;
1006 arg->inst_left = tree;
1007 arg->inst_right = (MonoInst*)call;
1008 arg->backend.reg3 = reg;
1009 call->used_fregs |= 1 << reg;
1011 case ArgInFloatRegR4:
1012 arg->opcode = OP_OUTARG_FREG_R4;
1013 arg->inst_left = tree;
1014 arg->inst_right = (MonoInst*)call;
1015 arg->backend.reg3 = reg;
1016 call->used_fregs |= 1 << reg;
1019 g_assert_not_reached ();
1024 add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
1028 MONO_INST_NEW (cfg, arg, OP_NOP);
1029 arg->sreg1 = tree->dreg;
1033 arg->opcode = OP_MOVE;
1034 arg->dreg = mono_alloc_ireg (cfg);
1036 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, FALSE);
1039 arg->opcode = OP_FMOVE;
1040 arg->dreg = mono_alloc_freg (cfg);
1042 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1044 case ArgInFloatRegR4:
1045 arg->opcode = OP_FCONV_TO_R4;
1046 arg->dreg = mono_alloc_freg (cfg);
1048 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1051 g_assert_not_reached ();
1054 MONO_ADD_INS (cfg->cbb, arg);
1058 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1061 MonoMethodSignature *tmp_sig;
1064 /* FIXME: Add support for signature tokens to AOT */
1065 cfg->disable_aot = TRUE;
1067 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1070 * mono_ArgIterator_Setup assumes the signature cookie is
1071 * passed first and all the arguments which were before it are
1072 * passed on the stack after the signature. So compensate by
1073 * passing a different signature.
1075 tmp_sig = mono_metadata_signature_dup (call->signature);
1076 tmp_sig->param_count -= call->signature->sentinelpos;
1077 tmp_sig->sentinelpos = 0;
1078 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1080 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1081 sig_arg->inst_p0 = tmp_sig;
1083 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1084 arg->inst_left = sig_arg;
1085 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1086 arg->type = STACK_PTR;
1088 /* prepend, so they get reversed */
1089 arg->next = call->out_args;
1090 call->out_args = arg;
1094 * take the arguments and generate the arch-specific
1095 * instructions to properly call the function in call.
1096 * This includes pushing, moving arguments to the right register
1100 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1103 MonoMethodSignature *sig;
1104 int i, n, stack_size;
1110 mono_ia64_alloc_stacked_registers (cfg);
1112 sig = call->signature;
1113 n = sig->param_count + sig->hasthis;
1115 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1117 if (cinfo->ret.storage == ArgAggregate) {
1118 /* The code in emit_this_vret_arg needs a local */
1119 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1120 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1123 for (i = 0; i < n; ++i) {
1124 ainfo = cinfo->args + i;
1126 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1127 /* Emit the signature cookie just before the implicit arguments */
1128 emit_sig_cookie (cfg, call, cinfo);
1131 if (is_virtual && i == 0) {
1132 /* the argument will be attached to the call instruction */
1133 in = call->args [i];
1137 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1138 in = call->args [i];
1139 arg->cil_code = in->cil_code;
1140 arg->inst_left = in;
1141 arg->type = in->type;
1142 /* prepend, so they get reversed */
1143 arg->next = call->out_args;
1144 call->out_args = arg;
1146 if (sig->hasthis && (i == 0))
1147 arg_type = &mono_defaults.object_class->byval_arg;
1149 arg_type = sig->params [i - sig->hasthis];
1151 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1152 MonoInst *stack_addr;
1156 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1157 size = sizeof (MonoTypedRef);
1158 align = sizeof (gpointer);
1162 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1165 * Other backends use mini_type_stack_size (), but that
1166 * aligns the size to 8, which is larger than the size of
1167 * the source, leading to reads of invalid memory if the
1168 * source is at the end of address space.
1170 size = mono_class_value_size (in->klass, &align);
1173 if (ainfo->storage == ArgAggregate) {
1174 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1177 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1180 * Part of the structure is passed in registers.
1182 for (j = 0; j < ainfo->nregs; ++j) {
1183 int offset, load_op, dest_reg, arg_storage;
1185 slot = ainfo->reg + j;
1187 if (ainfo->atype == AggregateSingleHFA) {
1188 load_op = CEE_LDIND_R4;
1190 dest_reg = ainfo->reg + j;
1191 arg_storage = ArgInFloatReg;
1192 } else if (ainfo->atype == AggregateDoubleHFA) {
1193 load_op = CEE_LDIND_R8;
1195 dest_reg = ainfo->reg + j;
1196 arg_storage = ArgInFloatReg;
1198 load_op = CEE_LDIND_I;
1200 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1201 arg_storage = ArgInIReg;
1204 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1205 load->ssa_op = MONO_SSA_LOAD;
1206 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1208 NEW_ICONST (cfg, offset_ins, offset);
1209 MONO_INST_NEW (cfg, load2, CEE_ADD);
1210 load2->inst_left = load;
1211 load2->inst_right = offset_ins;
1213 MONO_INST_NEW (cfg, load, load_op);
1214 load->inst_left = load2;
1219 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1220 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1221 if (set_reg != call->out_args) {
1222 set_reg->next = call->out_args;
1223 call->out_args = set_reg;
1228 * Part of the structure is passed on the stack.
1230 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1233 slot = ainfo->reg + j;
1235 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1236 load->ssa_op = MONO_SSA_LOAD;
1237 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1239 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1240 MONO_INST_NEW (cfg, load2, CEE_ADD);
1241 load2->inst_left = load;
1242 load2->inst_right = offset_ins;
1244 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1245 load->inst_left = load2;
1250 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1251 outarg->inst_left = load;
1252 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1254 if (outarg != call->out_args) {
1255 outarg->next = call->out_args;
1256 call->out_args = outarg;
1260 /* Trees can't be shared so make a copy */
1261 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1262 arg->cil_code = in->cil_code;
1263 arg->ssa_op = MONO_SSA_STORE;
1264 arg->inst_left = vtaddr;
1265 arg->inst_right = in;
1266 arg->type = in->type;
1268 /* prepend, so they get reversed */
1269 arg->next = call->out_args;
1270 call->out_args = arg;
1273 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1274 stack_addr->inst_basereg = IA64_SP;
1275 stack_addr->inst_offset = 16 + ainfo->offset;
1276 stack_addr->inst_imm = size;
1278 arg->opcode = OP_OUTARG_VT;
1279 arg->inst_right = stack_addr;
1283 switch (ainfo->storage) {
1285 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1288 case ArgInFloatRegR4:
1289 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1292 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1293 arg->opcode = OP_OUTARG_R4;
1296 arg->opcode = OP_OUTARG;
1297 arg->inst_imm = 16 + ainfo->offset;
1300 g_assert_not_reached ();
1306 /* Handle the case where there are no implicit arguments */
1307 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1308 emit_sig_cookie (cfg, call, cinfo);
1311 call->stack_usage = cinfo->stack_usage;
1312 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1313 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1314 cfg->flags |= MONO_CFG_HAS_CALLS;
1320 emit_sig_cookie2 (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1322 MonoMethodSignature *tmp_sig;
1324 /* Emit the signature cookie just before the implicit arguments */
1326 /* FIXME: Add support for signature tokens to AOT */
1327 cfg->disable_aot = TRUE;
1329 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1332 * mono_ArgIterator_Setup assumes the signature cookie is
1333 * passed first and all the arguments which were before it are
1334 * passed on the stack after the signature. So compensate by
1335 * passing a different signature.
1337 tmp_sig = mono_metadata_signature_dup (call->signature);
1338 tmp_sig->param_count -= call->signature->sentinelpos;
1339 tmp_sig->sentinelpos = 0;
1340 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1342 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1343 sig_arg->dreg = mono_alloc_ireg (cfg);
1344 sig_arg->inst_p0 = tmp_sig;
1345 MONO_ADD_INS (cfg->cbb, sig_arg);
1347 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + cinfo->sig_cookie.offset, sig_arg->dreg);
1351 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1354 MonoMethodSignature *sig;
1355 int i, n, stack_size;
1361 mono_ia64_alloc_stacked_registers (cfg);
1363 sig = call->signature;
1364 n = sig->param_count + sig->hasthis;
1366 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1368 if (cinfo->ret.storage == ArgAggregate) {
1373 * The valuetype is in registers after the call, need to be copied
1374 * to the stack. Save the address to a local here, so the call
1375 * instruction can access it.
1377 local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1378 local->flags |= MONO_INST_VOLATILE;
1379 cfg->arch.ret_var_addr_local = local;
1381 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1382 vtarg->sreg1 = call->vret_var->dreg;
1383 vtarg->dreg = local->dreg;
1384 MONO_ADD_INS (cfg->cbb, vtarg);
1387 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
1388 add_outarg_reg2 (cfg, call, ArgInIReg, cfg->arch.reg_out0 + cinfo->ret.reg, call->vret_var);
1391 for (i = 0; i < n; ++i) {
1394 ainfo = cinfo->args + i;
1396 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1397 /* Emit the signature cookie just before the implicit arguments */
1398 emit_sig_cookie2 (cfg, call, cinfo);
1401 in = call->args [i];
1403 if (sig->hasthis && (i == 0))
1404 arg_type = &mono_defaults.object_class->byval_arg;
1406 arg_type = sig->params [i - sig->hasthis];
1408 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1412 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1413 size = sizeof (MonoTypedRef);
1414 align = sizeof (gpointer);
1416 else if (sig->pinvoke)
1417 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1420 * Other backends use mono_type_stack_size (), but that
1421 * aligns the size to 8, which is larger than the size of
1422 * the source, leading to reads of invalid memory if the
1423 * source is at the end of address space.
1425 size = mono_class_value_size (in->klass, &align);
1431 MONO_INST_NEW (cfg, arg, OP_OUTARG_VT);
1432 arg->sreg1 = in->dreg;
1433 arg->klass = in->klass;
1434 arg->backend.size = size;
1435 arg->inst_p0 = call;
1436 arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1437 memcpy (arg->inst_p1, ainfo, sizeof (ArgInfo));
1439 MONO_ADD_INS (cfg->cbb, arg);
1443 switch (ainfo->storage) {
1445 add_outarg_reg2 (cfg, call, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1448 case ArgInFloatRegR4:
1449 add_outarg_reg2 (cfg, call, ainfo->storage, ainfo->reg, in);
1452 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref)
1453 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1454 else if (arg_type->type == MONO_TYPE_R8 && !arg_type->byref)
1455 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1457 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1460 g_assert_not_reached ();
1465 /* Handle the case where there are no implicit arguments */
1466 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1467 emit_sig_cookie2 (cfg, call, cinfo);
1470 call->stack_usage = cinfo->stack_usage;
1471 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1475 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1477 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1478 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1479 int size = ins->backend.size;
1481 if (ainfo->storage == ArgAggregate) {
1482 MonoInst *load, *store;
1486 * Part of the structure is passed in registers.
1488 for (i = 0; i < ainfo->nregs; ++i) {
1489 slot = ainfo->reg + i;
1491 if (ainfo->atype == AggregateSingleHFA) {
1492 MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
1493 load->inst_basereg = src->dreg;
1494 load->inst_offset = i * 4;
1495 load->dreg = mono_alloc_freg (cfg);
1497 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1498 } else if (ainfo->atype == AggregateDoubleHFA) {
1499 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1500 load->inst_basereg = src->dreg;
1501 load->inst_offset = i * 8;
1502 load->dreg = mono_alloc_freg (cfg);
1504 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1506 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1507 load->inst_basereg = src->dreg;
1508 load->inst_offset = i * 8;
1509 load->dreg = mono_alloc_ireg (cfg);
1511 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, cfg->arch.reg_out0 + ainfo->reg + i, FALSE);
1513 MONO_ADD_INS (cfg->cbb, load);
1517 * Part of the structure is passed on the stack.
1519 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1520 slot = ainfo->reg + i;
1522 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1523 load->inst_basereg = src->dreg;
1524 load->inst_offset = i * sizeof (gpointer);
1525 load->dreg = mono_alloc_preg (cfg);
1526 MONO_ADD_INS (cfg->cbb, load);
1528 MONO_INST_NEW (cfg, store, OP_STOREI8_MEMBASE_REG);
1529 store->sreg1 = load->dreg;
1530 store->inst_destbasereg = IA64_SP;
1531 store->inst_offset = 16 + ainfo->offset + (slot - 8) * 8;
1532 MONO_ADD_INS (cfg->cbb, store);
1535 mini_emit_memcpy2 (cfg, IA64_SP, 16 + ainfo->offset, src->dreg, 0, size, 4);
1540 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1542 CallInfo *cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
1544 switch (cinfo->ret.storage) {
1546 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1549 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1552 g_assert_not_reached ();
1557 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1562 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1564 MonoInst *ins, *n, *last_ins = NULL;
1567 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1568 switch (ins->opcode) {
1576 if (ins->dreg == ins->sreg1) {
1577 MONO_DELETE_INS (bb, ins);
1583 * OP_MOVE sreg, dreg
1584 * OP_MOVE dreg, sreg
1586 if (last_ins && last_ins->opcode == OP_MOVE &&
1587 ins->sreg1 == last_ins->dreg &&
1588 ins->dreg == last_ins->sreg1) {
1589 MONO_DELETE_INS (bb, ins);
1595 /* remove unnecessary multiplication with 1 */
1596 if (ins->inst_imm == 1) {
1597 if (ins->dreg != ins->sreg1) {
1598 ins->opcode = OP_MOVE;
1600 MONO_DELETE_INS (bb, ins);
1610 bb->last_ins = last_ins;
1613 int cond_to_ia64_cmp [][3] = {
1614 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1615 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1616 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1617 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1618 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1619 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1620 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1621 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1622 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1623 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1627 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1629 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1632 int cond_to_ia64_cmp_imm [][3] = {
1633 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1634 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1635 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1636 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1637 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1638 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1639 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1640 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1641 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1642 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1646 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1648 /* The condition needs to be reversed */
1649 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1652 #define NEW_INS(cfg,dest,op) do { \
1653 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1654 (dest)->opcode = (op); \
1655 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1656 last_ins = (dest); \
1660 * mono_arch_lowering_pass:
1662 * Converts complex opcodes into simpler ones so that each IR instruction
1663 * corresponds to one machine instruction.
1666 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1668 MonoInst *ins, *n, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1671 if (bb->max_vreg > cfg->rs->next_vreg)
1672 cfg->rs->next_vreg = bb->max_vreg;
1674 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1675 switch (ins->opcode) {
1676 case OP_STOREI1_MEMBASE_IMM:
1677 case OP_STOREI2_MEMBASE_IMM:
1678 case OP_STOREI4_MEMBASE_IMM:
1679 case OP_STOREI8_MEMBASE_IMM:
1680 case OP_STORE_MEMBASE_IMM:
1681 /* There are no store_membase instructions on ia64 */
1682 if (ins->inst_offset == 0) {
1684 } else if (ia64_is_imm14 (ins->inst_offset)) {
1685 NEW_INS (cfg, temp2, OP_ADD_IMM);
1686 temp2->sreg1 = ins->inst_destbasereg;
1687 temp2->inst_imm = ins->inst_offset;
1688 temp2->dreg = mono_regstate_next_int (cfg->rs);
1691 NEW_INS (cfg, temp, OP_I8CONST);
1692 temp->inst_c0 = ins->inst_offset;
1693 temp->dreg = mono_regstate_next_int (cfg->rs);
1695 NEW_INS (cfg, temp2, OP_LADD);
1696 temp2->sreg1 = ins->inst_destbasereg;
1697 temp2->sreg2 = temp->dreg;
1698 temp2->dreg = mono_regstate_next_int (cfg->rs);
1701 switch (ins->opcode) {
1702 case OP_STOREI1_MEMBASE_IMM:
1703 ins->opcode = OP_STOREI1_MEMBASE_REG;
1705 case OP_STOREI2_MEMBASE_IMM:
1706 ins->opcode = OP_STOREI2_MEMBASE_REG;
1708 case OP_STOREI4_MEMBASE_IMM:
1709 ins->opcode = OP_STOREI4_MEMBASE_REG;
1711 case OP_STOREI8_MEMBASE_IMM:
1712 case OP_STORE_MEMBASE_IMM:
1713 ins->opcode = OP_STOREI8_MEMBASE_REG;
1716 g_assert_not_reached ();
1719 if (ins->inst_imm == 0)
1720 ins->sreg1 = IA64_R0;
1722 NEW_INS (cfg, temp3, OP_I8CONST);
1723 temp3->inst_c0 = ins->inst_imm;
1724 temp3->dreg = mono_regstate_next_int (cfg->rs);
1725 ins->sreg1 = temp3->dreg;
1728 ins->inst_offset = 0;
1730 ins->inst_destbasereg = temp2->dreg;
1732 case OP_STOREI1_MEMBASE_REG:
1733 case OP_STOREI2_MEMBASE_REG:
1734 case OP_STOREI4_MEMBASE_REG:
1735 case OP_STOREI8_MEMBASE_REG:
1736 case OP_STORER4_MEMBASE_REG:
1737 case OP_STORER8_MEMBASE_REG:
1738 case OP_STORE_MEMBASE_REG:
1739 /* There are no store_membase instructions on ia64 */
1740 if (ins->inst_offset == 0) {
1743 else if (ia64_is_imm14 (ins->inst_offset)) {
1744 NEW_INS (cfg, temp2, OP_ADD_IMM);
1745 temp2->sreg1 = ins->inst_destbasereg;
1746 temp2->inst_imm = ins->inst_offset;
1747 temp2->dreg = mono_regstate_next_int (cfg->rs);
1750 NEW_INS (cfg, temp, OP_I8CONST);
1751 temp->inst_c0 = ins->inst_offset;
1752 temp->dreg = mono_regstate_next_int (cfg->rs);
1753 NEW_INS (cfg, temp2, OP_LADD);
1754 temp2->sreg1 = ins->inst_destbasereg;
1755 temp2->sreg2 = temp->dreg;
1756 temp2->dreg = mono_regstate_next_int (cfg->rs);
1759 ins->inst_offset = 0;
1760 ins->inst_destbasereg = temp2->dreg;
1762 case OP_LOADI1_MEMBASE:
1763 case OP_LOADU1_MEMBASE:
1764 case OP_LOADI2_MEMBASE:
1765 case OP_LOADU2_MEMBASE:
1766 case OP_LOADI4_MEMBASE:
1767 case OP_LOADU4_MEMBASE:
1768 case OP_LOADI8_MEMBASE:
1769 case OP_LOAD_MEMBASE:
1770 case OP_LOADR4_MEMBASE:
1771 case OP_LOADR8_MEMBASE:
1772 case OP_ATOMIC_EXCHANGE_I4:
1773 case OP_ATOMIC_EXCHANGE_I8:
1774 case OP_ATOMIC_ADD_NEW_I4:
1775 case OP_ATOMIC_ADD_NEW_I8:
1776 case OP_ATOMIC_ADD_IMM_NEW_I4:
1777 case OP_ATOMIC_ADD_IMM_NEW_I8:
1778 /* There are no membase instructions on ia64 */
1779 if (ins->inst_offset == 0) {
1782 else if (ia64_is_imm14 (ins->inst_offset)) {
1783 NEW_INS (cfg, temp2, OP_ADD_IMM);
1784 temp2->sreg1 = ins->inst_basereg;
1785 temp2->inst_imm = ins->inst_offset;
1786 temp2->dreg = mono_regstate_next_int (cfg->rs);
1789 NEW_INS (cfg, temp, OP_I8CONST);
1790 temp->inst_c0 = ins->inst_offset;
1791 temp->dreg = mono_regstate_next_int (cfg->rs);
1792 NEW_INS (cfg, temp2, OP_LADD);
1793 temp2->sreg1 = ins->inst_basereg;
1794 temp2->sreg2 = temp->dreg;
1795 temp2->dreg = mono_regstate_next_int (cfg->rs);
1798 ins->inst_offset = 0;
1799 ins->inst_basereg = temp2->dreg;
1819 case OP_ISHR_UN_IMM:
1820 case OP_LSHR_UN_IMM: {
1821 gboolean is_imm = FALSE;
1822 gboolean switched = FALSE;
1824 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1825 ins->opcode = OP_ZEXT_I1;
1829 switch (ins->opcode) {
1833 is_imm = ia64_is_imm14 (ins->inst_imm);
1838 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1840 /* A = B - IMM -> A = B + (-IMM) */
1841 ins->inst_imm = - ins->inst_imm;
1842 ins->opcode = OP_IADD_IMM;
1853 is_imm = ia64_is_imm8 (ins->inst_imm);
1862 case OP_ISHR_UN_IMM:
1863 case OP_LSHR_UN_IMM:
1864 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1872 ins->sreg2 = ins->sreg1;
1876 ins->opcode = mono_op_imm_to_op (ins->opcode);
1878 if (ins->inst_imm == 0)
1879 ins->sreg2 = IA64_R0;
1881 NEW_INS (cfg, temp, OP_I8CONST);
1882 temp->inst_c0 = ins->inst_imm;
1883 temp->dreg = mono_regstate_next_int (cfg->rs);
1884 ins->sreg2 = temp->dreg;
1888 case OP_COMPARE_IMM:
1889 case OP_ICOMPARE_IMM:
1890 case OP_LCOMPARE_IMM: {
1891 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1897 /* Branch opts can eliminate the branch */
1898 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1899 ins->opcode = OP_NOP;
1904 * The compare_imm instructions have switched up arguments, and
1905 * some of them take an imm between -127 and 128.
1908 cond = mono_opcode_to_cond (next->opcode);
1909 if ((cond == CMP_LT) || (cond == CMP_GE))
1910 imm = ia64_is_imm8 (ins->inst_imm - 1);
1911 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1912 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1914 imm = ia64_is_imm8 (ins->inst_imm);
1917 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1918 ins->sreg2 = ins->sreg1;
1921 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1923 if (ins->inst_imm == 0)
1924 ins->sreg2 = IA64_R0;
1926 NEW_INS (cfg, temp, OP_I8CONST);
1927 temp->inst_c0 = ins->inst_imm;
1928 temp->dreg = mono_regstate_next_int (cfg->rs);
1929 ins->sreg2 = temp->dreg;
1933 if (MONO_IS_COND_BRANCH_OP (next)) {
1934 next->opcode = OP_IA64_BR_COND;
1935 if (! (next->flags & MONO_INST_BRLABEL))
1936 next->inst_target_bb = next->inst_true_bb;
1937 } else if (MONO_IS_COND_EXC (next)) {
1938 next->opcode = OP_IA64_COND_EXC;
1939 } else if (MONO_IS_SETCC (next)) {
1940 next->opcode = OP_IA64_CSET;
1942 printf ("%s\n", mono_inst_name (next->opcode));
1952 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1956 /* Branch opts can eliminate the branch */
1957 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1958 ins->opcode = OP_NOP;
1962 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1964 if (MONO_IS_COND_BRANCH_OP (next)) {
1965 next->opcode = OP_IA64_BR_COND;
1966 if (! (next->flags & MONO_INST_BRLABEL))
1967 next->inst_target_bb = next->inst_true_bb;
1968 } else if (MONO_IS_COND_EXC (next)) {
1969 next->opcode = OP_IA64_COND_EXC;
1970 } else if (MONO_IS_SETCC (next)) {
1971 next->opcode = OP_IA64_CSET;
1973 printf ("%s\n", mono_inst_name (next->opcode));
1984 /* The front end removes the fcompare, so introduce it again */
1985 NEW_INS (cfg, temp, opcode_to_ia64_cmp (ins->opcode, OP_FCOMPARE));
1986 temp->sreg1 = ins->sreg1;
1987 temp->sreg2 = ins->sreg2;
1989 ins->opcode = OP_IA64_CSET;
1995 gboolean found = FALSE;
1996 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1998 /* First the easy cases */
1999 if (ins->inst_imm == 1) {
2000 ins->opcode = OP_MOVE;
2003 for (i = 1; i < 64; ++i)
2004 if (ins->inst_imm == (((gint64)1) << i)) {
2005 ins->opcode = shl_op;
2011 /* This could be optimized */
2014 for (i = 0; i < 64; ++i) {
2015 if (ins->inst_imm & (((gint64)1) << i)) {
2016 NEW_INS (cfg, temp, shl_op);
2017 temp->dreg = mono_regstate_next_int (cfg->rs);
2018 temp->sreg1 = ins->sreg1;
2022 sum_reg = temp->dreg;
2024 NEW_INS (cfg, temp2, OP_LADD);
2025 temp2->dreg = mono_regstate_next_int (cfg->rs);
2026 temp2->sreg1 = sum_reg;
2027 temp2->sreg2 = temp->dreg;
2028 sum_reg = temp2->dreg;
2032 ins->opcode = OP_MOVE;
2033 ins->sreg1 = sum_reg;
2037 case OP_LCONV_TO_OVF_U4:
2038 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
2039 temp->sreg1 = ins->sreg1;
2040 temp->sreg2 = IA64_R0;
2042 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
2043 temp->inst_p1 = (char*)"OverflowException";
2045 ins->opcode = OP_MOVE;
2047 case OP_LCONV_TO_OVF_I4_UN:
2048 NEW_INS (cfg, temp, OP_ICONST);
2049 temp->inst_c0 = 0x7fffffff;
2050 temp->dreg = mono_regstate_next_int (cfg->rs);
2052 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
2053 temp2->sreg1 = ins->sreg1;
2054 temp2->sreg2 = temp->dreg;
2056 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
2057 temp->inst_p1 = (char*)"OverflowException";
2059 ins->opcode = OP_MOVE;
2061 case OP_FCONV_TO_I4:
2062 case OP_FCONV_TO_I2:
2063 case OP_FCONV_TO_U2:
2064 case OP_FCONV_TO_I1:
2065 case OP_FCONV_TO_U1:
2066 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
2067 temp->sreg1 = ins->sreg1;
2068 temp->dreg = ins->dreg;
2070 switch (ins->opcode) {
2071 case OP_FCONV_TO_I4:
2072 ins->opcode = OP_SEXT_I4;
2074 case OP_FCONV_TO_I2:
2075 ins->opcode = OP_SEXT_I2;
2077 case OP_FCONV_TO_U2:
2078 ins->opcode = OP_ZEXT_I4;
2080 case OP_FCONV_TO_I1:
2081 ins->opcode = OP_SEXT_I1;
2083 case OP_FCONV_TO_U1:
2084 ins->opcode = OP_ZEXT_I1;
2087 g_assert_not_reached ();
2089 ins->sreg1 = ins->dreg;
2097 bb->last_ins = last_ins;
2099 bb->max_vreg = cfg->rs->next_vreg;
2103 * emit_load_volatile_arguments:
2105 * Load volatile arguments from the stack to the original input registers.
2106 * Required before a tail call.
2108 static Ia64CodegenState
2109 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
2111 MonoMethod *method = cfg->method;
2112 MonoMethodSignature *sig;
2117 /* FIXME: Generate intermediate code instead */
2119 sig = mono_method_signature (method);
2121 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
2123 /* This is the opposite of the code in emit_prolog */
2124 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2125 ArgInfo *ainfo = cinfo->args + i;
2126 gint32 stack_offset;
2129 ins = cfg->args [i];
2131 if (sig->hasthis && (i == 0))
2132 arg_type = &mono_defaults.object_class->byval_arg;
2134 arg_type = sig->params [i - sig->hasthis];
2136 arg_type = mono_type_get_underlying_type (arg_type);
2138 stack_offset = ainfo->offset + ARGS_OFFSET;
2140 /* Save volatile arguments to the stack */
2141 if (ins->opcode != OP_REGVAR) {
2142 switch (ainfo->storage) {
2145 /* FIXME: big offsets */
2146 g_assert (ins->opcode == OP_REGOFFSET);
2147 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2148 if (arg_type->byref)
2149 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2151 switch (arg_type->type) {
2153 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
2156 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
2159 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2171 if (ins->opcode == OP_REGVAR) {
2172 /* Argument allocated to (non-volatile) register */
2173 switch (ainfo->storage) {
2175 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
2176 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
2179 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
2180 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2191 static Ia64CodegenState
2192 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2197 /* Move return value to the target register */
2198 switch (ins->opcode) {
2200 case OP_VOIDCALL_REG:
2201 case OP_VOIDCALL_MEMBASE:
2205 case OP_CALL_MEMBASE:
2208 case OP_LCALL_MEMBASE:
2209 g_assert (ins->dreg == IA64_R8);
2213 case OP_FCALL_MEMBASE:
2214 g_assert (ins->dreg == 8);
2215 if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4)
2216 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2220 case OP_VCALL_MEMBASE:
2223 case OP_VCALL2_MEMBASE: {
2226 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
2227 storage = cinfo->ret.storage;
2229 if (storage == ArgAggregate) {
2230 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2232 /* Load address of stack space allocated for the return value */
2233 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2234 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2235 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2237 for (i = 0; i < cinfo->ret.nregs; ++i) {
2238 switch (cinfo->ret.atype) {
2239 case AggregateNormal:
2240 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2242 case AggregateSingleHFA:
2243 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2245 case AggregateDoubleHFA:
2246 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2249 g_assert_not_reached ();
2256 g_assert_not_reached ();
2262 #define add_patch_info(cfg,code,patch_type,data) do { \
2263 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2266 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2267 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2269 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2271 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2272 ia64_br_cond_pred (code, (predicate), 0); \
2275 static Ia64CodegenState
2276 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2278 add_patch_info (cfg, code, patch_type, data);
2280 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2282 /* mono_arch_patch_callsite will patch this */
2283 /* mono_arch_nullify_class_init_trampoline will patch this */
2284 ia64_movl (code, GP_SCRATCH_REG, 0);
2285 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2286 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2287 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2288 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2291 /* Can't use a direct call since the displacement might be too small */
2292 /* mono_arch_patch_callsite will patch this */
2293 ia64_movl (code, GP_SCRATCH_REG, 0);
2294 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2295 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2301 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2304 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2309 Ia64CodegenState code;
2310 guint8 *code_start = cfg->native_code + cfg->code_len;
2311 MonoInst *last_ins = NULL;
2312 guint last_offset = 0;
2315 if (cfg->opt & MONO_OPT_LOOP) {
2319 if (cfg->verbose_level > 2)
2320 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2322 cpos = bb->max_offset;
2324 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2328 offset = code_start - cfg->native_code;
2330 ia64_codegen_init (code, code_start);
2333 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2337 MONO_BB_FOR_EACH_INS (bb, ins) {
2338 offset = code.buf - cfg->native_code;
2340 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2342 while (offset + max_len + 16 > cfg->code_size) {
2343 ia64_codegen_close (code);
2345 offset = code.buf - cfg->native_code;
2347 cfg->code_size *= 2;
2348 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2349 code_start = cfg->native_code + offset;
2350 mono_jit_stats.code_reallocs++;
2352 ia64_codegen_init (code, code_start);
2355 mono_debug_record_line_number (cfg, ins, offset);
2357 switch (ins->opcode) {
2360 if (ia64_is_imm14 (ins->inst_c0))
2361 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2363 ia64_movl (code, ins->dreg, ins->inst_c0);
2366 add_patch_info (cfg, code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2367 ia64_movl (code, ins->dreg, 0);
2370 ia64_mov (code, ins->dreg, ins->sreg1);
2373 case OP_IA64_BR_COND: {
2375 if (ins->opcode == OP_IA64_BR_COND)
2377 if (ins->flags & MONO_INST_BRLABEL) {
2378 if (ins->inst_i0->inst_c0) {
2381 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2382 ia64_br_cond_pred (code, pred, 0);
2385 if (ins->inst_target_bb->native_offset) {
2386 guint8 *pos = code.buf + code.nins;
2388 ia64_br_cond_pred (code, pred, 0);
2389 ia64_begin_bundle (code);
2390 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2392 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2393 ia64_br_cond_pred (code, pred, 0);
2399 ia64_begin_bundle (code);
2400 ins->inst_c0 = code.buf - cfg->native_code;
2403 case OP_RELAXED_NOP:
2405 case OP_DUMMY_STORE:
2406 case OP_NOT_REACHED:
2410 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2411 ia64_br_cond_reg (code, IA64_B6);
2415 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2419 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2423 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2427 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2431 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2435 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2439 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2443 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2447 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2450 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2451 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2454 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2457 /* p6 and p7 is set if there is signed/unsigned overflow */
2459 /* Set p8-p9 == (sreg2 > 0) */
2460 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2462 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2464 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2465 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2466 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2467 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2469 /* res <u sreg1 => unsigned overflow */
2470 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2472 /* FIXME: Predicate this since this is a side effect */
2473 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2476 /* p6 and p7 is set if there is signed/unsigned overflow */
2478 /* Set p8-p9 == (sreg2 > 0) */
2479 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2481 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2483 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2484 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2485 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2486 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2488 /* sreg1 <u sreg2 => unsigned overflow */
2489 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2491 /* FIXME: Predicate this since this is a side effect */
2492 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2495 /* Same as OP_IADDCC */
2496 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2498 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2500 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2501 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2503 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2505 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2508 /* Same as OP_ISUBCC */
2510 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2512 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2514 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2515 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2517 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2519 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2524 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2529 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2533 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2537 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2542 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2547 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2549 case OP_ISHR_UN_IMM:
2550 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2551 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2553 case OP_LSHR_UN_IMM:
2554 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2557 /* Based on gcc code */
2558 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2559 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2560 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2561 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2564 case OP_STOREI1_MEMBASE_REG:
2565 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2567 case OP_STOREI2_MEMBASE_REG:
2568 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2570 case OP_STOREI4_MEMBASE_REG:
2571 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2573 case OP_STOREI8_MEMBASE_REG:
2574 case OP_STORE_MEMBASE_REG:
2575 if (ins->inst_offset != 0) {
2576 /* This is generated by local regalloc */
2577 if (ia64_is_imm14 (ins->inst_offset)) {
2578 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2580 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2581 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2583 ins->inst_destbasereg = GP_SCRATCH_REG;
2585 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2588 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2589 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2591 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2592 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2594 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2595 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2597 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2598 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2601 case OP_LOADU1_MEMBASE:
2602 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2604 case OP_LOADU2_MEMBASE:
2605 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2607 case OP_LOADU4_MEMBASE:
2608 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2610 case OP_LOADI1_MEMBASE:
2611 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2612 ia64_sxt1 (code, ins->dreg, ins->dreg);
2614 case OP_LOADI2_MEMBASE:
2615 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2616 ia64_sxt2 (code, ins->dreg, ins->dreg);
2618 case OP_LOADI4_MEMBASE:
2619 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2620 ia64_sxt4 (code, ins->dreg, ins->dreg);
2622 case OP_LOAD_MEMBASE:
2623 case OP_LOADI8_MEMBASE:
2624 if (ins->inst_offset != 0) {
2625 /* This is generated by local regalloc */
2626 if (ia64_is_imm14 (ins->inst_offset)) {
2627 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2629 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2630 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2632 ins->inst_basereg = GP_SCRATCH_REG;
2634 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2637 case OP_IA64_LOADU1_MEMBASE_INC:
2638 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2640 case OP_IA64_LOADU2_MEMBASE_INC:
2641 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2643 case OP_IA64_LOADU4_MEMBASE_INC:
2644 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2646 case OP_IA64_LOADI8_MEMBASE_INC:
2647 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2651 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2654 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2657 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2660 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2663 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2666 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2669 /* Compare opcodes */
2670 case OP_IA64_CMP4_EQ:
2671 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2673 case OP_IA64_CMP4_NE:
2674 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2676 case OP_IA64_CMP4_LE:
2677 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2679 case OP_IA64_CMP4_LT:
2680 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2682 case OP_IA64_CMP4_GE:
2683 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2685 case OP_IA64_CMP4_GT:
2686 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2688 case OP_IA64_CMP4_LT_UN:
2689 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2691 case OP_IA64_CMP4_LE_UN:
2692 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2694 case OP_IA64_CMP4_GT_UN:
2695 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2697 case OP_IA64_CMP4_GE_UN:
2698 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2700 case OP_IA64_CMP_EQ:
2701 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2703 case OP_IA64_CMP_NE:
2704 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2706 case OP_IA64_CMP_LE:
2707 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2709 case OP_IA64_CMP_LT:
2710 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2712 case OP_IA64_CMP_GE:
2713 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2715 case OP_IA64_CMP_GT:
2716 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2718 case OP_IA64_CMP_GT_UN:
2719 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2721 case OP_IA64_CMP_LT_UN:
2722 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2724 case OP_IA64_CMP_GE_UN:
2725 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2727 case OP_IA64_CMP_LE_UN:
2728 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2730 case OP_IA64_CMP4_EQ_IMM:
2731 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2733 case OP_IA64_CMP4_NE_IMM:
2734 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2736 case OP_IA64_CMP4_LE_IMM:
2737 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2739 case OP_IA64_CMP4_LT_IMM:
2740 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2742 case OP_IA64_CMP4_GE_IMM:
2743 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2745 case OP_IA64_CMP4_GT_IMM:
2746 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2748 case OP_IA64_CMP4_LT_UN_IMM:
2749 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2751 case OP_IA64_CMP4_LE_UN_IMM:
2752 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2754 case OP_IA64_CMP4_GT_UN_IMM:
2755 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2757 case OP_IA64_CMP4_GE_UN_IMM:
2758 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2760 case OP_IA64_CMP_EQ_IMM:
2761 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2763 case OP_IA64_CMP_NE_IMM:
2764 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2766 case OP_IA64_CMP_LE_IMM:
2767 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2769 case OP_IA64_CMP_LT_IMM:
2770 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2772 case OP_IA64_CMP_GE_IMM:
2773 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2775 case OP_IA64_CMP_GT_IMM:
2776 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2778 case OP_IA64_CMP_GT_UN_IMM:
2779 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2781 case OP_IA64_CMP_LT_UN_IMM:
2782 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2784 case OP_IA64_CMP_GE_UN_IMM:
2785 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2787 case OP_IA64_CMP_LE_UN_IMM:
2788 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2790 case OP_IA64_FCMP_EQ:
2791 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2793 case OP_IA64_FCMP_NE:
2794 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2796 case OP_IA64_FCMP_LT:
2797 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2799 case OP_IA64_FCMP_GT:
2800 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2802 case OP_IA64_FCMP_LE:
2803 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2805 case OP_IA64_FCMP_GE:
2806 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2808 case OP_IA64_FCMP_GT_UN:
2809 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2810 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2812 case OP_IA64_FCMP_LT_UN:
2813 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2814 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2816 case OP_IA64_FCMP_GE_UN:
2817 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2818 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2820 case OP_IA64_FCMP_LE_UN:
2821 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2822 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2825 case OP_COND_EXC_IOV:
2826 case OP_COND_EXC_OV:
2827 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2829 case OP_COND_EXC_IC:
2831 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2833 case OP_IA64_COND_EXC:
2834 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2837 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2838 ia64_no_stop (code);
2839 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2841 case OP_ICONV_TO_I1:
2842 case OP_LCONV_TO_I1:
2843 /* FIXME: Is this needed ? */
2844 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2846 case OP_ICONV_TO_I2:
2847 case OP_LCONV_TO_I2:
2848 /* FIXME: Is this needed ? */
2849 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2851 case OP_LCONV_TO_I4:
2852 /* FIXME: Is this needed ? */
2853 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2855 case OP_ICONV_TO_U1:
2856 case OP_LCONV_TO_U1:
2857 /* FIXME: Is this needed */
2858 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2860 case OP_ICONV_TO_U2:
2861 case OP_LCONV_TO_U2:
2862 /* FIXME: Is this needed */
2863 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2865 case OP_LCONV_TO_U4:
2866 /* FIXME: Is this needed */
2867 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2869 case OP_ICONV_TO_I8:
2871 case OP_LCONV_TO_I8:
2873 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2875 case OP_LCONV_TO_U8:
2877 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2884 double d = *(double *)ins->inst_p0;
2886 if ((d == 0.0) && (mono_signbit (d) == 0))
2887 ia64_fmov (code, ins->dreg, 0);
2889 ia64_fmov (code, ins->dreg, 1);
2891 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2892 ia64_movl (code, GP_SCRATCH_REG, 0);
2893 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2898 float f = *(float *)ins->inst_p0;
2900 if ((f == 0.0) && (mono_signbit (f) == 0))
2901 ia64_fmov (code, ins->dreg, 0);
2903 ia64_fmov (code, ins->dreg, 1);
2905 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2906 ia64_movl (code, GP_SCRATCH_REG, 0);
2907 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2912 ia64_fmov (code, ins->dreg, ins->sreg1);
2914 case OP_STORER8_MEMBASE_REG:
2915 if (ins->inst_offset != 0) {
2916 /* This is generated by local regalloc */
2917 if (ia64_is_imm14 (ins->inst_offset)) {
2918 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2920 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2921 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2923 ins->inst_destbasereg = GP_SCRATCH_REG;
2925 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2927 case OP_STORER4_MEMBASE_REG:
2928 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2929 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2931 case OP_LOADR8_MEMBASE:
2932 if (ins->inst_offset != 0) {
2933 /* This is generated by local regalloc */
2934 if (ia64_is_imm14 (ins->inst_offset)) {
2935 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2937 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2938 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2940 ins->inst_basereg = GP_SCRATCH_REG;
2942 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2944 case OP_LOADR4_MEMBASE:
2945 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2946 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2948 case OP_ICONV_TO_R4:
2949 case OP_LCONV_TO_R4:
2950 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2951 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2952 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2954 case OP_ICONV_TO_R8:
2955 case OP_LCONV_TO_R8:
2956 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2957 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2958 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2960 case OP_FCONV_TO_R4:
2961 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2963 case OP_FCONV_TO_I8:
2965 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2966 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2969 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2972 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2975 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2978 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2982 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2983 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2985 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2986 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2987 /* Positive infinity */
2988 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2989 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2990 /* Negative infinity */
2991 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2992 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2997 /* ensure ins->sreg1 is not NULL */
2998 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
3001 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
3002 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
3010 call = (MonoCallInst*)ins;
3012 if (ins->flags & MONO_INST_HAS_METHOD)
3013 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
3015 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
3017 code = emit_move_return_value (cfg, ins, code);
3025 case OP_VOIDCALL_REG: {
3026 MonoCallInst *call = (MonoCallInst*)ins;
3031 * mono_arch_find_this_arg () needs to find the this argument in a global
3034 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
3035 out_reg = cfg->arch.reg_out0;
3036 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
3038 ia64_mov (code, IA64_R10, out_reg);
3041 ia64_mov (code, IA64_R8, ins->sreg1);
3042 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
3043 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3044 ia64_ld8 (code, IA64_GP, IA64_R8);
3045 ia64_br_call_reg (code, IA64_B0, IA64_B6);
3047 code = emit_move_return_value (cfg, ins, code);
3050 case OP_FCALL_MEMBASE:
3051 case OP_LCALL_MEMBASE:
3052 case OP_VCALL_MEMBASE:
3053 case OP_VCALL2_MEMBASE:
3054 case OP_VOIDCALL_MEMBASE:
3055 case OP_CALL_MEMBASE: {
3056 MonoCallInst *call = (MonoCallInst*)ins;
3061 * There are no membase instructions on ia64, but we can't
3062 * lower this since get_vcall_slot_addr () needs to decode it.
3065 /* Keep this in synch with get_vcall_slot_addr */
3066 ia64_mov (code, IA64_R11, ins->sreg1);
3067 if (ia64_is_imm14 (ins->inst_offset))
3068 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
3070 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
3071 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
3074 if (call->method && ins->inst_offset < 0) {
3076 * This is a possible IMT call so save the IMT method in a global
3077 * register where mono_arch_find_imt_method () and its friends can
3080 ia64_movl (code, IA64_R9, call->method);
3084 * mono_arch_find_this_arg () needs to find the this argument in a global
3087 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
3088 out_reg = cfg->arch.reg_out0;
3089 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
3091 ia64_mov (code, IA64_R10, out_reg);
3093 ia64_begin_bundle (code);
3094 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3096 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
3098 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3101 * This nop will tell get_vcall_slot_addr that this is a virtual
3104 ia64_nop_i (code, 0x12345);
3106 ia64_br_call_reg (code, IA64_B0, IA64_B6);
3108 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3110 code = emit_move_return_value (cfg, ins, code);
3115 * Keep in sync with the code in emit_epilog.
3118 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3121 g_assert (!cfg->method->save_lmf);
3123 /* Load arguments into their original registers */
3124 code = emit_load_volatile_arguments (cfg, code);
3126 if (cfg->arch.stack_alloc_size) {
3127 if (cfg->arch.omit_fp) {
3128 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
3129 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
3131 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
3132 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3136 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
3138 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3139 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3141 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3142 ia64_movl (code, GP_SCRATCH_REG, 0);
3143 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3144 ia64_br_cond_reg (code, IA64_B6);
3149 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
3155 /* FIXME: Sigaltstack support */
3157 /* keep alignment */
3158 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
3159 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
3160 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3162 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3164 ia64_mov (code, ins->dreg, IA64_SP);
3166 /* An area at sp is reserved by the ABI for parameter passing */
3167 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
3168 if (ia64_is_adds_imm (abi_offset))
3169 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3171 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3172 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3175 if (ins->flags & MONO_INST_INIT) {
3177 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3179 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3182 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3183 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3184 ia64_br_cond_pred (code, 8, -2);
3186 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3188 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3193 case OP_LOCALLOC_IMM: {
3196 /* FIXME: Sigaltstack support */
3198 gssize size = ins->inst_imm;
3199 size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
3201 if (ia64_is_adds_imm (size))
3202 ia64_adds_imm (code, GP_SCRATCH_REG, size, IA64_R0);
3204 ia64_movl (code, GP_SCRATCH_REG, size);
3206 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3207 ia64_mov (code, ins->dreg, IA64_SP);
3209 /* An area at sp is reserved by the ABI for parameter passing */
3210 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
3211 if (ia64_is_adds_imm (abi_offset))
3212 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3214 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3215 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3218 if (ins->flags & MONO_INST_INIT) {
3220 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3222 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3225 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3226 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3227 ia64_br_cond_pred (code, 8, -2);
3229 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3231 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3237 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
3238 ia64_ld8 (code, ins->dreg, ins->dreg);
3241 /* Synchronization */
3242 case OP_MEMORY_BARRIER:
3245 case OP_ATOMIC_ADD_IMM_NEW_I4:
3246 g_assert (ins->inst_offset == 0);
3247 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3248 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3250 case OP_ATOMIC_ADD_IMM_NEW_I8:
3251 g_assert (ins->inst_offset == 0);
3252 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3253 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3255 case OP_ATOMIC_EXCHANGE_I4:
3256 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3257 ia64_sxt4 (code, ins->dreg, ins->dreg);
3259 case OP_ATOMIC_EXCHANGE_I8:
3260 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3262 case OP_ATOMIC_ADD_NEW_I4: {
3263 guint8 *label, *buf;
3265 /* From libatomic_ops */
3268 ia64_begin_bundle (code);
3269 label = code.buf + code.nins;
3270 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
3271 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3272 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3273 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3274 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3275 buf = code.buf + code.nins;
3276 ia64_br_cond_pred (code, 7, 0);
3277 ia64_begin_bundle (code);
3278 ia64_patch (buf, label);
3279 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3282 case OP_ATOMIC_ADD_NEW_I8: {
3283 guint8 *label, *buf;
3285 /* From libatomic_ops */
3288 ia64_begin_bundle (code);
3289 label = code.buf + code.nins;
3290 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
3291 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3292 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3293 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3294 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3295 buf = code.buf + code.nins;
3296 ia64_br_cond_pred (code, 7, 0);
3297 ia64_begin_bundle (code);
3298 ia64_patch (buf, label);
3299 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3303 /* Exception handling */
3304 case OP_CALL_HANDLER:
3306 * Using a call instruction would mess up the register stack, so
3307 * save the return address to a register and use a
3310 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3311 ia64_mov (code, IA64_R15, IA64_R0);
3312 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3313 /* Add the length of OP_CALL_HANDLER */
3314 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3315 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3316 ia64_movl (code, GP_SCRATCH_REG2, 0);
3317 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3318 ia64_br_cond_reg (code, IA64_B6);
3319 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3321 case OP_START_HANDLER: {
3323 * We receive the return address in GP_SCRATCH_REG.
3325 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3328 * R15 determines our caller. It is used since it is writable using
3330 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3331 * R15 != 0 means we are called by call_filter ().
3333 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3334 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3336 ia64_br_cond_pred (code, 6, 6);
3339 * Called by call_filter:
3340 * Allocate a new stack frame, and set the fp register from the
3341 * value passed in by the caller.
3342 * We allocate a similar frame as is done by the prolog, so
3343 * if an exception is thrown while executing the filter, the
3344 * unwinder can unwind through the filter frame using the unwind
3345 * info for the prolog.
3347 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);
3348 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3349 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3350 ia64_mov (code, cfg->frame_reg, IA64_R15);
3351 /* Signal to endfilter that we are called by call_filter */
3352 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3354 /* Branch target: */
3355 if (ia64_is_imm14 (spvar->inst_offset))
3356 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3358 ia64_movl (code, GP_SCRATCH_REG2, spvar->inst_offset);
3359 ia64_add (code, GP_SCRATCH_REG2, cfg->frame_reg, GP_SCRATCH_REG2);
3362 /* Save the return address */
3363 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3364 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3369 case OP_ENDFILTER: {
3370 /* FIXME: Return the value in ENDFILTER */
3371 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3373 /* Load the return address */
3374 if (ia64_is_imm14 (spvar->inst_offset)) {
3375 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3377 ia64_movl (code, GP_SCRATCH_REG, spvar->inst_offset);
3378 ia64_add (code, GP_SCRATCH_REG, cfg->frame_reg, GP_SCRATCH_REG);
3380 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3383 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3384 ia64_br_cond_pred (code, 7, 4);
3386 /* Called by call_filter */
3388 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3389 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3390 ia64_br_ret_reg (code, IA64_B0);
3392 /* Called by CALL_HANDLER */
3393 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3394 ia64_br_cond_reg (code, IA64_B6);
3398 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3399 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3400 (gpointer)"mono_arch_throw_exception");
3403 * This might be the last instruction in the method, so add a dummy
3404 * instruction so the unwinder will work.
3406 ia64_break_i (code, 0);
3409 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3410 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3411 (gpointer)"mono_arch_rethrow_exception");
3413 ia64_break_i (code, 0);
3417 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3418 g_assert_not_reached ();
3421 if ((code.buf - cfg->native_code - offset) > max_len) {
3422 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3423 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3424 g_assert_not_reached ();
3430 last_offset = offset;
3433 ia64_codegen_close (code);
3435 cfg->code_len = code.buf - cfg->native_code;
3439 mono_arch_register_lowlevel_calls (void)
3443 static Ia64InsType ins_types_in_template [32][3] = {
3444 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3445 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3446 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3447 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3448 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3449 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3452 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3453 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3454 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3455 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3456 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3457 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3458 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3459 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3460 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3461 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3462 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3463 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3466 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3467 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3468 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3469 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3472 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3473 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3478 static gboolean stops_in_template [32][3] = {
3479 { FALSE, FALSE, FALSE },
3480 { FALSE, FALSE, TRUE },
3481 { FALSE, TRUE, FALSE },
3482 { FALSE, TRUE, TRUE },
3483 { FALSE, FALSE, FALSE },
3484 { FALSE, FALSE, TRUE },
3485 { FALSE, FALSE, FALSE },
3486 { FALSE, FALSE, FALSE },
3488 { FALSE, FALSE, FALSE },
3489 { FALSE, FALSE, TRUE },
3490 { TRUE, FALSE, FALSE },
3491 { TRUE, FALSE, TRUE },
3492 { FALSE, FALSE, FALSE },
3493 { FALSE, FALSE, TRUE },
3494 { FALSE, FALSE, FALSE },
3495 { FALSE, FALSE, TRUE },
3497 { FALSE, FALSE, FALSE },
3498 { FALSE, FALSE, TRUE },
3499 { FALSE, FALSE, FALSE },
3500 { FALSE, FALSE, TRUE },
3501 { FALSE, FALSE, FALSE },
3502 { FALSE, FALSE, FALSE },
3503 { FALSE, FALSE, FALSE },
3504 { FALSE, FALSE, TRUE },
3506 { FALSE, FALSE, FALSE },
3507 { FALSE, FALSE, TRUE },
3508 { FALSE, FALSE, FALSE },
3509 { FALSE, FALSE, FALSE },
3510 { FALSE, FALSE, FALSE },
3511 { FALSE, FALSE, TRUE },
3512 { FALSE, FALSE, FALSE },
3513 { FALSE, FALSE, FALSE }
3516 static int last_stop_in_template [32] = {
3517 -1, 2, 1, 2, -1, 2, -1, -1,
3518 -1, 2, 0, 2, -1, 2, -1, 2,
3519 -1, 2, -1, 2, -1, -1, -1, 2,
3520 -1, 2, -1, -1, -1, 2, -1, -1
3523 static guint64 nops_for_ins_types [6] = {
3532 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3539 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3541 #define DEBUG_INS_SCHED(a)
3545 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3547 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3548 guint8 *deps = code->dep_info;
3549 gboolean need_stop, no_stop;
3551 for (i = 0; i < code->nins; ++i)
3555 current_deps_start = 0;
3556 current_ins_start = 0;
3557 deps_start [ins_index] = current_ins_start;
3560 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3561 while (pos < code->dep_info_pos) {
3563 switch (deps [pos]) {
3564 case IA64_END_OF_INS:
3566 current_ins_start = pos + 2;
3567 deps_start [ins_index] = current_ins_start;
3569 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3574 reg = deps [pos + 1];
3576 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3577 for (i = current_deps_start; i < current_ins_start; i += 2)
3578 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3582 reg = code->dep_info [pos + 1];
3584 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3585 for (i = current_deps_start; i < current_ins_start; i += 2)
3586 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3590 reg = deps [pos + 1];
3592 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3593 for (i = current_deps_start; i < current_ins_start; i += 2)
3594 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3597 case IA64_READ_PR_BRANCH:
3598 reg = deps [pos + 1];
3600 /* Writes to prs by non-float instructions are visible to branches */
3601 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3602 for (i = current_deps_start; i < current_ins_start; i += 2)
3603 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3607 reg = code->dep_info [pos + 1];
3609 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3610 for (i = current_deps_start; i < current_ins_start; i += 2)
3611 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3614 case IA64_WRITE_PR_FLOAT:
3615 reg = code->dep_info [pos + 1];
3617 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3618 for (i = current_deps_start; i < current_ins_start; i += 2)
3619 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3623 reg = deps [pos + 1];
3625 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3626 for (i = current_deps_start; i < current_ins_start; i += 2)
3627 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3631 reg = code->dep_info [pos + 1];
3633 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3634 for (i = current_deps_start; i < current_ins_start; i += 2)
3635 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3638 case IA64_READ_BR_BRANCH:
3639 reg = deps [pos + 1];
3641 /* Writes to brs are visible to branches */
3642 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3645 reg = deps [pos + 1];
3647 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3648 for (i = current_deps_start; i < current_ins_start; i += 2)
3649 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3653 reg = code->dep_info [pos + 1];
3655 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3656 for (i = current_deps_start; i < current_ins_start; i += 2)
3657 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3661 reg = deps [pos + 1];
3663 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3664 for (i = current_deps_start; i < current_ins_start; i += 2)
3665 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3669 reg = code->dep_info [pos + 1];
3671 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3672 for (i = current_deps_start; i < current_ins_start; i += 2)
3673 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3678 * Explicitly indicate that a stop is not required. Useful for
3679 * example when two predicated instructions with negated predicates
3680 * write the same registers.
3685 g_assert_not_reached ();
3689 if (need_stop && !no_stop) {
3690 g_assert (ins_index > 0);
3691 stops [ins_index - 1] = 1;
3693 DEBUG_INS_SCHED (printf ("STOP\n"));
3694 current_deps_start = current_ins_start;
3696 /* Skip remaining deps for this instruction */
3697 while (deps [pos] != IA64_END_OF_INS)
3702 if (code->nins > 0) {
3703 /* No dependency info for the last instruction */
3704 stops [code->nins - 1] = 1;
3707 deps_start [code->nins] = code->dep_info_pos;
3711 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3713 int stop_pos, i, deps_to_shift, dep_shift;
3715 g_assert (n <= code->nins);
3717 // if (n > 1) printf ("FOUND: %ld.\n", template);
3719 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3721 stop_pos = last_stop_in_template [template] + 1;
3725 /* Compute the number of 'real' instructions before the stop */
3726 deps_to_shift = stop_pos;
3727 if (stop_pos >= 3 && (nops & (1 << 2)))
3729 if (stop_pos >= 2 && (nops & (1 << 1)))
3731 if (stop_pos >= 1 && (nops & (1 << 0)))
3735 * We have to keep some dependencies whose instructions have been shifted
3736 * out of the buffer. So nullify the end_of_ins markers in the dependency
3739 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3740 if (code->dep_info [i] == IA64_END_OF_INS)
3741 code->dep_info [i] = IA64_NONE;
3743 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3744 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3745 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3747 dep_shift = deps_start [deps_to_shift];
3748 for (i = 0; i < code->nins + 1 - n; ++i)
3749 deps_start [i] = deps_start [n + i] - dep_shift;
3751 /* Determine the exact positions of instructions with unwind ops */
3752 if (code->unw_op_count) {
3754 int curr_ins, curr_ins_pos;
3757 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3758 for (i = 0; i < 3; ++i) {
3759 if (! (nops & (1 << i))) {
3760 ins_pos [curr_ins] = curr_ins_pos + i;
3765 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3766 if (code->unw_ops_pos [i] < n) {
3767 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3768 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3771 if (code->unw_op_pos < code->unw_op_count)
3772 code->unw_op_pos += n;
3775 if (n == code->nins) {
3780 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3781 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3782 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3788 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3790 int i, ins_type, template, nins_to_emit;
3791 int deps_start [16];
3796 * We implement a simple scheduler which tries to put three instructions
3797 * per bundle, then two, then one.
3799 ia64_analyze_deps (code, deps_start, stops);
3801 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3802 /* Find a suitable template */
3803 for (template = 0; template < 32; ++template) {
3804 if (stops_in_template [template][0] != stops [0] ||
3805 stops_in_template [template][1] != stops [1] ||
3806 stops_in_template [template][2] != stops [2])
3810 for (i = 0; i < 3; ++i) {
3811 ins_type = ins_types_in_template [template][i];
3812 switch (code->itypes [i]) {
3813 case IA64_INS_TYPE_A:
3814 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3817 found &= (ins_type == code->itypes [i]);
3823 found = debug_ins_sched ();
3826 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3832 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3833 /* Wait for more instructions */
3836 /* If it didn't work out, try putting two instructions into one bundle */
3837 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3838 /* Try a nop at the end */
3839 for (template = 0; template < 32; ++template) {
3840 if (stops_in_template [template][0] != stops [0] ||
3841 ((stops_in_template [template][1] != stops [1]) &&
3842 (stops_in_template [template][2] != stops [1])))
3846 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3847 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3850 if (!debug_ins_sched ())
3853 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);
3858 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3859 /* Wait for more instructions */
3862 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3863 /* Try a nop in the middle */
3864 for (template = 0; template < 32; ++template) {
3865 if (((stops_in_template [template][0] != stops [0]) &&
3866 (stops_in_template [template][1] != stops [0])) ||
3867 stops_in_template [template][2] != stops [1])
3870 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3871 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3874 if (!debug_ins_sched ())
3877 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);
3882 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3883 /* Try a nop at the beginning */
3884 for (template = 0; template < 32; ++template) {
3885 if ((stops_in_template [template][1] != stops [0]) ||
3886 (stops_in_template [template][2] != stops [1]))
3889 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3890 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3893 if (!debug_ins_sched ())
3896 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);
3901 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3902 /* Wait for more instructions */
3906 nins_to_emit = code->nins;
3910 while (nins_to_emit > 0) {
3911 if (!debug_ins_sched ())
3913 switch (code->itypes [0]) {
3914 case IA64_INS_TYPE_A:
3916 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3918 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3920 case IA64_INS_TYPE_I:
3922 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3924 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3926 case IA64_INS_TYPE_M:
3928 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3930 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3932 case IA64_INS_TYPE_B:
3934 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3936 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3938 case IA64_INS_TYPE_F:
3940 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3942 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3944 case IA64_INS_TYPE_LX:
3945 if (stops [0] || stops [1])
3946 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3948 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3952 g_assert_not_reached ();
3958 unw_dyn_region_info_t*
3959 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3961 unw_dyn_region_info_t *r;
3963 g_assert (code->nins == 0);
3964 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3965 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3966 r->op_count = code->unw_op_count;
3967 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3968 code->unw_op_count = 0;
3969 code->unw_op_pos = 0;
3970 code->region_start = code->buf;
3976 ia64_patch (unsigned char* code, gpointer target)
3979 guint64 instructions [3];
3980 guint8 gen_buf [16];
3981 Ia64CodegenState gen;
3986 * code encodes both the position inside the buffer and code.nins when
3987 * the instruction was emitted.
3989 ins_to_skip = (guint64)code % 16;
3990 code = (unsigned char*)((guint64)code & ~15);
3993 * Search for the first instruction which is 'patchable', skipping
3994 * ins_to_skip instructions.
3999 template = ia64_bundle_template (code);
4000 instructions [0] = ia64_bundle_ins1 (code);
4001 instructions [1] = ia64_bundle_ins2 (code);
4002 instructions [2] = ia64_bundle_ins3 (code);
4004 ia64_codegen_init (gen, gen_buf);
4007 for (i = 0; i < 3; ++i) {
4008 guint64 ins = instructions [i];
4009 int opcode = ia64_ins_opcode (ins);
4011 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
4019 switch (ins_types_in_template [template][i]) {
4020 case IA64_INS_TYPE_A:
4021 case IA64_INS_TYPE_M:
4022 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
4024 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
4025 instructions [i] = gen.instructions [0];
4031 case IA64_INS_TYPE_B:
4032 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
4034 gint64 disp = ((guint8*)target - code) >> 4;
4037 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
4039 instructions [i] = gen.instructions [0];
4042 else if (opcode == 5) {
4044 gint64 disp = ((guint8*)target - code) >> 4;
4047 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
4048 instructions [i] = gen.instructions [0];
4054 case IA64_INS_TYPE_LX:
4058 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
4060 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
4061 instructions [1] = gen.instructions [0];
4062 instructions [2] = gen.instructions [1];
4075 ia64_codegen_init (gen, code);
4076 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
4086 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4088 MonoJumpInfo *patch_info;
4090 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4091 unsigned char *ip = patch_info->ip.i + code;
4092 const unsigned char *target;
4094 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4096 if (patch_info->type == MONO_PATCH_INFO_NONE)
4098 if (mono_compile_aot) {
4102 ia64_patch (ip, (gpointer)target);
4107 mono_arch_emit_prolog (MonoCompile *cfg)
4109 MonoMethod *method = cfg->method;
4110 MonoMethodSignature *sig;
4112 int alloc_size, pos, i;
4113 Ia64CodegenState code;
4116 sig = mono_method_signature (method);
4119 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4121 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
4123 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4124 cfg->code_size += 1024;
4125 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4126 cfg->code_size += 1024;
4128 cfg->native_code = g_malloc (cfg->code_size);
4130 ia64_codegen_init (code, cfg->native_code);
4132 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
4133 if (cfg->param_area)
4134 alloc_size += cfg->param_area;
4138 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
4140 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
4141 /* Force sp to be saved/restored */
4142 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
4144 cfg->arch.stack_alloc_size = alloc_size;
4148 if (method->save_lmf) {
4149 /* No LMF on IA64 */
4154 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
4155 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);
4156 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
4157 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
4159 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
4160 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
4161 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
4162 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
4163 ia64_mov (code, cfg->frame_reg, IA64_SP);
4167 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4168 int pagesize = getpagesize ();
4170 if (alloc_size >= pagesize) {
4171 gint32 remaining_size = alloc_size;
4173 /* Generate stack touching code */
4174 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
4175 while (remaining_size >= pagesize) {
4176 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
4177 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4178 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4179 remaining_size -= pagesize;
4183 if (ia64_is_imm14 (-alloc_size)) {
4184 if (cfg->arch.omit_fp)
4185 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4186 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
4189 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
4190 if (cfg->arch.omit_fp)
4191 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4192 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4196 ia64_begin_bundle (code);
4198 /* Initialize unwind info */
4199 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
4201 if (sig->ret->type != MONO_TYPE_VOID) {
4202 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
4203 /* Save volatile arguments to the stack */
4208 /* Keep this in sync with emit_load_volatile_arguments */
4209 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4210 ArgInfo *ainfo = cinfo->args + i;
4211 gint32 stack_offset;
4214 inst = cfg->args [i];
4216 if (sig->hasthis && (i == 0))
4217 arg_type = &mono_defaults.object_class->byval_arg;
4219 arg_type = sig->params [i - sig->hasthis];
4221 arg_type = mono_type_get_underlying_type (arg_type);
4223 stack_offset = ainfo->offset + ARGS_OFFSET;
4226 * FIXME: Native code might pass non register sized integers
4227 * without initializing the upper bits.
4229 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && !arg_type->byref && ainfo->storage == ArgInIReg) {
4230 int reg = cfg->arch.reg_in0 + ainfo->reg;
4232 switch (mono_type_to_load_membase (cfg, arg_type)) {
4233 case OP_LOADI1_MEMBASE:
4234 ia64_sxt1 (code, reg, reg);
4236 case OP_LOADU1_MEMBASE:
4237 ia64_zxt1 (code, reg, reg);
4239 case OP_LOADI2_MEMBASE:
4240 ia64_sxt2 (code, reg, reg);
4242 case OP_LOADU2_MEMBASE:
4243 ia64_zxt2 (code, reg, reg);
4250 /* Save volatile arguments to the stack */
4251 if (inst->opcode != OP_REGVAR) {
4252 switch (ainfo->storage) {
4255 case ArgInFloatRegR4:
4256 g_assert (inst->opcode == OP_REGOFFSET);
4257 if (ia64_is_adds_imm (inst->inst_offset))
4258 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4260 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
4261 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4263 if (arg_type->byref)
4264 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4266 switch (arg_type->type) {
4268 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4271 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4274 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4282 if (ainfo->nslots != ainfo->nregs)
4285 g_assert (inst->opcode == OP_REGOFFSET);
4286 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4287 for (i = 0; i < ainfo->nregs; ++i) {
4288 switch (ainfo->atype) {
4289 case AggregateNormal:
4290 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
4292 case AggregateSingleHFA:
4293 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
4295 case AggregateDoubleHFA:
4296 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4304 g_assert_not_reached ();
4308 if (inst->opcode == OP_REGVAR) {
4309 /* Argument allocated to (non-volatile) register */
4310 switch (ainfo->storage) {
4312 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4313 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4316 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4317 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4325 if (method->save_lmf) {
4326 /* No LMF on IA64 */
4329 ia64_codegen_close (code);
4331 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4332 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4334 cfg->code_len = code.buf - cfg->native_code;
4336 g_assert (cfg->code_len < cfg->code_size);
4338 cfg->arch.prolog_end_offset = cfg->code_len;
4344 mono_arch_emit_epilog (MonoCompile *cfg)
4346 MonoMethod *method = cfg->method;
4348 int max_epilog_size = 16 * 4;
4349 Ia64CodegenState code;
4354 if (mono_jit_trace_calls != NULL)
4355 max_epilog_size += 1024;
4357 cfg->arch.epilog_begin_offset = cfg->code_len;
4359 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4360 cfg->code_size *= 2;
4361 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4362 mono_jit_stats.code_reallocs++;
4365 /* FIXME: Emit unwind info */
4367 buf = cfg->native_code + cfg->code_len;
4369 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4370 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4372 ia64_codegen_init (code, buf);
4374 /* the code restoring the registers must be kept in sync with OP_JMP */
4377 if (method->save_lmf) {
4378 /* No LMF on IA64 */
4381 /* Load returned vtypes into registers if needed */
4382 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4383 ainfo = &cinfo->ret;
4384 switch (ainfo->storage) {
4386 if (ainfo->nslots != ainfo->nregs)
4389 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4390 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4391 for (i = 0; i < ainfo->nregs; ++i) {
4392 switch (ainfo->atype) {
4393 case AggregateNormal:
4394 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4396 case AggregateSingleHFA:
4397 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4399 case AggregateDoubleHFA:
4400 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4403 g_assert_not_reached ();
4411 ia64_begin_bundle (code);
4413 code.region_start = cfg->native_code;
4415 /* Label the unwind state at the start of the exception throwing region */
4416 //ia64_unw_label_state (code, 1234);
4418 if (cfg->arch.stack_alloc_size) {
4419 if (cfg->arch.omit_fp) {
4420 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4421 ia64_unw_pop_frames (code, 1);
4422 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4424 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4425 ia64_unw_pop_frames (code, 1);
4426 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4430 ia64_unw_pop_frames (code, 1);
4431 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4434 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4435 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4436 ia64_br_ret_reg (code, IA64_B0);
4438 ia64_codegen_close (code);
4440 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4441 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4443 cfg->code_len = code.buf - cfg->native_code;
4445 g_assert (cfg->code_len < cfg->code_size);
4449 mono_arch_emit_exceptions (MonoCompile *cfg)
4451 MonoJumpInfo *patch_info;
4453 Ia64CodegenState code;
4454 gboolean empty = TRUE;
4455 //unw_dyn_region_info_t *r_exceptions;
4456 MonoClass *exc_classes [16];
4457 guint8 *exc_throw_start [16], *exc_throw_end [16];
4458 guint32 code_size = 0;
4460 /* Compute needed space */
4461 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4462 if (patch_info->type == MONO_PATCH_INFO_EXC)
4464 if (patch_info->type == MONO_PATCH_INFO_R8)
4465 code_size += 8 + 7; /* sizeof (double) + alignment */
4466 if (patch_info->type == MONO_PATCH_INFO_R4)
4467 code_size += 4 + 7; /* sizeof (float) + alignment */
4473 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4474 cfg->code_size *= 2;
4475 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4476 mono_jit_stats.code_reallocs++;
4479 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4481 /* The unwind state here is the same as before the epilog */
4482 //ia64_unw_copy_state (code, 1234);
4484 /* add code to raise exceptions */
4485 /* FIXME: Optimize this */
4487 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4488 switch (patch_info->type) {
4489 case MONO_PATCH_INFO_EXC: {
4490 MonoClass *exc_class;
4493 guint64 exc_token_index;
4495 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4496 g_assert (exc_class);
4497 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4498 throw_ip = cfg->native_code + patch_info->ip.i;
4500 ia64_begin_bundle (code);
4502 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4504 /* Find a throw sequence for the same exception class */
4505 for (i = 0; i < nthrows; ++i)
4506 if (exc_classes [i] == exc_class)
4510 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4512 if (ia64_is_adds_imm (offset))
4513 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4515 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4517 buf = code.buf + code.nins;
4518 ia64_br_cond_pred (code, 0, 0);
4519 ia64_begin_bundle (code);
4520 ia64_patch (buf, exc_throw_start [i]);
4522 patch_info->type = MONO_PATCH_INFO_NONE;
4527 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4529 ia64_begin_bundle (code);
4532 exc_classes [nthrows] = exc_class;
4533 exc_throw_start [nthrows] = code.buf;
4537 if (ia64_is_adds_imm (exc_token_index))
4538 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4540 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4542 patch_info->data.name = "mono_arch_throw_corlib_exception";
4543 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4544 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4547 ia64_movl (code, GP_SCRATCH_REG, 0);
4548 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4549 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4550 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4552 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4554 /* Patch up the throw offset */
4555 ia64_begin_bundle (code);
4557 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4560 exc_throw_end [nthrows] = code.buf;
4574 /* The unwinder needs this to work */
4575 ia64_break_i (code, 0);
4577 ia64_codegen_close (code);
4580 //r_exceptions = mono_ia64_create_unwind_region (&code);
4581 //cfg->arch.r_epilog = r_exceptions;
4583 cfg->code_len = code.buf - cfg->native_code;
4585 g_assert (cfg->code_len < cfg->code_size);
4589 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4591 Ia64CodegenState code;
4592 CallInfo *cinfo = NULL;
4593 MonoMethodSignature *sig;
4595 int i, n, stack_area = 0;
4597 ia64_codegen_init (code, p);
4599 /* Keep this in sync with mono_arch_get_argument_info */
4601 if (enable_arguments) {
4602 /* Allocate a new area on the stack and save arguments there */
4603 sig = mono_method_signature (cfg->method);
4605 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4607 n = sig->param_count + sig->hasthis;
4609 stack_area = ALIGN_TO (n * 8, 16);
4612 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4614 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4616 /* FIXME: Allocate out registers */
4618 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4620 /* Required by the ABI */
4621 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4623 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4624 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4626 /* Save arguments to the stack */
4627 for (i = 0; i < n; ++i) {
4628 ins = cfg->args [i];
4630 if (ins->opcode == OP_REGVAR) {
4631 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4632 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4633 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4636 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4637 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4638 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4639 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4640 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4641 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4646 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4649 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4651 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4652 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4654 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4656 if (enable_arguments && stack_area) {
4657 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4659 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4661 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4664 ia64_codegen_close (code);
4670 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4672 Ia64CodegenState code;
4673 CallInfo *cinfo = NULL;
4674 MonoMethod *method = cfg->method;
4675 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4677 ia64_codegen_init (code, p);
4679 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4681 /* Save return value + pass it to func */
4682 switch (cinfo->ret.storage) {
4686 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4687 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4690 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4691 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4692 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4693 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4695 case ArgValuetypeAddrInIReg:
4696 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4705 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4706 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4707 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4709 /* Restore return value */
4710 switch (cinfo->ret.storage) {
4714 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4717 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4718 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4720 case ArgValuetypeAddrInIReg:
4728 ia64_codegen_close (code);
4734 mono_arch_save_unwind_info (MonoCompile *cfg)
4738 /* FIXME: Unregister this for dynamic methods */
4740 di = g_malloc0 (sizeof (unw_dyn_info_t));
4741 di->start_ip = (unw_word_t) cfg->native_code;
4742 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4744 di->format = UNW_INFO_FORMAT_DYNAMIC;
4745 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4746 di->u.pi.regions = cfg->arch.r_pro;
4748 _U_dyn_register (di);
4752 unw_dyn_region_info_t *region = di->u.pi.regions;
4754 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4756 printf (" [Region: %d]\n", region->insn_count);
4757 region = region->next;
4764 mono_arch_flush_icache (guint8 *code, gint size)
4766 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4767 guint8* end = (guint8*)((guint64)code + size);
4769 #ifdef __INTEL_COMPILER
4770 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4777 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4778 /* FIXME: This could be increased to 128 on some cpus */
4785 mono_arch_flush_register_windows (void)
4787 /* Not needed because of libunwind */
4791 mono_arch_is_inst_imm (gint64 imm)
4793 /* The lowering pass will take care of it */
4799 * Determine whenever the trap whose info is in SIGINFO is caused by
4803 mono_arch_is_int_overflow (void *sigctx, void *info)
4805 /* Division is emulated with explicit overflow checks */
4810 mono_arch_get_patch_offset (guint8 *code)
4818 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4820 guint8 *bundle2 = code - 48;
4821 guint8 *bundle3 = code - 32;
4822 guint8 *bundle4 = code - 16;
4823 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4824 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4825 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4826 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4827 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4828 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4829 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4830 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4831 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4834 * Virtual calls are made with:
4836 * [MII] ld8 r31=[r8]
4840 * mov.sptk b6=r31,0x2000000000f32a80
4847 * br.call.sptk.few b0=b6;;
4850 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4851 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4852 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4853 (ins31 == IA64_NOP_M) &&
4854 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4855 (ins33 == IA64_NOP_I) &&
4856 (ins41 == IA64_NOP_M) &&
4857 (ins42 == IA64_NOP_I) &&
4858 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4859 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4860 g_assert (ins21 == IA64_NOP_M);
4861 g_assert (ins23 == IA64_NOP_I);
4862 g_assert (ia64_ins_opcode (ins22) == 0);
4863 g_assert (ia64_ins_x3 (ins22) == 7);
4864 g_assert (ia64_ins_x (ins22) == 0);
4865 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4867 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4869 return regs [IA64_R11];
4876 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4880 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4883 return (gpointer*)(gpointer)((char*)vt + displacement);
4887 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4894 static gboolean tls_offset_inited = FALSE;
4897 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4899 if (!tls_offset_inited) {
4900 tls_offset_inited = TRUE;
4902 appdomain_tls_offset = mono_domain_get_tls_offset ();
4903 thread_tls_offset = mono_thread_get_tls_offset ();
4908 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4913 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4915 MonoCallInst *call = (MonoCallInst*)inst;
4916 int out_reg = cfg->arch.reg_out0;
4919 CallInfo * cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
4922 if (cinfo->ret.storage == ArgAggregate) {
4923 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4926 * The valuetype is in registers after the call, need to be copied
4927 * to the stack. Save the address to a local here, so the call
4928 * instruction can access it.
4930 g_assert (local->opcode == OP_REGOFFSET);
4931 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4934 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4935 vtarg->sreg1 = vt_reg;
4936 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4937 mono_bblock_add_inst (cfg->cbb, vtarg);
4939 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4945 /* add the this argument */
4946 if (this_reg != -1) {
4948 MONO_INST_NEW (cfg, this, OP_MOVE);
4949 this->type = this_type;
4950 this->sreg1 = this_reg;
4951 this->dreg = mono_regstate_next_int (cfg->rs);
4952 mono_bblock_add_inst (cfg->cbb, this);
4954 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4959 #ifdef MONO_ARCH_HAVE_IMT
4962 * LOCKING: called with the domain lock held
4965 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4966 gpointer fail_tramp)
4970 guint8 *start, *buf;
4971 Ia64CodegenState code;
4973 g_assert (!fail_tramp);
4976 buf = g_malloc0 (size);
4977 ia64_codegen_init (code, buf);
4979 /* IA64_R9 contains the IMT method */
4981 for (i = 0; i < count; ++i) {
4982 MonoIMTCheckItem *item = imt_entries [i];
4983 ia64_begin_bundle (code);
4984 item->code_target = (guint8*)code.buf + code.nins;
4985 if (item->is_equals) {
4986 if (item->check_target_idx) {
4987 if (!item->compare_done) {
4988 ia64_movl (code, GP_SCRATCH_REG, item->key);
4989 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4991 item->jmp_code = (guint8*)code.buf + code.nins;
4992 ia64_br_cond_pred (code, 7, 0);
4994 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4995 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4996 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4997 ia64_br_cond_reg (code, IA64_B6);
4999 /* enable the commented code to assert on wrong method */
5000 #if ENABLE_WRONG_METHOD_CHECK
5001 g_assert_not_reached ();
5003 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
5004 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
5005 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
5006 ia64_br_cond_reg (code, IA64_B6);
5007 #if ENABLE_WRONG_METHOD_CHECK
5008 g_assert_not_reached ();
5012 ia64_movl (code, GP_SCRATCH_REG, item->key);
5013 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
5014 item->jmp_code = (guint8*)code.buf + code.nins;
5015 ia64_br_cond_pred (code, 6, 0);
5018 /* patch the branches to get to the target items */
5019 for (i = 0; i < count; ++i) {
5020 MonoIMTCheckItem *item = imt_entries [i];
5021 if (item->jmp_code) {
5022 if (item->check_target_idx) {
5023 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5028 ia64_codegen_close (code);
5029 g_assert (code.buf - buf <= size);
5031 size = code.buf - buf;
5032 start = mono_code_manager_reserve (domain->code_mp, size);
5033 memcpy (start, buf, size);
5035 mono_arch_flush_icache (start, size);
5037 mono_stats.imt_thunks_size += size;
5043 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
5045 return regs [IA64_R9];
5049 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
5051 /* Done by the implementation of the CALL_MEMBASE opcodes */
5056 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
5058 return (gpointer)regs [IA64_R10];
5062 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5064 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
5068 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5074 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5076 MonoInst *ins = NULL;
5078 if(cmethod->klass->image == mono_defaults.corlib &&
5079 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5080 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5082 * We don't use the generic version in mini_get_inst_for_method () since the
5083 * ia64 has atomic_add_imm opcodes.
5085 if (strcmp (cmethod->name, "Increment") == 0) {
5088 if (fsig->params [0]->type == MONO_TYPE_I4)
5089 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5090 else if (fsig->params [0]->type == MONO_TYPE_I8)
5091 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5093 g_assert_not_reached ();
5094 MONO_INST_NEW (cfg, ins, opcode);
5096 ins->inst_i0 = args [0];
5097 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5100 if (fsig->params [0]->type == MONO_TYPE_I4)
5101 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5102 else if (fsig->params [0]->type == MONO_TYPE_I8)
5103 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5105 g_assert_not_reached ();
5106 MONO_INST_NEW (cfg, ins, opcode);
5108 ins->inst_i0 = args [0];
5109 } else if (strcmp (cmethod->name, "Add") == 0) {
5112 if (fsig->params [0]->type == MONO_TYPE_I4)
5113 opcode = OP_ATOMIC_ADD_NEW_I4;
5114 else if (fsig->params [0]->type == MONO_TYPE_I8)
5115 opcode = OP_ATOMIC_ADD_NEW_I8;
5117 g_assert_not_reached ();
5119 MONO_INST_NEW (cfg, ins, opcode);
5121 ins->inst_i0 = args [0];
5122 ins->inst_i1 = args [1];
5130 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5132 MonoInst *ins = NULL;
5134 if (cmethod->klass->image == mono_defaults.corlib &&
5135 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5136 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5139 * We don't use the generic version in mini_emit_inst_for_method () since we
5140 * ia64 has atomic_add_imm opcodes.
5142 if (strcmp (cmethod->name, "Increment") == 0) {
5145 if (fsig->params [0]->type == MONO_TYPE_I4)
5146 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5147 else if (fsig->params [0]->type == MONO_TYPE_I8)
5148 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5150 g_assert_not_reached ();
5151 MONO_INST_NEW (cfg, ins, opcode);
5152 ins->dreg = mono_alloc_preg (cfg);
5154 ins->inst_basereg = args [0]->dreg;
5155 ins->inst_offset = 0;
5156 MONO_ADD_INS (cfg->cbb, ins);
5157 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5160 if (fsig->params [0]->type == MONO_TYPE_I4)
5161 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5162 else if (fsig->params [0]->type == MONO_TYPE_I8)
5163 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5165 g_assert_not_reached ();
5166 MONO_INST_NEW (cfg, ins, opcode);
5167 ins->dreg = mono_alloc_preg (cfg);
5169 ins->inst_basereg = args [0]->dreg;
5170 ins->inst_offset = 0;
5171 MONO_ADD_INS (cfg->cbb, ins);
5172 } else if (strcmp (cmethod->name, "Add") == 0) {
5174 gboolean is_imm = FALSE;
5177 if ((args [1]->opcode == OP_ICONST) || (args [1]->opcode == OP_I8CONST)) {
5178 imm = (args [1]->opcode == OP_ICONST) ? args [1]->inst_c0 : args [1]->inst_l;
5180 is_imm = (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
5184 if (fsig->params [0]->type == MONO_TYPE_I4)
5185 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5186 else if (fsig->params [0]->type == MONO_TYPE_I8)
5187 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5189 g_assert_not_reached ();
5191 MONO_INST_NEW (cfg, ins, opcode);
5192 ins->dreg = mono_alloc_ireg (cfg);
5193 ins->inst_basereg = args [0]->dreg;
5194 ins->inst_offset = 0;
5195 ins->inst_imm = imm;
5196 ins->type = (opcode == OP_ATOMIC_ADD_IMM_NEW_I4) ? STACK_I4 : STACK_I8;
5198 if (fsig->params [0]->type == MONO_TYPE_I4)
5199 opcode = OP_ATOMIC_ADD_NEW_I4;
5200 else if (fsig->params [0]->type == MONO_TYPE_I8)
5201 opcode = OP_ATOMIC_ADD_NEW_I8;
5203 g_assert_not_reached ();
5205 MONO_INST_NEW (cfg, ins, opcode);
5206 ins->dreg = mono_alloc_ireg (cfg);
5207 ins->inst_basereg = args [0]->dreg;
5208 ins->inst_offset = 0;
5209 ins->sreg2 = args [1]->dreg;
5210 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5212 MONO_ADD_INS (cfg->cbb, ins);
5220 mono_arch_print_tree (MonoInst *tree, int arity)
5225 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5229 if (appdomain_tls_offset == -1)
5232 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5233 ins->inst_offset = appdomain_tls_offset;
5237 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5241 if (thread_tls_offset == -1)
5244 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5245 ins->inst_offset = thread_tls_offset;
5250 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5252 /* FIXME: implement */
5253 g_assert_not_reached ();