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 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
793 ArgInfo *ainfo = &cinfo->args [i];
795 if (ainfo->storage == ArgOnStack) {
797 * The stack offset can only be determined when the frame
800 cfg->arch.omit_fp = FALSE;
804 mono_ia64_alloc_stacked_registers (cfg);
807 * We use the ABI calling conventions for managed code as well.
808 * Exception: valuetypes are never passed or returned in registers.
811 if (cfg->arch.omit_fp) {
812 cfg->flags |= MONO_CFG_HAS_SPILLUP;
813 cfg->frame_reg = IA64_SP;
814 offset = ARGS_OFFSET;
817 /* Locals are allocated backwards from %fp */
818 cfg->frame_reg = cfg->arch.reg_fp;
822 if (cfg->method->save_lmf) {
826 if (sig->ret->type != MONO_TYPE_VOID) {
827 switch (cinfo->ret.storage) {
829 cfg->ret->opcode = OP_REGVAR;
830 cfg->ret->inst_c0 = cinfo->ret.reg;
833 cfg->ret->opcode = OP_REGVAR;
834 cfg->ret->inst_c0 = cinfo->ret.reg;
836 case ArgValuetypeAddrInIReg:
837 cfg->vret_addr->opcode = OP_REGVAR;
838 cfg->vret_addr->dreg = cfg->arch.reg_in0 + cinfo->ret.reg;
841 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
842 if (cfg->arch.omit_fp)
843 g_assert_not_reached ();
844 offset = ALIGN_TO (offset, 8);
845 offset += cinfo->ret.nslots * 8;
846 cfg->ret->opcode = OP_REGOFFSET;
847 cfg->ret->inst_basereg = cfg->frame_reg;
848 cfg->ret->inst_offset = - offset;
851 g_assert_not_reached ();
853 cfg->ret->dreg = cfg->ret->inst_c0;
856 /* Allocate locals */
857 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
858 if (locals_stack_align) {
859 offset = ALIGN_TO (offset, locals_stack_align);
861 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
862 if (offsets [i] != -1) {
863 MonoInst *inst = cfg->varinfo [i];
864 inst->opcode = OP_REGOFFSET;
865 inst->inst_basereg = cfg->frame_reg;
866 if (cfg->arch.omit_fp)
867 inst->inst_offset = (offset + offsets [i]);
869 inst->inst_offset = - (offset + offsets [i]);
870 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
873 offset += locals_stack_size;
875 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
876 if (cfg->arch.omit_fp)
877 g_assert_not_reached ();
878 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
879 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
882 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
883 inst = cfg->args [i];
884 if (inst->opcode != OP_REGVAR) {
885 ArgInfo *ainfo = &cinfo->args [i];
886 gboolean inreg = TRUE;
889 if (sig->hasthis && (i == 0))
890 arg_type = &mono_defaults.object_class->byval_arg;
892 arg_type = sig->params [i - sig->hasthis];
894 /* FIXME: VOLATILE is only set if the liveness pass runs */
895 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
898 inst->opcode = OP_REGOFFSET;
900 switch (ainfo->storage) {
902 inst->opcode = OP_REGVAR;
903 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
906 case ArgInFloatRegR4:
908 * Since float regs are volatile, we save the arguments to
909 * the stack in the prolog.
914 if (cfg->arch.omit_fp)
915 g_assert_not_reached ();
916 inst->opcode = OP_REGOFFSET;
917 inst->inst_basereg = cfg->frame_reg;
918 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
927 if (!inreg && (ainfo->storage != ArgOnStack)) {
930 inst->opcode = OP_REGOFFSET;
931 inst->inst_basereg = cfg->frame_reg;
932 /* These arguments are saved to the stack in the prolog */
933 switch (ainfo->storage) {
935 if (ainfo->atype == AggregateSingleHFA)
936 size = ainfo->nslots * 4;
938 size = ainfo->nslots * 8;
941 size = sizeof (gpointer);
945 offset = ALIGN_TO (offset, sizeof (gpointer));
947 if (cfg->arch.omit_fp) {
948 inst->inst_offset = offset;
952 inst->inst_offset = - offset;
959 * FIXME: This doesn't work because some variables are allocated during local
963 if (cfg->arch.omit_fp && offset == 16)
967 cfg->stack_offset = offset;
971 mono_arch_create_vars (MonoCompile *cfg)
973 MonoMethodSignature *sig;
976 sig = mono_method_signature (cfg->method);
978 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
980 if (cinfo->ret.storage == ArgAggregate)
981 cfg->ret_var_is_local = TRUE;
982 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
983 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
984 if (G_UNLIKELY (cfg->verbose_level > 1)) {
985 printf ("vret_addr = ");
986 mono_print_ins (cfg->vret_addr);
992 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
996 arg->opcode = OP_OUTARG_REG;
997 arg->inst_left = tree;
998 arg->inst_right = (MonoInst*)call;
999 arg->backend.reg3 = reg;
1000 call->used_iregs |= 1 << reg;
1003 arg->opcode = OP_OUTARG_FREG;
1004 arg->inst_left = tree;
1005 arg->inst_right = (MonoInst*)call;
1006 arg->backend.reg3 = reg;
1007 call->used_fregs |= 1 << reg;
1009 case ArgInFloatRegR4:
1010 arg->opcode = OP_OUTARG_FREG_R4;
1011 arg->inst_left = tree;
1012 arg->inst_right = (MonoInst*)call;
1013 arg->backend.reg3 = reg;
1014 call->used_fregs |= 1 << reg;
1017 g_assert_not_reached ();
1022 add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
1026 MONO_INST_NEW (cfg, arg, OP_NOP);
1027 arg->sreg1 = tree->dreg;
1031 arg->opcode = OP_MOVE;
1032 arg->dreg = mono_alloc_ireg (cfg);
1034 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, FALSE);
1037 arg->opcode = OP_FMOVE;
1038 arg->dreg = mono_alloc_freg (cfg);
1040 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1042 case ArgInFloatRegR4:
1043 arg->opcode = OP_FCONV_TO_R4;
1044 arg->dreg = mono_alloc_freg (cfg);
1046 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1049 g_assert_not_reached ();
1052 MONO_ADD_INS (cfg->cbb, arg);
1056 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1059 MonoMethodSignature *tmp_sig;
1062 /* FIXME: Add support for signature tokens to AOT */
1063 cfg->disable_aot = TRUE;
1065 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1068 * mono_ArgIterator_Setup assumes the signature cookie is
1069 * passed first and all the arguments which were before it are
1070 * passed on the stack after the signature. So compensate by
1071 * passing a different signature.
1073 tmp_sig = mono_metadata_signature_dup (call->signature);
1074 tmp_sig->param_count -= call->signature->sentinelpos;
1075 tmp_sig->sentinelpos = 0;
1076 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1078 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1079 sig_arg->inst_p0 = tmp_sig;
1081 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1082 arg->inst_left = sig_arg;
1083 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1084 arg->type = STACK_PTR;
1086 /* prepend, so they get reversed */
1087 arg->next = call->out_args;
1088 call->out_args = arg;
1092 * take the arguments and generate the arch-specific
1093 * instructions to properly call the function in call.
1094 * This includes pushing, moving arguments to the right register
1098 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1101 MonoMethodSignature *sig;
1102 int i, n, stack_size;
1108 mono_ia64_alloc_stacked_registers (cfg);
1110 sig = call->signature;
1111 n = sig->param_count + sig->hasthis;
1113 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1115 if (cinfo->ret.storage == ArgAggregate) {
1116 /* The code in emit_this_vret_arg needs a local */
1117 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1118 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1121 for (i = 0; i < n; ++i) {
1122 ainfo = cinfo->args + i;
1124 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1125 /* Emit the signature cookie just before the implicit arguments */
1126 emit_sig_cookie (cfg, call, cinfo);
1129 if (is_virtual && i == 0) {
1130 /* the argument will be attached to the call instruction */
1131 in = call->args [i];
1135 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1136 in = call->args [i];
1137 arg->cil_code = in->cil_code;
1138 arg->inst_left = in;
1139 arg->type = in->type;
1140 /* prepend, so they get reversed */
1141 arg->next = call->out_args;
1142 call->out_args = arg;
1144 if (sig->hasthis && (i == 0))
1145 arg_type = &mono_defaults.object_class->byval_arg;
1147 arg_type = sig->params [i - sig->hasthis];
1149 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1150 MonoInst *stack_addr;
1154 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1155 size = sizeof (MonoTypedRef);
1156 align = sizeof (gpointer);
1160 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1163 * Other backends use mini_type_stack_size (), but that
1164 * aligns the size to 8, which is larger than the size of
1165 * the source, leading to reads of invalid memory if the
1166 * source is at the end of address space.
1168 size = mono_class_value_size (in->klass, &align);
1171 if (ainfo->storage == ArgAggregate) {
1172 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1175 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1178 * Part of the structure is passed in registers.
1180 for (j = 0; j < ainfo->nregs; ++j) {
1181 int offset, load_op, dest_reg, arg_storage;
1183 slot = ainfo->reg + j;
1185 if (ainfo->atype == AggregateSingleHFA) {
1186 load_op = CEE_LDIND_R4;
1188 dest_reg = ainfo->reg + j;
1189 arg_storage = ArgInFloatReg;
1190 } else if (ainfo->atype == AggregateDoubleHFA) {
1191 load_op = CEE_LDIND_R8;
1193 dest_reg = ainfo->reg + j;
1194 arg_storage = ArgInFloatReg;
1196 load_op = CEE_LDIND_I;
1198 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1199 arg_storage = ArgInIReg;
1202 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1203 load->ssa_op = MONO_SSA_LOAD;
1204 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1206 NEW_ICONST (cfg, offset_ins, offset);
1207 MONO_INST_NEW (cfg, load2, CEE_ADD);
1208 load2->inst_left = load;
1209 load2->inst_right = offset_ins;
1211 MONO_INST_NEW (cfg, load, load_op);
1212 load->inst_left = load2;
1217 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1218 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1219 if (set_reg != call->out_args) {
1220 set_reg->next = call->out_args;
1221 call->out_args = set_reg;
1226 * Part of the structure is passed on the stack.
1228 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1231 slot = ainfo->reg + j;
1233 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1234 load->ssa_op = MONO_SSA_LOAD;
1235 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1237 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1238 MONO_INST_NEW (cfg, load2, CEE_ADD);
1239 load2->inst_left = load;
1240 load2->inst_right = offset_ins;
1242 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1243 load->inst_left = load2;
1248 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1249 outarg->inst_left = load;
1250 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1252 if (outarg != call->out_args) {
1253 outarg->next = call->out_args;
1254 call->out_args = outarg;
1258 /* Trees can't be shared so make a copy */
1259 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1260 arg->cil_code = in->cil_code;
1261 arg->ssa_op = MONO_SSA_STORE;
1262 arg->inst_left = vtaddr;
1263 arg->inst_right = in;
1264 arg->type = in->type;
1266 /* prepend, so they get reversed */
1267 arg->next = call->out_args;
1268 call->out_args = arg;
1271 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1272 stack_addr->inst_basereg = IA64_SP;
1273 stack_addr->inst_offset = 16 + ainfo->offset;
1274 stack_addr->inst_imm = size;
1276 arg->opcode = OP_OUTARG_VT;
1277 arg->inst_right = stack_addr;
1281 switch (ainfo->storage) {
1283 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1286 case ArgInFloatRegR4:
1287 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1290 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1291 arg->opcode = OP_OUTARG_R4;
1294 arg->opcode = OP_OUTARG;
1295 arg->inst_imm = 16 + ainfo->offset;
1298 g_assert_not_reached ();
1304 /* Handle the case where there are no implicit arguments */
1305 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1306 emit_sig_cookie (cfg, call, cinfo);
1309 call->stack_usage = cinfo->stack_usage;
1310 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1311 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1312 cfg->flags |= MONO_CFG_HAS_CALLS;
1318 emit_sig_cookie2 (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1320 MonoMethodSignature *tmp_sig;
1322 /* Emit the signature cookie just before the implicit arguments */
1324 /* FIXME: Add support for signature tokens to AOT */
1325 cfg->disable_aot = TRUE;
1327 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1330 * mono_ArgIterator_Setup assumes the signature cookie is
1331 * passed first and all the arguments which were before it are
1332 * passed on the stack after the signature. So compensate by
1333 * passing a different signature.
1335 tmp_sig = mono_metadata_signature_dup (call->signature);
1336 tmp_sig->param_count -= call->signature->sentinelpos;
1337 tmp_sig->sentinelpos = 0;
1338 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1340 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1341 sig_arg->dreg = mono_alloc_ireg (cfg);
1342 sig_arg->inst_p0 = tmp_sig;
1343 MONO_ADD_INS (cfg->cbb, sig_arg);
1345 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + cinfo->sig_cookie.offset, sig_arg->dreg);
1349 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1352 MonoMethodSignature *sig;
1353 int i, n, stack_size;
1359 mono_ia64_alloc_stacked_registers (cfg);
1361 sig = call->signature;
1362 n = sig->param_count + sig->hasthis;
1364 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1366 if (cinfo->ret.storage == ArgAggregate) {
1371 * The valuetype is in registers after the call, need to be copied
1372 * to the stack. Save the address to a local here, so the call
1373 * instruction can access it.
1375 local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1376 local->flags |= MONO_INST_VOLATILE;
1377 cfg->arch.ret_var_addr_local = local;
1379 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1380 vtarg->sreg1 = call->vret_var->dreg;
1381 vtarg->dreg = local->dreg;
1382 MONO_ADD_INS (cfg->cbb, vtarg);
1385 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
1386 add_outarg_reg2 (cfg, call, ArgInIReg, cfg->arch.reg_out0 + cinfo->ret.reg, call->vret_var);
1389 for (i = 0; i < n; ++i) {
1392 ainfo = cinfo->args + i;
1394 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1395 /* Emit the signature cookie just before the implicit arguments */
1396 emit_sig_cookie2 (cfg, call, cinfo);
1399 in = call->args [i];
1401 if (sig->hasthis && (i == 0))
1402 arg_type = &mono_defaults.object_class->byval_arg;
1404 arg_type = sig->params [i - sig->hasthis];
1406 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1410 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1411 size = sizeof (MonoTypedRef);
1412 align = sizeof (gpointer);
1414 else if (sig->pinvoke)
1415 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1418 * Other backends use mono_type_stack_size (), but that
1419 * aligns the size to 8, which is larger than the size of
1420 * the source, leading to reads of invalid memory if the
1421 * source is at the end of address space.
1423 size = mono_class_value_size (in->klass, &align);
1429 MONO_INST_NEW (cfg, arg, OP_OUTARG_VT);
1430 arg->sreg1 = in->dreg;
1431 arg->klass = in->klass;
1432 arg->backend.size = size;
1433 arg->inst_p0 = call;
1434 arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1435 memcpy (arg->inst_p1, ainfo, sizeof (ArgInfo));
1437 MONO_ADD_INS (cfg->cbb, arg);
1441 switch (ainfo->storage) {
1443 add_outarg_reg2 (cfg, call, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1446 case ArgInFloatRegR4:
1447 add_outarg_reg2 (cfg, call, ainfo->storage, ainfo->reg, in);
1450 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref)
1451 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1452 else if (arg_type->type == MONO_TYPE_R8 && !arg_type->byref)
1453 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1455 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1458 g_assert_not_reached ();
1463 /* Handle the case where there are no implicit arguments */
1464 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1465 emit_sig_cookie2 (cfg, call, cinfo);
1468 call->stack_usage = cinfo->stack_usage;
1469 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1473 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1475 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1476 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1477 int size = ins->backend.size;
1479 if (ainfo->storage == ArgAggregate) {
1480 MonoInst *load, *store;
1484 * Part of the structure is passed in registers.
1486 for (i = 0; i < ainfo->nregs; ++i) {
1487 slot = ainfo->reg + i;
1489 if (ainfo->atype == AggregateSingleHFA) {
1490 MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
1491 load->inst_basereg = src->dreg;
1492 load->inst_offset = i * 4;
1493 load->dreg = mono_alloc_freg (cfg);
1495 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1496 } else if (ainfo->atype == AggregateDoubleHFA) {
1497 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1498 load->inst_basereg = src->dreg;
1499 load->inst_offset = i * 8;
1500 load->dreg = mono_alloc_freg (cfg);
1502 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1504 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1505 load->inst_basereg = src->dreg;
1506 load->inst_offset = i * 8;
1507 load->dreg = mono_alloc_ireg (cfg);
1509 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, cfg->arch.reg_out0 + ainfo->reg + i, FALSE);
1511 MONO_ADD_INS (cfg->cbb, load);
1515 * Part of the structure is passed on the stack.
1517 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1518 slot = ainfo->reg + i;
1520 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1521 load->inst_basereg = src->dreg;
1522 load->inst_offset = i * sizeof (gpointer);
1523 load->dreg = mono_alloc_preg (cfg);
1524 MONO_ADD_INS (cfg->cbb, load);
1526 MONO_INST_NEW (cfg, store, OP_STOREI8_MEMBASE_REG);
1527 store->sreg1 = load->dreg;
1528 store->inst_destbasereg = IA64_SP;
1529 store->inst_offset = 16 + ainfo->offset + (slot - 8) * 8;
1530 MONO_ADD_INS (cfg->cbb, store);
1533 mini_emit_memcpy2 (cfg, IA64_SP, 16 + ainfo->offset, src->dreg, 0, size, 4);
1538 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1540 CallInfo *cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
1542 switch (cinfo->ret.storage) {
1544 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1547 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1550 g_assert_not_reached ();
1555 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1560 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1562 MonoInst *ins, *n, *last_ins = NULL;
1565 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1566 switch (ins->opcode) {
1574 if (ins->dreg == ins->sreg1) {
1575 MONO_DELETE_INS (bb, ins);
1581 * OP_MOVE sreg, dreg
1582 * OP_MOVE dreg, sreg
1584 if (last_ins && last_ins->opcode == OP_MOVE &&
1585 ins->sreg1 == last_ins->dreg &&
1586 ins->dreg == last_ins->sreg1) {
1587 MONO_DELETE_INS (bb, ins);
1593 /* remove unnecessary multiplication with 1 */
1594 if (ins->inst_imm == 1) {
1595 if (ins->dreg != ins->sreg1) {
1596 ins->opcode = OP_MOVE;
1598 MONO_DELETE_INS (bb, ins);
1608 bb->last_ins = last_ins;
1611 int cond_to_ia64_cmp [][3] = {
1612 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1613 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1614 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1615 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1616 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1617 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1618 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1619 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1620 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1621 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1625 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1627 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1630 int cond_to_ia64_cmp_imm [][3] = {
1631 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1632 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1633 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1634 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1635 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1636 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1637 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1638 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1639 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1640 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1644 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1646 /* The condition needs to be reversed */
1647 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1650 #define NEW_INS(cfg,dest,op) do { \
1651 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1652 (dest)->opcode = (op); \
1653 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1654 last_ins = (dest); \
1658 * mono_arch_lowering_pass:
1660 * Converts complex opcodes into simpler ones so that each IR instruction
1661 * corresponds to one machine instruction.
1664 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1666 MonoInst *ins, *n, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1669 if (bb->max_vreg > cfg->rs->next_vreg)
1670 cfg->rs->next_vreg = bb->max_vreg;
1672 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1673 switch (ins->opcode) {
1674 case OP_STOREI1_MEMBASE_IMM:
1675 case OP_STOREI2_MEMBASE_IMM:
1676 case OP_STOREI4_MEMBASE_IMM:
1677 case OP_STOREI8_MEMBASE_IMM:
1678 case OP_STORE_MEMBASE_IMM:
1679 /* There are no store_membase instructions on ia64 */
1680 if (ins->inst_offset == 0) {
1682 } else if (ia64_is_imm14 (ins->inst_offset)) {
1683 NEW_INS (cfg, temp2, OP_ADD_IMM);
1684 temp2->sreg1 = ins->inst_destbasereg;
1685 temp2->inst_imm = ins->inst_offset;
1686 temp2->dreg = mono_regstate_next_int (cfg->rs);
1689 NEW_INS (cfg, temp, OP_I8CONST);
1690 temp->inst_c0 = ins->inst_offset;
1691 temp->dreg = mono_regstate_next_int (cfg->rs);
1693 NEW_INS (cfg, temp2, OP_LADD);
1694 temp2->sreg1 = ins->inst_destbasereg;
1695 temp2->sreg2 = temp->dreg;
1696 temp2->dreg = mono_regstate_next_int (cfg->rs);
1699 switch (ins->opcode) {
1700 case OP_STOREI1_MEMBASE_IMM:
1701 ins->opcode = OP_STOREI1_MEMBASE_REG;
1703 case OP_STOREI2_MEMBASE_IMM:
1704 ins->opcode = OP_STOREI2_MEMBASE_REG;
1706 case OP_STOREI4_MEMBASE_IMM:
1707 ins->opcode = OP_STOREI4_MEMBASE_REG;
1709 case OP_STOREI8_MEMBASE_IMM:
1710 case OP_STORE_MEMBASE_IMM:
1711 ins->opcode = OP_STOREI8_MEMBASE_REG;
1714 g_assert_not_reached ();
1717 if (ins->inst_imm == 0)
1718 ins->sreg1 = IA64_R0;
1720 NEW_INS (cfg, temp3, OP_I8CONST);
1721 temp3->inst_c0 = ins->inst_imm;
1722 temp3->dreg = mono_regstate_next_int (cfg->rs);
1723 ins->sreg1 = temp3->dreg;
1726 ins->inst_offset = 0;
1728 ins->inst_destbasereg = temp2->dreg;
1730 case OP_STOREI1_MEMBASE_REG:
1731 case OP_STOREI2_MEMBASE_REG:
1732 case OP_STOREI4_MEMBASE_REG:
1733 case OP_STOREI8_MEMBASE_REG:
1734 case OP_STORER4_MEMBASE_REG:
1735 case OP_STORER8_MEMBASE_REG:
1736 case OP_STORE_MEMBASE_REG:
1737 /* There are no store_membase instructions on ia64 */
1738 if (ins->inst_offset == 0) {
1741 else if (ia64_is_imm14 (ins->inst_offset)) {
1742 NEW_INS (cfg, temp2, OP_ADD_IMM);
1743 temp2->sreg1 = ins->inst_destbasereg;
1744 temp2->inst_imm = ins->inst_offset;
1745 temp2->dreg = mono_regstate_next_int (cfg->rs);
1748 NEW_INS (cfg, temp, OP_I8CONST);
1749 temp->inst_c0 = ins->inst_offset;
1750 temp->dreg = mono_regstate_next_int (cfg->rs);
1751 NEW_INS (cfg, temp2, OP_LADD);
1752 temp2->sreg1 = ins->inst_destbasereg;
1753 temp2->sreg2 = temp->dreg;
1754 temp2->dreg = mono_regstate_next_int (cfg->rs);
1757 ins->inst_offset = 0;
1758 ins->inst_destbasereg = temp2->dreg;
1760 case OP_LOADI1_MEMBASE:
1761 case OP_LOADU1_MEMBASE:
1762 case OP_LOADI2_MEMBASE:
1763 case OP_LOADU2_MEMBASE:
1764 case OP_LOADI4_MEMBASE:
1765 case OP_LOADU4_MEMBASE:
1766 case OP_LOADI8_MEMBASE:
1767 case OP_LOAD_MEMBASE:
1768 case OP_LOADR4_MEMBASE:
1769 case OP_LOADR8_MEMBASE:
1770 case OP_ATOMIC_EXCHANGE_I4:
1771 case OP_ATOMIC_EXCHANGE_I8:
1772 case OP_ATOMIC_ADD_NEW_I4:
1773 case OP_ATOMIC_ADD_NEW_I8:
1774 case OP_ATOMIC_ADD_IMM_NEW_I4:
1775 case OP_ATOMIC_ADD_IMM_NEW_I8:
1776 /* There are no membase instructions on ia64 */
1777 if (ins->inst_offset == 0) {
1780 else if (ia64_is_imm14 (ins->inst_offset)) {
1781 NEW_INS (cfg, temp2, OP_ADD_IMM);
1782 temp2->sreg1 = ins->inst_basereg;
1783 temp2->inst_imm = ins->inst_offset;
1784 temp2->dreg = mono_regstate_next_int (cfg->rs);
1787 NEW_INS (cfg, temp, OP_I8CONST);
1788 temp->inst_c0 = ins->inst_offset;
1789 temp->dreg = mono_regstate_next_int (cfg->rs);
1790 NEW_INS (cfg, temp2, OP_LADD);
1791 temp2->sreg1 = ins->inst_basereg;
1792 temp2->sreg2 = temp->dreg;
1793 temp2->dreg = mono_regstate_next_int (cfg->rs);
1796 ins->inst_offset = 0;
1797 ins->inst_basereg = temp2->dreg;
1817 case OP_ISHR_UN_IMM:
1818 case OP_LSHR_UN_IMM: {
1819 gboolean is_imm = FALSE;
1820 gboolean switched = FALSE;
1822 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1823 ins->opcode = OP_ZEXT_I1;
1827 switch (ins->opcode) {
1831 is_imm = ia64_is_imm14 (ins->inst_imm);
1836 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1838 /* A = B - IMM -> A = B + (-IMM) */
1839 ins->inst_imm = - ins->inst_imm;
1840 ins->opcode = OP_IADD_IMM;
1851 is_imm = ia64_is_imm8 (ins->inst_imm);
1860 case OP_ISHR_UN_IMM:
1861 case OP_LSHR_UN_IMM:
1862 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1870 ins->sreg2 = ins->sreg1;
1874 ins->opcode = mono_op_imm_to_op (ins->opcode);
1876 if (ins->inst_imm == 0)
1877 ins->sreg2 = IA64_R0;
1879 NEW_INS (cfg, temp, OP_I8CONST);
1880 temp->inst_c0 = ins->inst_imm;
1881 temp->dreg = mono_regstate_next_int (cfg->rs);
1882 ins->sreg2 = temp->dreg;
1886 case OP_COMPARE_IMM:
1887 case OP_ICOMPARE_IMM:
1888 case OP_LCOMPARE_IMM: {
1889 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1895 /* Branch opts can eliminate the branch */
1896 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1897 ins->opcode = OP_NOP;
1902 * The compare_imm instructions have switched up arguments, and
1903 * some of them take an imm between -127 and 128.
1906 cond = mono_opcode_to_cond (next->opcode);
1907 if ((cond == CMP_LT) || (cond == CMP_GE))
1908 imm = ia64_is_imm8 (ins->inst_imm - 1);
1909 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1910 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1912 imm = ia64_is_imm8 (ins->inst_imm);
1915 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1916 ins->sreg2 = ins->sreg1;
1919 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1921 if (ins->inst_imm == 0)
1922 ins->sreg2 = IA64_R0;
1924 NEW_INS (cfg, temp, OP_I8CONST);
1925 temp->inst_c0 = ins->inst_imm;
1926 temp->dreg = mono_regstate_next_int (cfg->rs);
1927 ins->sreg2 = temp->dreg;
1931 if (MONO_IS_COND_BRANCH_OP (next)) {
1932 next->opcode = OP_IA64_BR_COND;
1933 if (! (next->flags & MONO_INST_BRLABEL))
1934 next->inst_target_bb = next->inst_true_bb;
1935 } else if (MONO_IS_COND_EXC (next)) {
1936 next->opcode = OP_IA64_COND_EXC;
1937 } else if (MONO_IS_SETCC (next)) {
1938 next->opcode = OP_IA64_CSET;
1940 printf ("%s\n", mono_inst_name (next->opcode));
1950 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1954 /* Branch opts can eliminate the branch */
1955 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1956 ins->opcode = OP_NOP;
1960 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1962 if (MONO_IS_COND_BRANCH_OP (next)) {
1963 next->opcode = OP_IA64_BR_COND;
1964 if (! (next->flags & MONO_INST_BRLABEL))
1965 next->inst_target_bb = next->inst_true_bb;
1966 } else if (MONO_IS_COND_EXC (next)) {
1967 next->opcode = OP_IA64_COND_EXC;
1968 } else if (MONO_IS_SETCC (next)) {
1969 next->opcode = OP_IA64_CSET;
1971 printf ("%s\n", mono_inst_name (next->opcode));
1982 /* The front end removes the fcompare, so introduce it again */
1983 NEW_INS (cfg, temp, opcode_to_ia64_cmp (ins->opcode, OP_FCOMPARE));
1984 temp->sreg1 = ins->sreg1;
1985 temp->sreg2 = ins->sreg2;
1987 ins->opcode = OP_IA64_CSET;
1993 gboolean found = FALSE;
1994 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1996 /* First the easy cases */
1997 if (ins->inst_imm == 1) {
1998 ins->opcode = OP_MOVE;
2001 for (i = 1; i < 64; ++i)
2002 if (ins->inst_imm == (((gint64)1) << i)) {
2003 ins->opcode = shl_op;
2009 /* This could be optimized */
2012 for (i = 0; i < 64; ++i) {
2013 if (ins->inst_imm & (((gint64)1) << i)) {
2014 NEW_INS (cfg, temp, shl_op);
2015 temp->dreg = mono_regstate_next_int (cfg->rs);
2016 temp->sreg1 = ins->sreg1;
2020 sum_reg = temp->dreg;
2022 NEW_INS (cfg, temp2, OP_LADD);
2023 temp2->dreg = mono_regstate_next_int (cfg->rs);
2024 temp2->sreg1 = sum_reg;
2025 temp2->sreg2 = temp->dreg;
2026 sum_reg = temp2->dreg;
2030 ins->opcode = OP_MOVE;
2031 ins->sreg1 = sum_reg;
2035 case OP_LCONV_TO_OVF_U4:
2036 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
2037 temp->sreg1 = ins->sreg1;
2038 temp->sreg2 = IA64_R0;
2040 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
2041 temp->inst_p1 = (char*)"OverflowException";
2043 ins->opcode = OP_MOVE;
2045 case OP_LCONV_TO_OVF_I4_UN:
2046 NEW_INS (cfg, temp, OP_ICONST);
2047 temp->inst_c0 = 0x7fffffff;
2048 temp->dreg = mono_regstate_next_int (cfg->rs);
2050 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
2051 temp2->sreg1 = ins->sreg1;
2052 temp2->sreg2 = temp->dreg;
2054 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
2055 temp->inst_p1 = (char*)"OverflowException";
2057 ins->opcode = OP_MOVE;
2059 case OP_FCONV_TO_I4:
2060 case OP_FCONV_TO_I2:
2061 case OP_FCONV_TO_U2:
2062 case OP_FCONV_TO_I1:
2063 case OP_FCONV_TO_U1:
2064 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
2065 temp->sreg1 = ins->sreg1;
2066 temp->dreg = ins->dreg;
2068 switch (ins->opcode) {
2069 case OP_FCONV_TO_I4:
2070 ins->opcode = OP_SEXT_I4;
2072 case OP_FCONV_TO_I2:
2073 ins->opcode = OP_SEXT_I2;
2075 case OP_FCONV_TO_U2:
2076 ins->opcode = OP_ZEXT_I4;
2078 case OP_FCONV_TO_I1:
2079 ins->opcode = OP_SEXT_I1;
2081 case OP_FCONV_TO_U1:
2082 ins->opcode = OP_ZEXT_I1;
2085 g_assert_not_reached ();
2087 ins->sreg1 = ins->dreg;
2095 bb->last_ins = last_ins;
2097 bb->max_vreg = cfg->rs->next_vreg;
2101 * emit_load_volatile_arguments:
2103 * Load volatile arguments from the stack to the original input registers.
2104 * Required before a tail call.
2106 static Ia64CodegenState
2107 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
2109 MonoMethod *method = cfg->method;
2110 MonoMethodSignature *sig;
2115 /* FIXME: Generate intermediate code instead */
2117 sig = mono_method_signature (method);
2119 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
2121 /* This is the opposite of the code in emit_prolog */
2122 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2123 ArgInfo *ainfo = cinfo->args + i;
2124 gint32 stack_offset;
2127 ins = cfg->args [i];
2129 if (sig->hasthis && (i == 0))
2130 arg_type = &mono_defaults.object_class->byval_arg;
2132 arg_type = sig->params [i - sig->hasthis];
2134 arg_type = mono_type_get_underlying_type (arg_type);
2136 stack_offset = ainfo->offset + ARGS_OFFSET;
2138 /* Save volatile arguments to the stack */
2139 if (ins->opcode != OP_REGVAR) {
2140 switch (ainfo->storage) {
2143 /* FIXME: big offsets */
2144 g_assert (ins->opcode == OP_REGOFFSET);
2145 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2146 if (arg_type->byref)
2147 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2149 switch (arg_type->type) {
2151 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
2154 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
2157 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2169 if (ins->opcode == OP_REGVAR) {
2170 /* Argument allocated to (non-volatile) register */
2171 switch (ainfo->storage) {
2173 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
2174 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
2177 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
2178 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2189 static Ia64CodegenState
2190 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2195 /* Move return value to the target register */
2196 switch (ins->opcode) {
2198 case OP_VOIDCALL_REG:
2199 case OP_VOIDCALL_MEMBASE:
2203 case OP_CALL_MEMBASE:
2206 case OP_LCALL_MEMBASE:
2207 g_assert (ins->dreg == IA64_R8);
2211 case OP_FCALL_MEMBASE:
2212 g_assert (ins->dreg == 8);
2216 case OP_VCALL_MEMBASE:
2219 case OP_VCALL2_MEMBASE: {
2222 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
2223 storage = cinfo->ret.storage;
2225 if (storage == ArgAggregate) {
2226 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2228 /* Load address of stack space allocated for the return value */
2229 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2230 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2231 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2233 for (i = 0; i < cinfo->ret.nregs; ++i) {
2234 switch (cinfo->ret.atype) {
2235 case AggregateNormal:
2236 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2238 case AggregateSingleHFA:
2239 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2241 case AggregateDoubleHFA:
2242 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2245 g_assert_not_reached ();
2252 g_assert_not_reached ();
2258 #define add_patch_info(cfg,code,patch_type,data) do { \
2259 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2262 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2263 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2265 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2267 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2268 ia64_br_cond_pred (code, (predicate), 0); \
2271 static Ia64CodegenState
2272 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2274 add_patch_info (cfg, code, patch_type, data);
2276 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2278 /* mono_arch_patch_callsite will patch this */
2279 /* mono_arch_nullify_class_init_trampoline will patch this */
2280 ia64_movl (code, GP_SCRATCH_REG, 0);
2281 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2282 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2283 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2284 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2287 /* Can't use a direct call since the displacement might be too small */
2288 /* mono_arch_patch_callsite will patch this */
2289 ia64_movl (code, GP_SCRATCH_REG, 0);
2290 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2291 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2297 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2300 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2305 Ia64CodegenState code;
2306 guint8 *code_start = cfg->native_code + cfg->code_len;
2307 MonoInst *last_ins = NULL;
2308 guint last_offset = 0;
2311 if (cfg->opt & MONO_OPT_LOOP) {
2315 if (cfg->verbose_level > 2)
2316 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2318 cpos = bb->max_offset;
2320 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2324 offset = code_start - cfg->native_code;
2326 ia64_codegen_init (code, code_start);
2329 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2333 MONO_BB_FOR_EACH_INS (bb, ins) {
2334 offset = code.buf - cfg->native_code;
2336 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2338 while (offset + max_len + 16 > cfg->code_size) {
2339 ia64_codegen_close (code);
2341 offset = code.buf - cfg->native_code;
2343 cfg->code_size *= 2;
2344 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2345 code_start = cfg->native_code + offset;
2346 mono_jit_stats.code_reallocs++;
2348 ia64_codegen_init (code, code_start);
2351 mono_debug_record_line_number (cfg, ins, offset);
2353 switch (ins->opcode) {
2356 if (ia64_is_imm14 (ins->inst_c0))
2357 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2359 ia64_movl (code, ins->dreg, ins->inst_c0);
2362 add_patch_info (cfg, code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2363 ia64_movl (code, ins->dreg, 0);
2366 ia64_mov (code, ins->dreg, ins->sreg1);
2369 case OP_IA64_BR_COND: {
2371 if (ins->opcode == OP_IA64_BR_COND)
2373 if (ins->flags & MONO_INST_BRLABEL) {
2374 if (ins->inst_i0->inst_c0) {
2377 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2378 ia64_br_cond_pred (code, pred, 0);
2381 if (ins->inst_target_bb->native_offset) {
2382 guint8 *pos = code.buf + code.nins;
2384 ia64_br_cond_pred (code, pred, 0);
2385 ia64_begin_bundle (code);
2386 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2388 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2389 ia64_br_cond_pred (code, pred, 0);
2395 ia64_begin_bundle (code);
2396 ins->inst_c0 = code.buf - cfg->native_code;
2399 case OP_RELAXED_NOP:
2401 case OP_DUMMY_STORE:
2402 case OP_NOT_REACHED:
2406 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2407 ia64_br_cond_reg (code, IA64_B6);
2411 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2415 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2419 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2423 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2427 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2431 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2435 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2439 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2443 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2446 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2447 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2450 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2453 /* p6 and p7 is set if there is signed/unsigned overflow */
2455 /* Set p8-p9 == (sreg2 > 0) */
2456 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2458 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2460 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2461 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2462 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2463 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2465 /* res <u sreg1 => unsigned overflow */
2466 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2468 /* FIXME: Predicate this since this is a side effect */
2469 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2472 /* p6 and p7 is set if there is signed/unsigned overflow */
2474 /* Set p8-p9 == (sreg2 > 0) */
2475 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2477 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2479 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2480 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2481 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2482 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2484 /* sreg1 <u sreg2 => unsigned overflow */
2485 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2487 /* FIXME: Predicate this since this is a side effect */
2488 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2491 /* Same as OP_IADDCC */
2492 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2494 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2496 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2497 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2499 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2501 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2504 /* Same as OP_ISUBCC */
2506 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2508 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2510 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2511 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2513 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2515 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2520 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2525 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2529 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2533 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2538 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2543 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2545 case OP_ISHR_UN_IMM:
2546 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2547 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2549 case OP_LSHR_UN_IMM:
2550 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2553 /* Based on gcc code */
2554 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2555 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2556 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2557 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2560 case OP_STOREI1_MEMBASE_REG:
2561 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2563 case OP_STOREI2_MEMBASE_REG:
2564 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2566 case OP_STOREI4_MEMBASE_REG:
2567 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2569 case OP_STOREI8_MEMBASE_REG:
2570 case OP_STORE_MEMBASE_REG:
2571 if (ins->inst_offset != 0) {
2572 /* This is generated by local regalloc */
2573 if (ia64_is_imm14 (ins->inst_offset)) {
2574 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2576 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2577 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2579 ins->inst_destbasereg = GP_SCRATCH_REG;
2581 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2584 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2585 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2587 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2588 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2590 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2591 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2593 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2594 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2597 case OP_LOADU1_MEMBASE:
2598 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2600 case OP_LOADU2_MEMBASE:
2601 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2603 case OP_LOADU4_MEMBASE:
2604 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2606 case OP_LOADI1_MEMBASE:
2607 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2608 ia64_sxt1 (code, ins->dreg, ins->dreg);
2610 case OP_LOADI2_MEMBASE:
2611 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2612 ia64_sxt2 (code, ins->dreg, ins->dreg);
2614 case OP_LOADI4_MEMBASE:
2615 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2616 ia64_sxt4 (code, ins->dreg, ins->dreg);
2618 case OP_LOAD_MEMBASE:
2619 case OP_LOADI8_MEMBASE:
2620 if (ins->inst_offset != 0) {
2621 /* This is generated by local regalloc */
2622 if (ia64_is_imm14 (ins->inst_offset)) {
2623 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2625 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2626 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2628 ins->inst_basereg = GP_SCRATCH_REG;
2630 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2633 case OP_IA64_LOADU1_MEMBASE_INC:
2634 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2636 case OP_IA64_LOADU2_MEMBASE_INC:
2637 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2639 case OP_IA64_LOADU4_MEMBASE_INC:
2640 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2642 case OP_IA64_LOADI8_MEMBASE_INC:
2643 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2647 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2650 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2653 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2656 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2659 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2662 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2665 /* Compare opcodes */
2666 case OP_IA64_CMP4_EQ:
2667 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2669 case OP_IA64_CMP4_NE:
2670 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2672 case OP_IA64_CMP4_LE:
2673 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2675 case OP_IA64_CMP4_LT:
2676 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2678 case OP_IA64_CMP4_GE:
2679 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2681 case OP_IA64_CMP4_GT:
2682 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2684 case OP_IA64_CMP4_LT_UN:
2685 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2687 case OP_IA64_CMP4_LE_UN:
2688 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2690 case OP_IA64_CMP4_GT_UN:
2691 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2693 case OP_IA64_CMP4_GE_UN:
2694 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2696 case OP_IA64_CMP_EQ:
2697 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2699 case OP_IA64_CMP_NE:
2700 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2702 case OP_IA64_CMP_LE:
2703 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2705 case OP_IA64_CMP_LT:
2706 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2708 case OP_IA64_CMP_GE:
2709 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2711 case OP_IA64_CMP_GT:
2712 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2714 case OP_IA64_CMP_GT_UN:
2715 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2717 case OP_IA64_CMP_LT_UN:
2718 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2720 case OP_IA64_CMP_GE_UN:
2721 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2723 case OP_IA64_CMP_LE_UN:
2724 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2726 case OP_IA64_CMP4_EQ_IMM:
2727 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2729 case OP_IA64_CMP4_NE_IMM:
2730 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2732 case OP_IA64_CMP4_LE_IMM:
2733 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2735 case OP_IA64_CMP4_LT_IMM:
2736 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2738 case OP_IA64_CMP4_GE_IMM:
2739 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2741 case OP_IA64_CMP4_GT_IMM:
2742 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2744 case OP_IA64_CMP4_LT_UN_IMM:
2745 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2747 case OP_IA64_CMP4_LE_UN_IMM:
2748 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2750 case OP_IA64_CMP4_GT_UN_IMM:
2751 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2753 case OP_IA64_CMP4_GE_UN_IMM:
2754 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2756 case OP_IA64_CMP_EQ_IMM:
2757 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2759 case OP_IA64_CMP_NE_IMM:
2760 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2762 case OP_IA64_CMP_LE_IMM:
2763 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2765 case OP_IA64_CMP_LT_IMM:
2766 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2768 case OP_IA64_CMP_GE_IMM:
2769 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2771 case OP_IA64_CMP_GT_IMM:
2772 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2774 case OP_IA64_CMP_GT_UN_IMM:
2775 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2777 case OP_IA64_CMP_LT_UN_IMM:
2778 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2780 case OP_IA64_CMP_GE_UN_IMM:
2781 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2783 case OP_IA64_CMP_LE_UN_IMM:
2784 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2786 case OP_IA64_FCMP_EQ:
2787 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2789 case OP_IA64_FCMP_NE:
2790 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2792 case OP_IA64_FCMP_LT:
2793 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2795 case OP_IA64_FCMP_GT:
2796 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2798 case OP_IA64_FCMP_LE:
2799 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2801 case OP_IA64_FCMP_GE:
2802 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2804 case OP_IA64_FCMP_GT_UN:
2805 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2806 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2808 case OP_IA64_FCMP_LT_UN:
2809 ia64_fcmp_lt_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_GE_UN:
2813 ia64_fcmp_ge_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_LE_UN:
2817 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2818 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2821 case OP_COND_EXC_IOV:
2822 case OP_COND_EXC_OV:
2823 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2825 case OP_COND_EXC_IC:
2827 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2829 case OP_IA64_COND_EXC:
2830 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2833 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2834 ia64_no_stop (code);
2835 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2837 case OP_ICONV_TO_I1:
2838 case OP_LCONV_TO_I1:
2839 /* FIXME: Is this needed ? */
2840 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2842 case OP_ICONV_TO_I2:
2843 case OP_LCONV_TO_I2:
2844 /* FIXME: Is this needed ? */
2845 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2847 case OP_LCONV_TO_I4:
2848 /* FIXME: Is this needed ? */
2849 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2851 case OP_ICONV_TO_U1:
2852 case OP_LCONV_TO_U1:
2853 /* FIXME: Is this needed */
2854 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2856 case OP_ICONV_TO_U2:
2857 case OP_LCONV_TO_U2:
2858 /* FIXME: Is this needed */
2859 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2861 case OP_LCONV_TO_U4:
2862 /* FIXME: Is this needed */
2863 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2865 case OP_ICONV_TO_I8:
2867 case OP_LCONV_TO_I8:
2869 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2871 case OP_LCONV_TO_U8:
2873 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2880 double d = *(double *)ins->inst_p0;
2882 if ((d == 0.0) && (mono_signbit (d) == 0))
2883 ia64_fmov (code, ins->dreg, 0);
2885 ia64_fmov (code, ins->dreg, 1);
2887 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2888 ia64_movl (code, GP_SCRATCH_REG, 0);
2889 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2894 float f = *(float *)ins->inst_p0;
2896 if ((f == 0.0) && (mono_signbit (f) == 0))
2897 ia64_fmov (code, ins->dreg, 0);
2899 ia64_fmov (code, ins->dreg, 1);
2901 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2902 ia64_movl (code, GP_SCRATCH_REG, 0);
2903 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2908 ia64_fmov (code, ins->dreg, ins->sreg1);
2910 case OP_STORER8_MEMBASE_REG:
2911 if (ins->inst_offset != 0) {
2912 /* This is generated by local regalloc */
2913 if (ia64_is_imm14 (ins->inst_offset)) {
2914 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2916 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2917 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2919 ins->inst_destbasereg = GP_SCRATCH_REG;
2921 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2923 case OP_STORER4_MEMBASE_REG:
2924 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2925 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2927 case OP_LOADR8_MEMBASE:
2928 if (ins->inst_offset != 0) {
2929 /* This is generated by local regalloc */
2930 if (ia64_is_imm14 (ins->inst_offset)) {
2931 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2933 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2934 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2936 ins->inst_basereg = GP_SCRATCH_REG;
2938 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2940 case OP_LOADR4_MEMBASE:
2941 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2942 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2944 case OP_ICONV_TO_R4:
2945 case OP_LCONV_TO_R4:
2946 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2947 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2948 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2950 case OP_ICONV_TO_R8:
2951 case OP_LCONV_TO_R8:
2952 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2953 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2954 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2956 case OP_FCONV_TO_R4:
2957 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2959 case OP_FCONV_TO_I8:
2961 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2962 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2965 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2968 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2971 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2974 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2978 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2979 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2981 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2982 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2983 /* Positive infinity */
2984 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2985 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2986 /* Negative infinity */
2987 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2988 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2993 /* ensure ins->sreg1 is not NULL */
2994 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2997 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2998 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
3006 call = (MonoCallInst*)ins;
3008 if (ins->flags & MONO_INST_HAS_METHOD)
3009 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
3011 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
3013 code = emit_move_return_value (cfg, ins, code);
3021 case OP_VOIDCALL_REG: {
3022 MonoCallInst *call = (MonoCallInst*)ins;
3027 * mono_arch_find_this_arg () needs to find the this argument in a global
3030 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
3031 out_reg = cfg->arch.reg_out0;
3032 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
3034 ia64_mov (code, IA64_R10, out_reg);
3037 ia64_mov (code, IA64_R8, ins->sreg1);
3038 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
3039 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3040 ia64_ld8 (code, IA64_GP, IA64_R8);
3041 ia64_br_call_reg (code, IA64_B0, IA64_B6);
3043 code = emit_move_return_value (cfg, ins, code);
3046 case OP_FCALL_MEMBASE:
3047 case OP_LCALL_MEMBASE:
3048 case OP_VCALL_MEMBASE:
3049 case OP_VCALL2_MEMBASE:
3050 case OP_VOIDCALL_MEMBASE:
3051 case OP_CALL_MEMBASE: {
3052 MonoCallInst *call = (MonoCallInst*)ins;
3057 * There are no membase instructions on ia64, but we can't
3058 * lower this since get_vcall_slot_addr () needs to decode it.
3061 /* Keep this in synch with get_vcall_slot_addr */
3062 ia64_mov (code, IA64_R11, ins->sreg1);
3063 if (ia64_is_imm14 (ins->inst_offset))
3064 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
3066 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
3067 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
3070 if (call->method && ins->inst_offset < 0) {
3072 * This is a possible IMT call so save the IMT method in a global
3073 * register where mono_arch_find_imt_method () and its friends can
3076 ia64_movl (code, IA64_R9, call->method);
3080 * mono_arch_find_this_arg () needs to find the this argument in a global
3083 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
3084 out_reg = cfg->arch.reg_out0;
3085 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
3087 ia64_mov (code, IA64_R10, out_reg);
3089 ia64_begin_bundle (code);
3090 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3092 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
3094 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3097 * This nop will tell get_vcall_slot_addr that this is a virtual
3100 ia64_nop_i (code, 0x12345);
3102 ia64_br_call_reg (code, IA64_B0, IA64_B6);
3104 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3106 code = emit_move_return_value (cfg, ins, code);
3111 * Keep in sync with the code in emit_epilog.
3114 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3117 g_assert (!cfg->method->save_lmf);
3119 /* Load arguments into their original registers */
3120 code = emit_load_volatile_arguments (cfg, code);
3122 if (cfg->arch.stack_alloc_size) {
3123 if (cfg->arch.omit_fp) {
3124 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
3125 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
3127 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
3128 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3132 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
3134 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3135 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3137 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3138 ia64_movl (code, GP_SCRATCH_REG, 0);
3139 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3140 ia64_br_cond_reg (code, IA64_B6);
3145 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
3151 /* FIXME: Sigaltstack support */
3153 /* keep alignment */
3154 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
3155 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
3156 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3158 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3160 ia64_mov (code, ins->dreg, IA64_SP);
3162 /* An area at sp is reserved by the ABI for parameter passing */
3163 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
3164 if (ia64_is_adds_imm (abi_offset))
3165 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3167 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3168 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3171 if (ins->flags & MONO_INST_INIT) {
3173 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3175 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3178 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3179 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3180 ia64_br_cond_pred (code, 8, -2);
3182 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3184 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3189 case OP_LOCALLOC_IMM: {
3192 /* FIXME: Sigaltstack support */
3194 gssize size = ins->inst_imm;
3195 size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
3197 if (ia64_is_adds_imm (size))
3198 ia64_adds_imm (code, GP_SCRATCH_REG, size, IA64_R0);
3200 ia64_movl (code, GP_SCRATCH_REG, size);
3202 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3203 ia64_mov (code, ins->dreg, IA64_SP);
3205 /* An area at sp is reserved by the ABI for parameter passing */
3206 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
3207 if (ia64_is_adds_imm (abi_offset))
3208 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3210 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3211 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3214 if (ins->flags & MONO_INST_INIT) {
3216 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3218 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3221 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3222 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3223 ia64_br_cond_pred (code, 8, -2);
3225 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3227 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3233 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
3234 ia64_ld8 (code, ins->dreg, ins->dreg);
3237 /* Synchronization */
3238 case OP_MEMORY_BARRIER:
3241 case OP_ATOMIC_ADD_IMM_NEW_I4:
3242 g_assert (ins->inst_offset == 0);
3243 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3244 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3246 case OP_ATOMIC_ADD_IMM_NEW_I8:
3247 g_assert (ins->inst_offset == 0);
3248 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3249 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3251 case OP_ATOMIC_EXCHANGE_I4:
3252 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3253 ia64_sxt4 (code, ins->dreg, ins->dreg);
3255 case OP_ATOMIC_EXCHANGE_I8:
3256 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3258 case OP_ATOMIC_ADD_NEW_I4: {
3259 guint8 *label, *buf;
3261 /* From libatomic_ops */
3264 ia64_begin_bundle (code);
3265 label = code.buf + code.nins;
3266 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
3267 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3268 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3269 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3270 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3271 buf = code.buf + code.nins;
3272 ia64_br_cond_pred (code, 7, 0);
3273 ia64_begin_bundle (code);
3274 ia64_patch (buf, label);
3275 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3278 case OP_ATOMIC_ADD_NEW_I8: {
3279 guint8 *label, *buf;
3281 /* From libatomic_ops */
3284 ia64_begin_bundle (code);
3285 label = code.buf + code.nins;
3286 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
3287 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3288 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3289 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3290 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3291 buf = code.buf + code.nins;
3292 ia64_br_cond_pred (code, 7, 0);
3293 ia64_begin_bundle (code);
3294 ia64_patch (buf, label);
3295 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3299 /* Exception handling */
3300 case OP_CALL_HANDLER:
3302 * Using a call instruction would mess up the register stack, so
3303 * save the return address to a register and use a
3306 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3307 ia64_mov (code, IA64_R15, IA64_R0);
3308 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3309 /* Add the length of OP_CALL_HANDLER */
3310 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3311 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3312 ia64_movl (code, GP_SCRATCH_REG2, 0);
3313 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3314 ia64_br_cond_reg (code, IA64_B6);
3315 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3317 case OP_START_HANDLER: {
3319 * We receive the return address in GP_SCRATCH_REG.
3321 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3324 * R15 determines our caller. It is used since it is writable using
3326 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3327 * R15 != 0 means we are called by call_filter ().
3329 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3330 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3332 ia64_br_cond_pred (code, 6, 6);
3335 * Called by call_filter:
3336 * Allocate a new stack frame, and set the fp register from the
3337 * value passed in by the caller.
3338 * We allocate a similar frame as is done by the prolog, so
3339 * if an exception is thrown while executing the filter, the
3340 * unwinder can unwind through the filter frame using the unwind
3341 * info for the prolog.
3343 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);
3344 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3345 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3346 ia64_mov (code, cfg->frame_reg, IA64_R15);
3347 /* Signal to endfilter that we are called by call_filter */
3348 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3350 /* Branch target: */
3351 if (ia64_is_imm14 (spvar->inst_offset))
3352 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3354 ia64_movl (code, GP_SCRATCH_REG2, spvar->inst_offset);
3355 ia64_add (code, GP_SCRATCH_REG2, cfg->frame_reg, GP_SCRATCH_REG2);
3358 /* Save the return address */
3359 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3360 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3365 case OP_ENDFILTER: {
3366 /* FIXME: Return the value in ENDFILTER */
3367 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3369 /* Load the return address */
3370 if (ia64_is_imm14 (spvar->inst_offset)) {
3371 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3373 ia64_movl (code, GP_SCRATCH_REG, spvar->inst_offset);
3374 ia64_add (code, GP_SCRATCH_REG, cfg->frame_reg, GP_SCRATCH_REG);
3376 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3379 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3380 ia64_br_cond_pred (code, 7, 4);
3382 /* Called by call_filter */
3384 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3385 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3386 ia64_br_ret_reg (code, IA64_B0);
3388 /* Called by CALL_HANDLER */
3389 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3390 ia64_br_cond_reg (code, IA64_B6);
3394 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3395 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3396 (gpointer)"mono_arch_throw_exception");
3399 * This might be the last instruction in the method, so add a dummy
3400 * instruction so the unwinder will work.
3402 ia64_break_i (code, 0);
3405 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3406 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3407 (gpointer)"mono_arch_rethrow_exception");
3409 ia64_break_i (code, 0);
3413 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3414 g_assert_not_reached ();
3417 if ((code.buf - cfg->native_code - offset) > max_len) {
3418 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3419 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3420 g_assert_not_reached ();
3426 last_offset = offset;
3429 ia64_codegen_close (code);
3431 cfg->code_len = code.buf - cfg->native_code;
3435 mono_arch_register_lowlevel_calls (void)
3439 static Ia64InsType ins_types_in_template [32][3] = {
3440 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3441 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3442 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3443 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3444 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3445 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3448 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3449 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3450 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3451 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3452 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3453 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3454 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3455 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3456 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3457 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3458 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3459 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3462 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3463 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3464 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3465 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3468 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3469 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3474 static gboolean stops_in_template [32][3] = {
3475 { FALSE, FALSE, FALSE },
3476 { FALSE, FALSE, TRUE },
3477 { FALSE, TRUE, FALSE },
3478 { FALSE, TRUE, TRUE },
3479 { FALSE, FALSE, FALSE },
3480 { FALSE, FALSE, TRUE },
3481 { FALSE, FALSE, FALSE },
3482 { FALSE, FALSE, FALSE },
3484 { FALSE, FALSE, FALSE },
3485 { FALSE, FALSE, TRUE },
3486 { TRUE, FALSE, FALSE },
3487 { TRUE, FALSE, TRUE },
3488 { FALSE, FALSE, FALSE },
3489 { FALSE, FALSE, TRUE },
3490 { FALSE, FALSE, FALSE },
3491 { FALSE, FALSE, TRUE },
3493 { FALSE, FALSE, FALSE },
3494 { FALSE, FALSE, TRUE },
3495 { FALSE, FALSE, FALSE },
3496 { FALSE, FALSE, TRUE },
3497 { FALSE, FALSE, FALSE },
3498 { FALSE, FALSE, FALSE },
3499 { FALSE, FALSE, FALSE },
3500 { FALSE, FALSE, TRUE },
3502 { FALSE, FALSE, FALSE },
3503 { FALSE, FALSE, TRUE },
3504 { FALSE, FALSE, FALSE },
3505 { FALSE, FALSE, FALSE },
3506 { FALSE, FALSE, FALSE },
3507 { FALSE, FALSE, TRUE },
3508 { FALSE, FALSE, FALSE },
3509 { FALSE, FALSE, FALSE }
3512 static int last_stop_in_template [32] = {
3513 -1, 2, 1, 2, -1, 2, -1, -1,
3514 -1, 2, 0, 2, -1, 2, -1, 2,
3515 -1, 2, -1, 2, -1, -1, -1, 2,
3516 -1, 2, -1, -1, -1, 2, -1, -1
3519 static guint64 nops_for_ins_types [6] = {
3528 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3535 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3537 #define DEBUG_INS_SCHED(a)
3541 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3543 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3544 guint8 *deps = code->dep_info;
3545 gboolean need_stop, no_stop;
3547 for (i = 0; i < code->nins; ++i)
3551 current_deps_start = 0;
3552 current_ins_start = 0;
3553 deps_start [ins_index] = current_ins_start;
3556 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3557 while (pos < code->dep_info_pos) {
3559 switch (deps [pos]) {
3560 case IA64_END_OF_INS:
3562 current_ins_start = pos + 2;
3563 deps_start [ins_index] = current_ins_start;
3565 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3570 reg = deps [pos + 1];
3572 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3573 for (i = current_deps_start; i < current_ins_start; i += 2)
3574 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3578 reg = code->dep_info [pos + 1];
3580 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3581 for (i = current_deps_start; i < current_ins_start; i += 2)
3582 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3586 reg = deps [pos + 1];
3588 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3589 for (i = current_deps_start; i < current_ins_start; i += 2)
3590 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3593 case IA64_READ_PR_BRANCH:
3594 reg = deps [pos + 1];
3596 /* Writes to prs by non-float instructions are visible to branches */
3597 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3598 for (i = current_deps_start; i < current_ins_start; i += 2)
3599 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3603 reg = code->dep_info [pos + 1];
3605 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3606 for (i = current_deps_start; i < current_ins_start; i += 2)
3607 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3610 case IA64_WRITE_PR_FLOAT:
3611 reg = code->dep_info [pos + 1];
3613 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3614 for (i = current_deps_start; i < current_ins_start; i += 2)
3615 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3619 reg = deps [pos + 1];
3621 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3622 for (i = current_deps_start; i < current_ins_start; i += 2)
3623 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3627 reg = code->dep_info [pos + 1];
3629 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3630 for (i = current_deps_start; i < current_ins_start; i += 2)
3631 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3634 case IA64_READ_BR_BRANCH:
3635 reg = deps [pos + 1];
3637 /* Writes to brs are visible to branches */
3638 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3641 reg = deps [pos + 1];
3643 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3644 for (i = current_deps_start; i < current_ins_start; i += 2)
3645 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3649 reg = code->dep_info [pos + 1];
3651 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3652 for (i = current_deps_start; i < current_ins_start; i += 2)
3653 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3657 reg = deps [pos + 1];
3659 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3660 for (i = current_deps_start; i < current_ins_start; i += 2)
3661 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3665 reg = code->dep_info [pos + 1];
3667 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3668 for (i = current_deps_start; i < current_ins_start; i += 2)
3669 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3674 * Explicitly indicate that a stop is not required. Useful for
3675 * example when two predicated instructions with negated predicates
3676 * write the same registers.
3681 g_assert_not_reached ();
3685 if (need_stop && !no_stop) {
3686 g_assert (ins_index > 0);
3687 stops [ins_index - 1] = 1;
3689 DEBUG_INS_SCHED (printf ("STOP\n"));
3690 current_deps_start = current_ins_start;
3692 /* Skip remaining deps for this instruction */
3693 while (deps [pos] != IA64_END_OF_INS)
3698 if (code->nins > 0) {
3699 /* No dependency info for the last instruction */
3700 stops [code->nins - 1] = 1;
3703 deps_start [code->nins] = code->dep_info_pos;
3707 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3709 int stop_pos, i, deps_to_shift, dep_shift;
3711 g_assert (n <= code->nins);
3713 // if (n > 1) printf ("FOUND: %ld.\n", template);
3715 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3717 stop_pos = last_stop_in_template [template] + 1;
3721 /* Compute the number of 'real' instructions before the stop */
3722 deps_to_shift = stop_pos;
3723 if (stop_pos >= 3 && (nops & (1 << 2)))
3725 if (stop_pos >= 2 && (nops & (1 << 1)))
3727 if (stop_pos >= 1 && (nops & (1 << 0)))
3731 * We have to keep some dependencies whose instructions have been shifted
3732 * out of the buffer. So nullify the end_of_ins markers in the dependency
3735 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3736 if (code->dep_info [i] == IA64_END_OF_INS)
3737 code->dep_info [i] = IA64_NONE;
3739 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3740 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3741 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3743 dep_shift = deps_start [deps_to_shift];
3744 for (i = 0; i < code->nins + 1 - n; ++i)
3745 deps_start [i] = deps_start [n + i] - dep_shift;
3747 /* Determine the exact positions of instructions with unwind ops */
3748 if (code->unw_op_count) {
3750 int curr_ins, curr_ins_pos;
3753 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3754 for (i = 0; i < 3; ++i) {
3755 if (! (nops & (1 << i))) {
3756 ins_pos [curr_ins] = curr_ins_pos + i;
3761 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3762 if (code->unw_ops_pos [i] < n) {
3763 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3764 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3767 if (code->unw_op_pos < code->unw_op_count)
3768 code->unw_op_pos += n;
3771 if (n == code->nins) {
3776 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3777 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3778 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3784 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3786 int i, ins_type, template, nins_to_emit;
3787 int deps_start [16];
3792 * We implement a simple scheduler which tries to put three instructions
3793 * per bundle, then two, then one.
3795 ia64_analyze_deps (code, deps_start, stops);
3797 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3798 /* Find a suitable template */
3799 for (template = 0; template < 32; ++template) {
3800 if (stops_in_template [template][0] != stops [0] ||
3801 stops_in_template [template][1] != stops [1] ||
3802 stops_in_template [template][2] != stops [2])
3806 for (i = 0; i < 3; ++i) {
3807 ins_type = ins_types_in_template [template][i];
3808 switch (code->itypes [i]) {
3809 case IA64_INS_TYPE_A:
3810 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3813 found &= (ins_type == code->itypes [i]);
3819 found = debug_ins_sched ();
3822 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3828 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3829 /* Wait for more instructions */
3832 /* If it didn't work out, try putting two instructions into one bundle */
3833 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3834 /* Try a nop at the end */
3835 for (template = 0; template < 32; ++template) {
3836 if (stops_in_template [template][0] != stops [0] ||
3837 ((stops_in_template [template][1] != stops [1]) &&
3838 (stops_in_template [template][2] != stops [1])))
3842 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3843 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3846 if (!debug_ins_sched ())
3849 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);
3854 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3855 /* Wait for more instructions */
3858 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3859 /* Try a nop in the middle */
3860 for (template = 0; template < 32; ++template) {
3861 if (((stops_in_template [template][0] != stops [0]) &&
3862 (stops_in_template [template][1] != stops [0])) ||
3863 stops_in_template [template][2] != stops [1])
3866 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3867 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3870 if (!debug_ins_sched ())
3873 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);
3878 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3879 /* Try a nop at the beginning */
3880 for (template = 0; template < 32; ++template) {
3881 if ((stops_in_template [template][1] != stops [0]) ||
3882 (stops_in_template [template][2] != stops [1]))
3885 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3886 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3889 if (!debug_ins_sched ())
3892 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);
3897 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3898 /* Wait for more instructions */
3902 nins_to_emit = code->nins;
3906 while (nins_to_emit > 0) {
3907 if (!debug_ins_sched ())
3909 switch (code->itypes [0]) {
3910 case IA64_INS_TYPE_A:
3912 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3914 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3916 case IA64_INS_TYPE_I:
3918 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3920 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3922 case IA64_INS_TYPE_M:
3924 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3926 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3928 case IA64_INS_TYPE_B:
3930 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3932 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3934 case IA64_INS_TYPE_F:
3936 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3938 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3940 case IA64_INS_TYPE_LX:
3941 if (stops [0] || stops [1])
3942 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3944 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3948 g_assert_not_reached ();
3954 unw_dyn_region_info_t*
3955 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3957 unw_dyn_region_info_t *r;
3959 g_assert (code->nins == 0);
3960 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3961 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3962 r->op_count = code->unw_op_count;
3963 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3964 code->unw_op_count = 0;
3965 code->unw_op_pos = 0;
3966 code->region_start = code->buf;
3972 ia64_patch (unsigned char* code, gpointer target)
3975 guint64 instructions [3];
3976 guint8 gen_buf [16];
3977 Ia64CodegenState gen;
3982 * code encodes both the position inside the buffer and code.nins when
3983 * the instruction was emitted.
3985 ins_to_skip = (guint64)code % 16;
3986 code = (unsigned char*)((guint64)code & ~15);
3989 * Search for the first instruction which is 'patchable', skipping
3990 * ins_to_skip instructions.
3995 template = ia64_bundle_template (code);
3996 instructions [0] = ia64_bundle_ins1 (code);
3997 instructions [1] = ia64_bundle_ins2 (code);
3998 instructions [2] = ia64_bundle_ins3 (code);
4000 ia64_codegen_init (gen, gen_buf);
4003 for (i = 0; i < 3; ++i) {
4004 guint64 ins = instructions [i];
4005 int opcode = ia64_ins_opcode (ins);
4007 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
4015 switch (ins_types_in_template [template][i]) {
4016 case IA64_INS_TYPE_A:
4017 case IA64_INS_TYPE_M:
4018 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
4020 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
4021 instructions [i] = gen.instructions [0];
4027 case IA64_INS_TYPE_B:
4028 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
4030 gint64 disp = ((guint8*)target - code) >> 4;
4033 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
4035 instructions [i] = gen.instructions [0];
4038 else if (opcode == 5) {
4040 gint64 disp = ((guint8*)target - code) >> 4;
4043 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
4044 instructions [i] = gen.instructions [0];
4050 case IA64_INS_TYPE_LX:
4054 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
4056 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
4057 instructions [1] = gen.instructions [0];
4058 instructions [2] = gen.instructions [1];
4071 ia64_codegen_init (gen, code);
4072 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
4082 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4084 MonoJumpInfo *patch_info;
4086 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4087 unsigned char *ip = patch_info->ip.i + code;
4088 const unsigned char *target;
4090 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4092 if (patch_info->type == MONO_PATCH_INFO_NONE)
4094 if (mono_compile_aot) {
4098 ia64_patch (ip, (gpointer)target);
4103 mono_arch_emit_prolog (MonoCompile *cfg)
4105 MonoMethod *method = cfg->method;
4106 MonoMethodSignature *sig;
4108 int alloc_size, pos, i;
4109 Ia64CodegenState code;
4112 sig = mono_method_signature (method);
4115 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4117 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
4119 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4120 cfg->code_size += 1024;
4121 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4122 cfg->code_size += 1024;
4124 cfg->native_code = g_malloc (cfg->code_size);
4126 ia64_codegen_init (code, cfg->native_code);
4128 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
4129 if (cfg->param_area)
4130 alloc_size += cfg->param_area;
4134 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
4136 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
4137 /* Force sp to be saved/restored */
4138 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
4140 cfg->arch.stack_alloc_size = alloc_size;
4144 if (method->save_lmf) {
4145 /* No LMF on IA64 */
4150 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
4151 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);
4152 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
4153 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
4155 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
4156 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
4157 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
4158 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
4159 ia64_mov (code, cfg->frame_reg, IA64_SP);
4163 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4164 int pagesize = getpagesize ();
4166 if (alloc_size >= pagesize) {
4167 gint32 remaining_size = alloc_size;
4169 /* Generate stack touching code */
4170 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
4171 while (remaining_size >= pagesize) {
4172 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
4173 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4174 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4175 remaining_size -= pagesize;
4179 if (ia64_is_imm14 (-alloc_size)) {
4180 if (cfg->arch.omit_fp)
4181 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4182 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
4185 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
4186 if (cfg->arch.omit_fp)
4187 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4188 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4192 ia64_begin_bundle (code);
4194 /* Initialize unwind info */
4195 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
4197 if (sig->ret->type != MONO_TYPE_VOID) {
4198 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
4199 /* Save volatile arguments to the stack */
4204 /* Keep this in sync with emit_load_volatile_arguments */
4205 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4206 ArgInfo *ainfo = cinfo->args + i;
4207 gint32 stack_offset;
4210 inst = cfg->args [i];
4212 if (sig->hasthis && (i == 0))
4213 arg_type = &mono_defaults.object_class->byval_arg;
4215 arg_type = sig->params [i - sig->hasthis];
4217 arg_type = mono_type_get_underlying_type (arg_type);
4219 stack_offset = ainfo->offset + ARGS_OFFSET;
4222 * FIXME: Native code might pass non register sized integers
4223 * without initializing the upper bits.
4225 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && !arg_type->byref && ainfo->storage == ArgInIReg) {
4226 int reg = cfg->arch.reg_in0 + ainfo->reg;
4228 switch (mono_type_to_load_membase (cfg, arg_type)) {
4229 case OP_LOADI1_MEMBASE:
4230 ia64_sxt1 (code, reg, reg);
4232 case OP_LOADU1_MEMBASE:
4233 ia64_zxt1 (code, reg, reg);
4235 case OP_LOADI2_MEMBASE:
4236 ia64_sxt2 (code, reg, reg);
4238 case OP_LOADU2_MEMBASE:
4239 ia64_zxt2 (code, reg, reg);
4246 /* Save volatile arguments to the stack */
4247 if (inst->opcode != OP_REGVAR) {
4248 switch (ainfo->storage) {
4251 case ArgInFloatRegR4:
4252 g_assert (inst->opcode == OP_REGOFFSET);
4253 if (ia64_is_adds_imm (inst->inst_offset))
4254 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4256 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
4257 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4259 if (arg_type->byref)
4260 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4262 switch (arg_type->type) {
4264 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4267 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4270 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4278 if (ainfo->nslots != ainfo->nregs)
4281 g_assert (inst->opcode == OP_REGOFFSET);
4282 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4283 for (i = 0; i < ainfo->nregs; ++i) {
4284 switch (ainfo->atype) {
4285 case AggregateNormal:
4286 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
4288 case AggregateSingleHFA:
4289 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
4291 case AggregateDoubleHFA:
4292 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4300 g_assert_not_reached ();
4304 if (inst->opcode == OP_REGVAR) {
4305 /* Argument allocated to (non-volatile) register */
4306 switch (ainfo->storage) {
4308 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4309 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4312 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4313 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4321 if (method->save_lmf) {
4322 /* No LMF on IA64 */
4325 ia64_codegen_close (code);
4327 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4328 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4330 cfg->code_len = code.buf - cfg->native_code;
4332 g_assert (cfg->code_len < cfg->code_size);
4334 cfg->arch.prolog_end_offset = cfg->code_len;
4340 mono_arch_emit_epilog (MonoCompile *cfg)
4342 MonoMethod *method = cfg->method;
4344 int max_epilog_size = 16 * 4;
4345 Ia64CodegenState code;
4350 if (mono_jit_trace_calls != NULL)
4351 max_epilog_size += 1024;
4353 cfg->arch.epilog_begin_offset = cfg->code_len;
4355 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4356 cfg->code_size *= 2;
4357 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4358 mono_jit_stats.code_reallocs++;
4361 /* FIXME: Emit unwind info */
4363 buf = cfg->native_code + cfg->code_len;
4365 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4366 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4368 ia64_codegen_init (code, buf);
4370 /* the code restoring the registers must be kept in sync with OP_JMP */
4373 if (method->save_lmf) {
4374 /* No LMF on IA64 */
4377 /* Load returned vtypes into registers if needed */
4378 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4379 ainfo = &cinfo->ret;
4380 switch (ainfo->storage) {
4382 if (ainfo->nslots != ainfo->nregs)
4385 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4386 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4387 for (i = 0; i < ainfo->nregs; ++i) {
4388 switch (ainfo->atype) {
4389 case AggregateNormal:
4390 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4392 case AggregateSingleHFA:
4393 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4395 case AggregateDoubleHFA:
4396 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4399 g_assert_not_reached ();
4407 ia64_begin_bundle (code);
4409 code.region_start = cfg->native_code;
4411 /* Label the unwind state at the start of the exception throwing region */
4412 //ia64_unw_label_state (code, 1234);
4414 if (cfg->arch.stack_alloc_size) {
4415 if (cfg->arch.omit_fp) {
4416 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4417 ia64_unw_pop_frames (code, 1);
4418 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4420 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4421 ia64_unw_pop_frames (code, 1);
4422 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4426 ia64_unw_pop_frames (code, 1);
4427 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4430 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4431 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4432 ia64_br_ret_reg (code, IA64_B0);
4434 ia64_codegen_close (code);
4436 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4437 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4439 cfg->code_len = code.buf - cfg->native_code;
4441 g_assert (cfg->code_len < cfg->code_size);
4445 mono_arch_emit_exceptions (MonoCompile *cfg)
4447 MonoJumpInfo *patch_info;
4449 Ia64CodegenState code;
4450 gboolean empty = TRUE;
4451 //unw_dyn_region_info_t *r_exceptions;
4452 MonoClass *exc_classes [16];
4453 guint8 *exc_throw_start [16], *exc_throw_end [16];
4454 guint32 code_size = 0;
4456 /* Compute needed space */
4457 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4458 if (patch_info->type == MONO_PATCH_INFO_EXC)
4460 if (patch_info->type == MONO_PATCH_INFO_R8)
4461 code_size += 8 + 7; /* sizeof (double) + alignment */
4462 if (patch_info->type == MONO_PATCH_INFO_R4)
4463 code_size += 4 + 7; /* sizeof (float) + alignment */
4469 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4470 cfg->code_size *= 2;
4471 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4472 mono_jit_stats.code_reallocs++;
4475 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4477 /* The unwind state here is the same as before the epilog */
4478 //ia64_unw_copy_state (code, 1234);
4480 /* add code to raise exceptions */
4481 /* FIXME: Optimize this */
4483 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4484 switch (patch_info->type) {
4485 case MONO_PATCH_INFO_EXC: {
4486 MonoClass *exc_class;
4489 guint64 exc_token_index;
4491 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4492 g_assert (exc_class);
4493 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4494 throw_ip = cfg->native_code + patch_info->ip.i;
4496 ia64_begin_bundle (code);
4498 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4500 /* Find a throw sequence for the same exception class */
4501 for (i = 0; i < nthrows; ++i)
4502 if (exc_classes [i] == exc_class)
4506 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4508 if (ia64_is_adds_imm (offset))
4509 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4511 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4513 buf = code.buf + code.nins;
4514 ia64_br_cond_pred (code, 0, 0);
4515 ia64_begin_bundle (code);
4516 ia64_patch (buf, exc_throw_start [i]);
4518 patch_info->type = MONO_PATCH_INFO_NONE;
4523 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4525 ia64_begin_bundle (code);
4528 exc_classes [nthrows] = exc_class;
4529 exc_throw_start [nthrows] = code.buf;
4533 if (ia64_is_adds_imm (exc_token_index))
4534 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4536 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4538 patch_info->data.name = "mono_arch_throw_corlib_exception";
4539 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4540 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4543 ia64_movl (code, GP_SCRATCH_REG, 0);
4544 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4545 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4546 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4548 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4550 /* Patch up the throw offset */
4551 ia64_begin_bundle (code);
4553 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4556 exc_throw_end [nthrows] = code.buf;
4570 /* The unwinder needs this to work */
4571 ia64_break_i (code, 0);
4573 ia64_codegen_close (code);
4576 //r_exceptions = mono_ia64_create_unwind_region (&code);
4577 //cfg->arch.r_epilog = r_exceptions;
4579 cfg->code_len = code.buf - cfg->native_code;
4581 g_assert (cfg->code_len < cfg->code_size);
4585 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4587 Ia64CodegenState code;
4588 CallInfo *cinfo = NULL;
4589 MonoMethodSignature *sig;
4591 int i, n, stack_area = 0;
4593 ia64_codegen_init (code, p);
4595 /* Keep this in sync with mono_arch_get_argument_info */
4597 if (enable_arguments) {
4598 /* Allocate a new area on the stack and save arguments there */
4599 sig = mono_method_signature (cfg->method);
4601 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4603 n = sig->param_count + sig->hasthis;
4605 stack_area = ALIGN_TO (n * 8, 16);
4608 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4610 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4612 /* FIXME: Allocate out registers */
4614 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4616 /* Required by the ABI */
4617 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4619 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4620 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4622 /* Save arguments to the stack */
4623 for (i = 0; i < n; ++i) {
4624 ins = cfg->args [i];
4626 if (ins->opcode == OP_REGVAR) {
4627 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4628 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4629 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4632 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4633 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4634 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4635 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4636 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4637 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4642 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4645 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4647 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4648 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4650 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4652 if (enable_arguments && stack_area) {
4653 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4655 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4657 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4660 ia64_codegen_close (code);
4666 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4668 Ia64CodegenState code;
4669 CallInfo *cinfo = NULL;
4670 MonoMethod *method = cfg->method;
4671 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4673 ia64_codegen_init (code, p);
4675 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4677 /* Save return value + pass it to func */
4678 switch (cinfo->ret.storage) {
4682 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4683 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4686 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4687 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4688 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4689 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4691 case ArgValuetypeAddrInIReg:
4692 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4701 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4702 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4703 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4705 /* Restore return value */
4706 switch (cinfo->ret.storage) {
4710 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4713 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4714 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4716 case ArgValuetypeAddrInIReg:
4724 ia64_codegen_close (code);
4730 mono_arch_save_unwind_info (MonoCompile *cfg)
4734 /* FIXME: Unregister this for dynamic methods */
4736 di = g_malloc0 (sizeof (unw_dyn_info_t));
4737 di->start_ip = (unw_word_t) cfg->native_code;
4738 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4740 di->format = UNW_INFO_FORMAT_DYNAMIC;
4741 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4742 di->u.pi.regions = cfg->arch.r_pro;
4744 _U_dyn_register (di);
4748 unw_dyn_region_info_t *region = di->u.pi.regions;
4750 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4752 printf (" [Region: %d]\n", region->insn_count);
4753 region = region->next;
4760 mono_arch_flush_icache (guint8 *code, gint size)
4762 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4763 guint8* end = (guint8*)((guint64)code + size);
4765 #ifdef __INTEL_COMPILER
4766 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4773 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4774 /* FIXME: This could be increased to 128 on some cpus */
4781 mono_arch_flush_register_windows (void)
4783 /* Not needed because of libunwind */
4787 mono_arch_is_inst_imm (gint64 imm)
4789 /* The lowering pass will take care of it */
4795 * Determine whenever the trap whose info is in SIGINFO is caused by
4799 mono_arch_is_int_overflow (void *sigctx, void *info)
4801 /* Division is emulated with explicit overflow checks */
4806 mono_arch_get_patch_offset (guint8 *code)
4814 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4816 guint8 *bundle2 = code - 48;
4817 guint8 *bundle3 = code - 32;
4818 guint8 *bundle4 = code - 16;
4819 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4820 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4821 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4822 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4823 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4824 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4825 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4826 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4827 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4830 * Virtual calls are made with:
4832 * [MII] ld8 r31=[r8]
4836 * mov.sptk b6=r31,0x2000000000f32a80
4843 * br.call.sptk.few b0=b6;;
4846 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4847 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4848 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4849 (ins31 == IA64_NOP_M) &&
4850 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4851 (ins33 == IA64_NOP_I) &&
4852 (ins41 == IA64_NOP_M) &&
4853 (ins42 == IA64_NOP_I) &&
4854 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4855 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4856 g_assert (ins21 == IA64_NOP_M);
4857 g_assert (ins23 == IA64_NOP_I);
4858 g_assert (ia64_ins_opcode (ins22) == 0);
4859 g_assert (ia64_ins_x3 (ins22) == 7);
4860 g_assert (ia64_ins_x (ins22) == 0);
4861 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4863 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4865 return regs [IA64_R11];
4872 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4876 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4879 return (gpointer*)(gpointer)((char*)vt + displacement);
4883 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4890 static gboolean tls_offset_inited = FALSE;
4893 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4895 if (!tls_offset_inited) {
4896 tls_offset_inited = TRUE;
4898 appdomain_tls_offset = mono_domain_get_tls_offset ();
4899 thread_tls_offset = mono_thread_get_tls_offset ();
4904 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4909 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4911 MonoCallInst *call = (MonoCallInst*)inst;
4912 int out_reg = cfg->arch.reg_out0;
4915 CallInfo * cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
4918 if (cinfo->ret.storage == ArgAggregate) {
4919 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4922 * The valuetype is in registers after the call, need to be copied
4923 * to the stack. Save the address to a local here, so the call
4924 * instruction can access it.
4926 g_assert (local->opcode == OP_REGOFFSET);
4927 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4930 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4931 vtarg->sreg1 = vt_reg;
4932 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4933 mono_bblock_add_inst (cfg->cbb, vtarg);
4935 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4941 /* add the this argument */
4942 if (this_reg != -1) {
4944 MONO_INST_NEW (cfg, this, OP_MOVE);
4945 this->type = this_type;
4946 this->sreg1 = this_reg;
4947 this->dreg = mono_regstate_next_int (cfg->rs);
4948 mono_bblock_add_inst (cfg->cbb, this);
4950 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4955 #ifdef MONO_ARCH_HAVE_IMT
4958 * LOCKING: called with the domain lock held
4961 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4965 guint8 *start, *buf;
4966 Ia64CodegenState code;
4969 buf = g_malloc0 (size);
4970 ia64_codegen_init (code, buf);
4972 /* IA64_R9 contains the IMT method */
4974 for (i = 0; i < count; ++i) {
4975 MonoIMTCheckItem *item = imt_entries [i];
4976 ia64_begin_bundle (code);
4977 item->code_target = (guint8*)code.buf + code.nins;
4978 if (item->is_equals) {
4979 if (item->check_target_idx) {
4980 if (!item->compare_done) {
4981 ia64_movl (code, GP_SCRATCH_REG, item->method);
4982 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4984 item->jmp_code = (guint8*)code.buf + code.nins;
4985 ia64_br_cond_pred (code, 7, 0);
4987 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4988 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4989 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4990 ia64_br_cond_reg (code, IA64_B6);
4992 /* enable the commented code to assert on wrong method */
4993 #if ENABLE_WRONG_METHOD_CHECK
4994 g_assert_not_reached ();
4996 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4997 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4998 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4999 ia64_br_cond_reg (code, IA64_B6);
5000 #if ENABLE_WRONG_METHOD_CHECK
5001 g_assert_not_reached ();
5005 ia64_movl (code, GP_SCRATCH_REG, item->method);
5006 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
5007 item->jmp_code = (guint8*)code.buf + code.nins;
5008 ia64_br_cond_pred (code, 6, 0);
5011 /* patch the branches to get to the target items */
5012 for (i = 0; i < count; ++i) {
5013 MonoIMTCheckItem *item = imt_entries [i];
5014 if (item->jmp_code) {
5015 if (item->check_target_idx) {
5016 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5021 ia64_codegen_close (code);
5022 g_assert (code.buf - buf <= size);
5024 size = code.buf - buf;
5025 start = mono_code_manager_reserve (domain->code_mp, size);
5026 memcpy (start, buf, size);
5028 mono_arch_flush_icache (start, size);
5030 mono_stats.imt_thunks_size += size;
5036 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
5038 return regs [IA64_R9];
5042 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
5044 /* Done by the implementation of the CALL_MEMBASE opcodes */
5049 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
5051 return (gpointer)regs [IA64_R10];
5055 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5057 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
5061 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5067 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5069 MonoInst *ins = NULL;
5071 if(cmethod->klass->image == mono_defaults.corlib &&
5072 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5073 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5075 * We don't use the generic version in mini_get_inst_for_method () since the
5076 * ia64 has atomic_add_imm opcodes.
5078 if (strcmp (cmethod->name, "Increment") == 0) {
5081 if (fsig->params [0]->type == MONO_TYPE_I4)
5082 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5083 else if (fsig->params [0]->type == MONO_TYPE_I8)
5084 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5086 g_assert_not_reached ();
5087 MONO_INST_NEW (cfg, ins, opcode);
5089 ins->inst_i0 = args [0];
5090 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5093 if (fsig->params [0]->type == MONO_TYPE_I4)
5094 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5095 else if (fsig->params [0]->type == MONO_TYPE_I8)
5096 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5098 g_assert_not_reached ();
5099 MONO_INST_NEW (cfg, ins, opcode);
5101 ins->inst_i0 = args [0];
5102 } else if (strcmp (cmethod->name, "Add") == 0) {
5105 if (fsig->params [0]->type == MONO_TYPE_I4)
5106 opcode = OP_ATOMIC_ADD_NEW_I4;
5107 else if (fsig->params [0]->type == MONO_TYPE_I8)
5108 opcode = OP_ATOMIC_ADD_NEW_I8;
5110 g_assert_not_reached ();
5112 MONO_INST_NEW (cfg, ins, opcode);
5114 ins->inst_i0 = args [0];
5115 ins->inst_i1 = args [1];
5123 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5125 MonoInst *ins = NULL;
5127 if (cmethod->klass->image == mono_defaults.corlib &&
5128 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5129 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5132 * We don't use the generic version in mini_emit_inst_for_method () since we
5133 * ia64 has atomic_add_imm opcodes.
5135 if (strcmp (cmethod->name, "Increment") == 0) {
5138 if (fsig->params [0]->type == MONO_TYPE_I4)
5139 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5140 else if (fsig->params [0]->type == MONO_TYPE_I8)
5141 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5143 g_assert_not_reached ();
5144 MONO_INST_NEW (cfg, ins, opcode);
5145 ins->dreg = mono_alloc_preg (cfg);
5147 ins->inst_basereg = args [0]->dreg;
5148 ins->inst_offset = 0;
5149 MONO_ADD_INS (cfg->cbb, ins);
5150 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5153 if (fsig->params [0]->type == MONO_TYPE_I4)
5154 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5155 else if (fsig->params [0]->type == MONO_TYPE_I8)
5156 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5158 g_assert_not_reached ();
5159 MONO_INST_NEW (cfg, ins, opcode);
5160 ins->dreg = mono_alloc_preg (cfg);
5162 ins->inst_basereg = args [0]->dreg;
5163 ins->inst_offset = 0;
5164 MONO_ADD_INS (cfg->cbb, ins);
5165 } else if (strcmp (cmethod->name, "Add") == 0) {
5167 gboolean is_imm = FALSE;
5170 if ((args [1]->opcode == OP_ICONST) || (args [1]->opcode == OP_I8CONST)) {
5171 imm = (args [1]->opcode == OP_ICONST) ? args [1]->inst_c0 : args [1]->inst_l;
5173 is_imm = (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
5177 if (fsig->params [0]->type == MONO_TYPE_I4)
5178 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5179 else if (fsig->params [0]->type == MONO_TYPE_I8)
5180 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5182 g_assert_not_reached ();
5184 MONO_INST_NEW (cfg, ins, opcode);
5185 ins->dreg = mono_alloc_ireg (cfg);
5186 ins->inst_basereg = args [0]->dreg;
5187 ins->inst_offset = 0;
5188 ins->inst_imm = imm;
5189 ins->type = (opcode == OP_ATOMIC_ADD_IMM_NEW_I4) ? STACK_I4 : STACK_I8;
5191 if (fsig->params [0]->type == MONO_TYPE_I4)
5192 opcode = OP_ATOMIC_ADD_NEW_I4;
5193 else if (fsig->params [0]->type == MONO_TYPE_I8)
5194 opcode = OP_ATOMIC_ADD_NEW_I8;
5196 g_assert_not_reached ();
5198 MONO_INST_NEW (cfg, ins, opcode);
5199 ins->dreg = mono_alloc_ireg (cfg);
5200 ins->inst_basereg = args [0]->dreg;
5201 ins->inst_offset = 0;
5202 ins->sreg2 = args [1]->dreg;
5203 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5205 MONO_ADD_INS (cfg->cbb, ins);
5213 mono_arch_print_tree (MonoInst *tree, int arity)
5218 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5222 if (appdomain_tls_offset == -1)
5225 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5226 ins->inst_offset = appdomain_tls_offset;
5230 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5234 if (thread_tls_offset == -1)
5237 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5238 ins->inst_offset = thread_tls_offset;
5243 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5245 /* FIXME: implement */
5246 g_assert_not_reached ();