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;
2400 case OP_DUMMY_STORE:
2401 case OP_NOT_REACHED:
2405 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2406 ia64_br_cond_reg (code, IA64_B6);
2410 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2414 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2418 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2422 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2426 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2430 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2434 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2438 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2442 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2445 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2446 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2449 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2452 /* p6 and p7 is set if there is signed/unsigned overflow */
2454 /* Set p8-p9 == (sreg2 > 0) */
2455 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2457 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2459 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2460 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2461 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2462 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2464 /* res <u sreg1 => unsigned overflow */
2465 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2467 /* FIXME: Predicate this since this is a side effect */
2468 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2471 /* p6 and p7 is set if there is signed/unsigned overflow */
2473 /* Set p8-p9 == (sreg2 > 0) */
2474 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2476 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2478 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2479 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2480 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2481 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2483 /* sreg1 <u sreg2 => unsigned overflow */
2484 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2486 /* FIXME: Predicate this since this is a side effect */
2487 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2490 /* Same as OP_IADDCC */
2491 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2493 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2495 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2496 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2498 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2500 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2503 /* Same as OP_ISUBCC */
2505 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2507 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2509 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2510 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2512 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2514 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2519 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2524 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2528 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2532 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2537 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2542 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2544 case OP_ISHR_UN_IMM:
2545 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2546 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2548 case OP_LSHR_UN_IMM:
2549 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2552 /* Based on gcc code */
2553 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2554 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2555 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2556 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2559 case OP_STOREI1_MEMBASE_REG:
2560 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2562 case OP_STOREI2_MEMBASE_REG:
2563 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2565 case OP_STOREI4_MEMBASE_REG:
2566 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2568 case OP_STOREI8_MEMBASE_REG:
2569 case OP_STORE_MEMBASE_REG:
2570 if (ins->inst_offset != 0) {
2571 /* This is generated by local regalloc */
2572 if (ia64_is_imm14 (ins->inst_offset)) {
2573 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2575 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2576 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2578 ins->inst_destbasereg = GP_SCRATCH_REG;
2580 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2583 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2584 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2586 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2587 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2589 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2590 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2592 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2593 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2596 case OP_LOADU1_MEMBASE:
2597 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2599 case OP_LOADU2_MEMBASE:
2600 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2602 case OP_LOADU4_MEMBASE:
2603 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2605 case OP_LOADI1_MEMBASE:
2606 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2607 ia64_sxt1 (code, ins->dreg, ins->dreg);
2609 case OP_LOADI2_MEMBASE:
2610 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2611 ia64_sxt2 (code, ins->dreg, ins->dreg);
2613 case OP_LOADI4_MEMBASE:
2614 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2615 ia64_sxt4 (code, ins->dreg, ins->dreg);
2617 case OP_LOAD_MEMBASE:
2618 case OP_LOADI8_MEMBASE:
2619 if (ins->inst_offset != 0) {
2620 /* This is generated by local regalloc */
2621 if (ia64_is_imm14 (ins->inst_offset)) {
2622 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2624 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2625 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2627 ins->inst_basereg = GP_SCRATCH_REG;
2629 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2632 case OP_IA64_LOADU1_MEMBASE_INC:
2633 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2635 case OP_IA64_LOADU2_MEMBASE_INC:
2636 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2638 case OP_IA64_LOADU4_MEMBASE_INC:
2639 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2641 case OP_IA64_LOADI8_MEMBASE_INC:
2642 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2646 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2649 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2652 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2655 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2658 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2661 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2664 /* Compare opcodes */
2665 case OP_IA64_CMP4_EQ:
2666 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2668 case OP_IA64_CMP4_NE:
2669 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2671 case OP_IA64_CMP4_LE:
2672 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2674 case OP_IA64_CMP4_LT:
2675 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2677 case OP_IA64_CMP4_GE:
2678 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2680 case OP_IA64_CMP4_GT:
2681 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2683 case OP_IA64_CMP4_LT_UN:
2684 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2686 case OP_IA64_CMP4_LE_UN:
2687 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2689 case OP_IA64_CMP4_GT_UN:
2690 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2692 case OP_IA64_CMP4_GE_UN:
2693 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2695 case OP_IA64_CMP_EQ:
2696 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2698 case OP_IA64_CMP_NE:
2699 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2701 case OP_IA64_CMP_LE:
2702 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2704 case OP_IA64_CMP_LT:
2705 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2707 case OP_IA64_CMP_GE:
2708 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2710 case OP_IA64_CMP_GT:
2711 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2713 case OP_IA64_CMP_GT_UN:
2714 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2716 case OP_IA64_CMP_LT_UN:
2717 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2719 case OP_IA64_CMP_GE_UN:
2720 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2722 case OP_IA64_CMP_LE_UN:
2723 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2725 case OP_IA64_CMP4_EQ_IMM:
2726 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2728 case OP_IA64_CMP4_NE_IMM:
2729 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2731 case OP_IA64_CMP4_LE_IMM:
2732 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2734 case OP_IA64_CMP4_LT_IMM:
2735 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2737 case OP_IA64_CMP4_GE_IMM:
2738 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2740 case OP_IA64_CMP4_GT_IMM:
2741 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2743 case OP_IA64_CMP4_LT_UN_IMM:
2744 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2746 case OP_IA64_CMP4_LE_UN_IMM:
2747 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2749 case OP_IA64_CMP4_GT_UN_IMM:
2750 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2752 case OP_IA64_CMP4_GE_UN_IMM:
2753 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2755 case OP_IA64_CMP_EQ_IMM:
2756 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2758 case OP_IA64_CMP_NE_IMM:
2759 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2761 case OP_IA64_CMP_LE_IMM:
2762 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2764 case OP_IA64_CMP_LT_IMM:
2765 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2767 case OP_IA64_CMP_GE_IMM:
2768 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2770 case OP_IA64_CMP_GT_IMM:
2771 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2773 case OP_IA64_CMP_GT_UN_IMM:
2774 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2776 case OP_IA64_CMP_LT_UN_IMM:
2777 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2779 case OP_IA64_CMP_GE_UN_IMM:
2780 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2782 case OP_IA64_CMP_LE_UN_IMM:
2783 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2785 case OP_IA64_FCMP_EQ:
2786 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2788 case OP_IA64_FCMP_NE:
2789 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2791 case OP_IA64_FCMP_LT:
2792 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2794 case OP_IA64_FCMP_GT:
2795 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2797 case OP_IA64_FCMP_LE:
2798 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2800 case OP_IA64_FCMP_GE:
2801 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2803 case OP_IA64_FCMP_GT_UN:
2804 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2805 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2807 case OP_IA64_FCMP_LT_UN:
2808 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2809 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2811 case OP_IA64_FCMP_GE_UN:
2812 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2813 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2815 case OP_IA64_FCMP_LE_UN:
2816 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2817 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2820 case OP_COND_EXC_IOV:
2821 case OP_COND_EXC_OV:
2822 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2824 case OP_COND_EXC_IC:
2826 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2828 case OP_IA64_COND_EXC:
2829 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2832 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2833 ia64_no_stop (code);
2834 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2836 case OP_ICONV_TO_I1:
2837 case OP_LCONV_TO_I1:
2838 /* FIXME: Is this needed ? */
2839 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2841 case OP_ICONV_TO_I2:
2842 case OP_LCONV_TO_I2:
2843 /* FIXME: Is this needed ? */
2844 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2846 case OP_LCONV_TO_I4:
2847 /* FIXME: Is this needed ? */
2848 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2850 case OP_ICONV_TO_U1:
2851 case OP_LCONV_TO_U1:
2852 /* FIXME: Is this needed */
2853 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2855 case OP_ICONV_TO_U2:
2856 case OP_LCONV_TO_U2:
2857 /* FIXME: Is this needed */
2858 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2860 case OP_LCONV_TO_U4:
2861 /* FIXME: Is this needed */
2862 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2864 case OP_ICONV_TO_I8:
2866 case OP_LCONV_TO_I8:
2868 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2870 case OP_LCONV_TO_U8:
2872 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2879 double d = *(double *)ins->inst_p0;
2881 if ((d == 0.0) && (mono_signbit (d) == 0))
2882 ia64_fmov (code, ins->dreg, 0);
2884 ia64_fmov (code, ins->dreg, 1);
2886 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2887 ia64_movl (code, GP_SCRATCH_REG, 0);
2888 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2893 float f = *(float *)ins->inst_p0;
2895 if ((f == 0.0) && (mono_signbit (f) == 0))
2896 ia64_fmov (code, ins->dreg, 0);
2898 ia64_fmov (code, ins->dreg, 1);
2900 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2901 ia64_movl (code, GP_SCRATCH_REG, 0);
2902 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2907 ia64_fmov (code, ins->dreg, ins->sreg1);
2909 case OP_STORER8_MEMBASE_REG:
2910 if (ins->inst_offset != 0) {
2911 /* This is generated by local regalloc */
2912 if (ia64_is_imm14 (ins->inst_offset)) {
2913 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2915 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2916 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2918 ins->inst_destbasereg = GP_SCRATCH_REG;
2920 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2922 case OP_STORER4_MEMBASE_REG:
2923 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2924 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2926 case OP_LOADR8_MEMBASE:
2927 if (ins->inst_offset != 0) {
2928 /* This is generated by local regalloc */
2929 if (ia64_is_imm14 (ins->inst_offset)) {
2930 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2932 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2933 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2935 ins->inst_basereg = GP_SCRATCH_REG;
2937 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2939 case OP_LOADR4_MEMBASE:
2940 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2941 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2943 case OP_ICONV_TO_R4:
2944 case OP_LCONV_TO_R4:
2945 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2946 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2947 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2949 case OP_ICONV_TO_R8:
2950 case OP_LCONV_TO_R8:
2951 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2952 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2953 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2955 case OP_FCONV_TO_R4:
2956 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2958 case OP_FCONV_TO_I8:
2959 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2960 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2963 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2966 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2969 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2972 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2976 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2977 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2979 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2980 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2981 /* Positive infinity */
2982 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2983 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2984 /* Negative infinity */
2985 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2986 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2991 /* ensure ins->sreg1 is not NULL */
2992 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2995 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2996 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
3004 call = (MonoCallInst*)ins;
3006 if (ins->flags & MONO_INST_HAS_METHOD)
3007 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
3009 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
3011 code = emit_move_return_value (cfg, ins, code);
3019 case OP_VOIDCALL_REG: {
3020 MonoCallInst *call = (MonoCallInst*)ins;
3025 * mono_arch_find_this_arg () needs to find the this argument in a global
3028 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
3029 out_reg = cfg->arch.reg_out0;
3030 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
3032 ia64_mov (code, IA64_R10, out_reg);
3035 ia64_mov (code, IA64_R8, ins->sreg1);
3036 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
3037 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3038 ia64_ld8 (code, IA64_GP, IA64_R8);
3039 ia64_br_call_reg (code, IA64_B0, IA64_B6);
3041 code = emit_move_return_value (cfg, ins, code);
3044 case OP_FCALL_MEMBASE:
3045 case OP_LCALL_MEMBASE:
3046 case OP_VCALL_MEMBASE:
3047 case OP_VCALL2_MEMBASE:
3048 case OP_VOIDCALL_MEMBASE:
3049 case OP_CALL_MEMBASE: {
3050 MonoCallInst *call = (MonoCallInst*)ins;
3055 * There are no membase instructions on ia64, but we can't
3056 * lower this since get_vcall_slot_addr () needs to decode it.
3059 /* Keep this in synch with get_vcall_slot_addr */
3060 ia64_mov (code, IA64_R11, ins->sreg1);
3061 if (ia64_is_imm14 (ins->inst_offset))
3062 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
3064 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
3065 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
3068 if (call->method && ins->inst_offset < 0) {
3070 * This is a possible IMT call so save the IMT method in a global
3071 * register where mono_arch_find_imt_method () and its friends can
3074 ia64_movl (code, IA64_R9, call->method);
3078 * mono_arch_find_this_arg () needs to find the this argument in a global
3081 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
3082 out_reg = cfg->arch.reg_out0;
3083 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
3085 ia64_mov (code, IA64_R10, out_reg);
3087 ia64_begin_bundle (code);
3088 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3090 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
3092 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3095 * This nop will tell get_vcall_slot_addr that this is a virtual
3098 ia64_nop_i (code, 0x12345);
3100 ia64_br_call_reg (code, IA64_B0, IA64_B6);
3102 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3104 code = emit_move_return_value (cfg, ins, code);
3109 * Keep in sync with the code in emit_epilog.
3112 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3115 g_assert (!cfg->method->save_lmf);
3117 /* Load arguments into their original registers */
3118 code = emit_load_volatile_arguments (cfg, code);
3120 if (cfg->arch.stack_alloc_size) {
3121 if (cfg->arch.omit_fp) {
3122 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
3123 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
3125 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
3126 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3130 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
3132 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3133 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3135 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3136 ia64_movl (code, GP_SCRATCH_REG, 0);
3137 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3138 ia64_br_cond_reg (code, IA64_B6);
3143 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
3149 /* FIXME: Sigaltstack support */
3151 /* keep alignment */
3152 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
3153 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
3154 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3156 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3158 ia64_mov (code, ins->dreg, IA64_SP);
3160 /* An area at sp is reserved by the ABI for parameter passing */
3161 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
3162 if (ia64_is_adds_imm (abi_offset))
3163 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3165 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3166 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3169 if (ins->flags & MONO_INST_INIT) {
3171 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3173 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3176 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3177 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3178 ia64_br_cond_pred (code, 8, -2);
3180 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3182 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3187 case OP_LOCALLOC_IMM: {
3190 /* FIXME: Sigaltstack support */
3192 gssize size = ins->inst_imm;
3193 size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
3195 if (ia64_is_adds_imm (size))
3196 ia64_adds_imm (code, GP_SCRATCH_REG, size, IA64_R0);
3198 ia64_movl (code, GP_SCRATCH_REG, size);
3200 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3201 ia64_mov (code, ins->dreg, IA64_SP);
3203 /* An area at sp is reserved by the ABI for parameter passing */
3204 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
3205 if (ia64_is_adds_imm (abi_offset))
3206 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3208 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3209 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3212 if (ins->flags & MONO_INST_INIT) {
3214 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3216 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3219 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3220 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3221 ia64_br_cond_pred (code, 8, -2);
3223 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3225 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3231 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
3232 ia64_ld8 (code, ins->dreg, ins->dreg);
3235 /* Synchronization */
3236 case OP_MEMORY_BARRIER:
3239 case OP_ATOMIC_ADD_IMM_NEW_I4:
3240 g_assert (ins->inst_offset == 0);
3241 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3242 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3244 case OP_ATOMIC_ADD_IMM_NEW_I8:
3245 g_assert (ins->inst_offset == 0);
3246 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3247 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3249 case OP_ATOMIC_EXCHANGE_I4:
3250 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3251 ia64_sxt4 (code, ins->dreg, ins->dreg);
3253 case OP_ATOMIC_EXCHANGE_I8:
3254 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3256 case OP_ATOMIC_ADD_NEW_I4: {
3257 guint8 *label, *buf;
3259 /* From libatomic_ops */
3262 ia64_begin_bundle (code);
3263 label = code.buf + code.nins;
3264 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
3265 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3266 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3267 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3268 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3269 buf = code.buf + code.nins;
3270 ia64_br_cond_pred (code, 7, 0);
3271 ia64_begin_bundle (code);
3272 ia64_patch (buf, label);
3273 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3276 case OP_ATOMIC_ADD_NEW_I8: {
3277 guint8 *label, *buf;
3279 /* From libatomic_ops */
3282 ia64_begin_bundle (code);
3283 label = code.buf + code.nins;
3284 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
3285 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
3286 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
3287 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
3288 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3289 buf = code.buf + code.nins;
3290 ia64_br_cond_pred (code, 7, 0);
3291 ia64_begin_bundle (code);
3292 ia64_patch (buf, label);
3293 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3297 /* Exception handling */
3298 case OP_CALL_HANDLER:
3300 * Using a call instruction would mess up the register stack, so
3301 * save the return address to a register and use a
3304 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3305 ia64_mov (code, IA64_R15, IA64_R0);
3306 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3307 /* Add the length of OP_CALL_HANDLER */
3308 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3309 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3310 ia64_movl (code, GP_SCRATCH_REG2, 0);
3311 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3312 ia64_br_cond_reg (code, IA64_B6);
3313 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3315 case OP_START_HANDLER: {
3317 * We receive the return address in GP_SCRATCH_REG.
3319 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3322 * R15 determines our caller. It is used since it is writable using
3324 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3325 * R15 != 0 means we are called by call_filter ().
3327 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3328 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3330 ia64_br_cond_pred (code, 6, 6);
3333 * Called by call_filter:
3334 * Allocate a new stack frame, and set the fp register from the
3335 * value passed in by the caller.
3336 * We allocate a similar frame as is done by the prolog, so
3337 * if an exception is thrown while executing the filter, the
3338 * unwinder can unwind through the filter frame using the unwind
3339 * info for the prolog.
3341 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);
3342 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3343 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3344 ia64_mov (code, cfg->frame_reg, IA64_R15);
3345 /* Signal to endfilter that we are called by call_filter */
3346 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3348 /* Branch target: */
3349 if (ia64_is_imm14 (spvar->inst_offset))
3350 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3352 ia64_movl (code, GP_SCRATCH_REG2, spvar->inst_offset);
3353 ia64_add (code, GP_SCRATCH_REG2, cfg->frame_reg, GP_SCRATCH_REG2);
3356 /* Save the return address */
3357 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3358 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3363 case OP_ENDFILTER: {
3364 /* FIXME: Return the value in ENDFILTER */
3365 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3367 /* Load the return address */
3368 if (ia64_is_imm14 (spvar->inst_offset)) {
3369 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3371 ia64_movl (code, GP_SCRATCH_REG, spvar->inst_offset);
3372 ia64_add (code, GP_SCRATCH_REG, cfg->frame_reg, GP_SCRATCH_REG);
3374 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3377 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3378 ia64_br_cond_pred (code, 7, 4);
3380 /* Called by call_filter */
3382 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3383 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3384 ia64_br_ret_reg (code, IA64_B0);
3386 /* Called by CALL_HANDLER */
3387 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3388 ia64_br_cond_reg (code, IA64_B6);
3392 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3393 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3394 (gpointer)"mono_arch_throw_exception");
3397 * This might be the last instruction in the method, so add a dummy
3398 * instruction so the unwinder will work.
3400 ia64_break_i (code, 0);
3403 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3404 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3405 (gpointer)"mono_arch_rethrow_exception");
3407 ia64_break_i (code, 0);
3411 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3412 g_assert_not_reached ();
3415 if ((code.buf - cfg->native_code - offset) > max_len) {
3416 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3417 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3418 g_assert_not_reached ();
3424 last_offset = offset;
3427 ia64_codegen_close (code);
3429 cfg->code_len = code.buf - cfg->native_code;
3433 mono_arch_register_lowlevel_calls (void)
3437 static Ia64InsType ins_types_in_template [32][3] = {
3438 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3439 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
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_LX, IA64_INS_TYPE_LX},
3443 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3446 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3447 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
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_F, IA64_INS_TYPE_I},
3451 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3452 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3453 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3454 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3455 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3456 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3457 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3460 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3461 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3462 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3463 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3466 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3467 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3472 static gboolean stops_in_template [32][3] = {
3473 { FALSE, FALSE, FALSE },
3474 { FALSE, FALSE, TRUE },
3475 { FALSE, TRUE, FALSE },
3476 { FALSE, TRUE, TRUE },
3477 { FALSE, FALSE, FALSE },
3478 { FALSE, FALSE, TRUE },
3479 { FALSE, FALSE, FALSE },
3480 { FALSE, FALSE, FALSE },
3482 { FALSE, FALSE, FALSE },
3483 { FALSE, FALSE, TRUE },
3484 { TRUE, FALSE, FALSE },
3485 { TRUE, FALSE, TRUE },
3486 { FALSE, FALSE, FALSE },
3487 { FALSE, FALSE, TRUE },
3488 { FALSE, FALSE, FALSE },
3489 { FALSE, FALSE, TRUE },
3491 { FALSE, FALSE, FALSE },
3492 { FALSE, FALSE, TRUE },
3493 { FALSE, FALSE, FALSE },
3494 { FALSE, FALSE, TRUE },
3495 { FALSE, FALSE, FALSE },
3496 { FALSE, FALSE, FALSE },
3497 { FALSE, FALSE, FALSE },
3498 { FALSE, FALSE, TRUE },
3500 { FALSE, FALSE, FALSE },
3501 { FALSE, FALSE, TRUE },
3502 { FALSE, FALSE, FALSE },
3503 { FALSE, FALSE, FALSE },
3504 { FALSE, FALSE, FALSE },
3505 { FALSE, FALSE, TRUE },
3506 { FALSE, FALSE, FALSE },
3507 { FALSE, FALSE, FALSE }
3510 static int last_stop_in_template [32] = {
3511 -1, 2, 1, 2, -1, 2, -1, -1,
3512 -1, 2, 0, 2, -1, 2, -1, 2,
3513 -1, 2, -1, 2, -1, -1, -1, 2,
3514 -1, 2, -1, -1, -1, 2, -1, -1
3517 static guint64 nops_for_ins_types [6] = {
3526 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3533 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3535 #define DEBUG_INS_SCHED(a)
3539 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3541 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3542 guint8 *deps = code->dep_info;
3543 gboolean need_stop, no_stop;
3545 for (i = 0; i < code->nins; ++i)
3549 current_deps_start = 0;
3550 current_ins_start = 0;
3551 deps_start [ins_index] = current_ins_start;
3554 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3555 while (pos < code->dep_info_pos) {
3557 switch (deps [pos]) {
3558 case IA64_END_OF_INS:
3560 current_ins_start = pos + 2;
3561 deps_start [ins_index] = current_ins_start;
3563 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3568 reg = deps [pos + 1];
3570 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3571 for (i = current_deps_start; i < current_ins_start; i += 2)
3572 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3576 reg = code->dep_info [pos + 1];
3578 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3579 for (i = current_deps_start; i < current_ins_start; i += 2)
3580 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3584 reg = deps [pos + 1];
3586 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3587 for (i = current_deps_start; i < current_ins_start; i += 2)
3588 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3591 case IA64_READ_PR_BRANCH:
3592 reg = deps [pos + 1];
3594 /* Writes to prs by non-float instructions are visible to branches */
3595 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3596 for (i = current_deps_start; i < current_ins_start; i += 2)
3597 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3601 reg = code->dep_info [pos + 1];
3603 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3604 for (i = current_deps_start; i < current_ins_start; i += 2)
3605 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3608 case IA64_WRITE_PR_FLOAT:
3609 reg = code->dep_info [pos + 1];
3611 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3612 for (i = current_deps_start; i < current_ins_start; i += 2)
3613 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3617 reg = deps [pos + 1];
3619 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3620 for (i = current_deps_start; i < current_ins_start; i += 2)
3621 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3625 reg = code->dep_info [pos + 1];
3627 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3628 for (i = current_deps_start; i < current_ins_start; i += 2)
3629 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3632 case IA64_READ_BR_BRANCH:
3633 reg = deps [pos + 1];
3635 /* Writes to brs are visible to branches */
3636 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3639 reg = deps [pos + 1];
3641 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3642 for (i = current_deps_start; i < current_ins_start; i += 2)
3643 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3647 reg = code->dep_info [pos + 1];
3649 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3650 for (i = current_deps_start; i < current_ins_start; i += 2)
3651 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3655 reg = deps [pos + 1];
3657 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3658 for (i = current_deps_start; i < current_ins_start; i += 2)
3659 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3663 reg = code->dep_info [pos + 1];
3665 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3666 for (i = current_deps_start; i < current_ins_start; i += 2)
3667 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3672 * Explicitly indicate that a stop is not required. Useful for
3673 * example when two predicated instructions with negated predicates
3674 * write the same registers.
3679 g_assert_not_reached ();
3683 if (need_stop && !no_stop) {
3684 g_assert (ins_index > 0);
3685 stops [ins_index - 1] = 1;
3687 DEBUG_INS_SCHED (printf ("STOP\n"));
3688 current_deps_start = current_ins_start;
3690 /* Skip remaining deps for this instruction */
3691 while (deps [pos] != IA64_END_OF_INS)
3696 if (code->nins > 0) {
3697 /* No dependency info for the last instruction */
3698 stops [code->nins - 1] = 1;
3701 deps_start [code->nins] = code->dep_info_pos;
3705 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3707 int stop_pos, i, deps_to_shift, dep_shift;
3709 g_assert (n <= code->nins);
3711 // if (n > 1) printf ("FOUND: %ld.\n", template);
3713 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3715 stop_pos = last_stop_in_template [template] + 1;
3719 /* Compute the number of 'real' instructions before the stop */
3720 deps_to_shift = stop_pos;
3721 if (stop_pos >= 3 && (nops & (1 << 2)))
3723 if (stop_pos >= 2 && (nops & (1 << 1)))
3725 if (stop_pos >= 1 && (nops & (1 << 0)))
3729 * We have to keep some dependencies whose instructions have been shifted
3730 * out of the buffer. So nullify the end_of_ins markers in the dependency
3733 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3734 if (code->dep_info [i] == IA64_END_OF_INS)
3735 code->dep_info [i] = IA64_NONE;
3737 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3738 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3739 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3741 dep_shift = deps_start [deps_to_shift];
3742 for (i = 0; i < code->nins + 1 - n; ++i)
3743 deps_start [i] = deps_start [n + i] - dep_shift;
3745 /* Determine the exact positions of instructions with unwind ops */
3746 if (code->unw_op_count) {
3748 int curr_ins, curr_ins_pos;
3751 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3752 for (i = 0; i < 3; ++i) {
3753 if (! (nops & (1 << i))) {
3754 ins_pos [curr_ins] = curr_ins_pos + i;
3759 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3760 if (code->unw_ops_pos [i] < n) {
3761 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3762 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3765 if (code->unw_op_pos < code->unw_op_count)
3766 code->unw_op_pos += n;
3769 if (n == code->nins) {
3774 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3775 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3776 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3782 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3784 int i, ins_type, template, nins_to_emit;
3785 int deps_start [16];
3790 * We implement a simple scheduler which tries to put three instructions
3791 * per bundle, then two, then one.
3793 ia64_analyze_deps (code, deps_start, stops);
3795 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3796 /* Find a suitable template */
3797 for (template = 0; template < 32; ++template) {
3798 if (stops_in_template [template][0] != stops [0] ||
3799 stops_in_template [template][1] != stops [1] ||
3800 stops_in_template [template][2] != stops [2])
3804 for (i = 0; i < 3; ++i) {
3805 ins_type = ins_types_in_template [template][i];
3806 switch (code->itypes [i]) {
3807 case IA64_INS_TYPE_A:
3808 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3811 found &= (ins_type == code->itypes [i]);
3817 found = debug_ins_sched ();
3820 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3826 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3827 /* Wait for more instructions */
3830 /* If it didn't work out, try putting two instructions into one bundle */
3831 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3832 /* Try a nop at the end */
3833 for (template = 0; template < 32; ++template) {
3834 if (stops_in_template [template][0] != stops [0] ||
3835 ((stops_in_template [template][1] != stops [1]) &&
3836 (stops_in_template [template][2] != stops [1])))
3840 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3841 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3844 if (!debug_ins_sched ())
3847 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);
3852 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3853 /* Wait for more instructions */
3856 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3857 /* Try a nop in the middle */
3858 for (template = 0; template < 32; ++template) {
3859 if (((stops_in_template [template][0] != stops [0]) &&
3860 (stops_in_template [template][1] != stops [0])) ||
3861 stops_in_template [template][2] != stops [1])
3864 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3865 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3868 if (!debug_ins_sched ())
3871 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);
3876 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3877 /* Try a nop at the beginning */
3878 for (template = 0; template < 32; ++template) {
3879 if ((stops_in_template [template][1] != stops [0]) ||
3880 (stops_in_template [template][2] != stops [1]))
3883 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3884 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3887 if (!debug_ins_sched ())
3890 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);
3895 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3896 /* Wait for more instructions */
3900 nins_to_emit = code->nins;
3904 while (nins_to_emit > 0) {
3905 if (!debug_ins_sched ())
3907 switch (code->itypes [0]) {
3908 case IA64_INS_TYPE_A:
3910 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3912 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3914 case IA64_INS_TYPE_I:
3916 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3918 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3920 case IA64_INS_TYPE_M:
3922 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3924 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3926 case IA64_INS_TYPE_B:
3928 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3930 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3932 case IA64_INS_TYPE_F:
3934 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3936 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3938 case IA64_INS_TYPE_LX:
3939 if (stops [0] || stops [1])
3940 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3942 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3946 g_assert_not_reached ();
3952 unw_dyn_region_info_t*
3953 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3955 unw_dyn_region_info_t *r;
3957 g_assert (code->nins == 0);
3958 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3959 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3960 r->op_count = code->unw_op_count;
3961 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3962 code->unw_op_count = 0;
3963 code->unw_op_pos = 0;
3964 code->region_start = code->buf;
3970 ia64_patch (unsigned char* code, gpointer target)
3973 guint64 instructions [3];
3974 guint8 gen_buf [16];
3975 Ia64CodegenState gen;
3980 * code encodes both the position inside the buffer and code.nins when
3981 * the instruction was emitted.
3983 ins_to_skip = (guint64)code % 16;
3984 code = (unsigned char*)((guint64)code & ~15);
3987 * Search for the first instruction which is 'patchable', skipping
3988 * ins_to_skip instructions.
3993 template = ia64_bundle_template (code);
3994 instructions [0] = ia64_bundle_ins1 (code);
3995 instructions [1] = ia64_bundle_ins2 (code);
3996 instructions [2] = ia64_bundle_ins3 (code);
3998 ia64_codegen_init (gen, gen_buf);
4001 for (i = 0; i < 3; ++i) {
4002 guint64 ins = instructions [i];
4003 int opcode = ia64_ins_opcode (ins);
4005 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
4013 switch (ins_types_in_template [template][i]) {
4014 case IA64_INS_TYPE_A:
4015 case IA64_INS_TYPE_M:
4016 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
4018 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
4019 instructions [i] = gen.instructions [0];
4025 case IA64_INS_TYPE_B:
4026 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
4028 gint64 disp = ((guint8*)target - code) >> 4;
4031 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
4033 instructions [i] = gen.instructions [0];
4036 else if (opcode == 5) {
4038 gint64 disp = ((guint8*)target - code) >> 4;
4041 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
4042 instructions [i] = gen.instructions [0];
4048 case IA64_INS_TYPE_LX:
4052 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
4054 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
4055 instructions [1] = gen.instructions [0];
4056 instructions [2] = gen.instructions [1];
4069 ia64_codegen_init (gen, code);
4070 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
4080 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4082 MonoJumpInfo *patch_info;
4084 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4085 unsigned char *ip = patch_info->ip.i + code;
4086 const unsigned char *target;
4088 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4090 if (patch_info->type == MONO_PATCH_INFO_NONE)
4092 if (mono_compile_aot) {
4096 ia64_patch (ip, (gpointer)target);
4101 mono_arch_emit_prolog (MonoCompile *cfg)
4103 MonoMethod *method = cfg->method;
4104 MonoMethodSignature *sig;
4106 int alloc_size, pos, i;
4107 Ia64CodegenState code;
4110 sig = mono_method_signature (method);
4113 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4115 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
4117 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4118 cfg->code_size += 1024;
4119 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4120 cfg->code_size += 1024;
4122 cfg->native_code = g_malloc (cfg->code_size);
4124 ia64_codegen_init (code, cfg->native_code);
4126 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
4127 if (cfg->param_area)
4128 alloc_size += cfg->param_area;
4132 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
4134 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
4135 /* Force sp to be saved/restored */
4136 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
4138 cfg->arch.stack_alloc_size = alloc_size;
4142 if (method->save_lmf) {
4143 /* No LMF on IA64 */
4148 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
4149 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);
4150 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
4151 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
4153 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
4154 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
4155 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
4156 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
4157 ia64_mov (code, cfg->frame_reg, IA64_SP);
4161 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4162 int pagesize = getpagesize ();
4164 if (alloc_size >= pagesize) {
4165 gint32 remaining_size = alloc_size;
4167 /* Generate stack touching code */
4168 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
4169 while (remaining_size >= pagesize) {
4170 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
4171 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4172 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4173 remaining_size -= pagesize;
4177 if (ia64_is_imm14 (-alloc_size)) {
4178 if (cfg->arch.omit_fp)
4179 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4180 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
4183 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
4184 if (cfg->arch.omit_fp)
4185 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
4186 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4190 ia64_begin_bundle (code);
4192 /* Initialize unwind info */
4193 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
4195 if (sig->ret->type != MONO_TYPE_VOID) {
4196 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
4197 /* Save volatile arguments to the stack */
4202 /* Keep this in sync with emit_load_volatile_arguments */
4203 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4204 ArgInfo *ainfo = cinfo->args + i;
4205 gint32 stack_offset;
4208 inst = cfg->args [i];
4210 if (sig->hasthis && (i == 0))
4211 arg_type = &mono_defaults.object_class->byval_arg;
4213 arg_type = sig->params [i - sig->hasthis];
4215 arg_type = mono_type_get_underlying_type (arg_type);
4217 stack_offset = ainfo->offset + ARGS_OFFSET;
4220 * FIXME: Native code might pass non register sized integers
4221 * without initializing the upper bits.
4223 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && !arg_type->byref && ainfo->storage == ArgInIReg) {
4224 int reg = cfg->arch.reg_in0 + ainfo->reg;
4226 switch (mono_type_to_load_membase (cfg, arg_type)) {
4227 case OP_LOADI1_MEMBASE:
4228 ia64_sxt1 (code, reg, reg);
4230 case OP_LOADU1_MEMBASE:
4231 ia64_zxt1 (code, reg, reg);
4233 case OP_LOADI2_MEMBASE:
4234 ia64_sxt2 (code, reg, reg);
4236 case OP_LOADU2_MEMBASE:
4237 ia64_zxt2 (code, reg, reg);
4244 /* Save volatile arguments to the stack */
4245 if (inst->opcode != OP_REGVAR) {
4246 switch (ainfo->storage) {
4249 case ArgInFloatRegR4:
4250 g_assert (inst->opcode == OP_REGOFFSET);
4251 if (ia64_is_adds_imm (inst->inst_offset))
4252 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4254 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
4255 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4257 if (arg_type->byref)
4258 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4260 switch (arg_type->type) {
4262 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4265 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4268 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4276 if (ainfo->nslots != ainfo->nregs)
4279 g_assert (inst->opcode == OP_REGOFFSET);
4280 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4281 for (i = 0; i < ainfo->nregs; ++i) {
4282 switch (ainfo->atype) {
4283 case AggregateNormal:
4284 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
4286 case AggregateSingleHFA:
4287 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
4289 case AggregateDoubleHFA:
4290 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4298 g_assert_not_reached ();
4302 if (inst->opcode == OP_REGVAR) {
4303 /* Argument allocated to (non-volatile) register */
4304 switch (ainfo->storage) {
4306 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4307 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4310 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4311 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4319 if (method->save_lmf) {
4320 /* No LMF on IA64 */
4323 ia64_codegen_close (code);
4325 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4326 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4328 cfg->code_len = code.buf - cfg->native_code;
4330 g_assert (cfg->code_len < cfg->code_size);
4332 cfg->arch.prolog_end_offset = cfg->code_len;
4338 mono_arch_emit_epilog (MonoCompile *cfg)
4340 MonoMethod *method = cfg->method;
4342 int max_epilog_size = 16 * 4;
4343 Ia64CodegenState code;
4348 if (mono_jit_trace_calls != NULL)
4349 max_epilog_size += 1024;
4351 cfg->arch.epilog_begin_offset = cfg->code_len;
4353 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4354 cfg->code_size *= 2;
4355 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4356 mono_jit_stats.code_reallocs++;
4359 /* FIXME: Emit unwind info */
4361 buf = cfg->native_code + cfg->code_len;
4363 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4364 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4366 ia64_codegen_init (code, buf);
4368 /* the code restoring the registers must be kept in sync with OP_JMP */
4371 if (method->save_lmf) {
4372 /* No LMF on IA64 */
4375 /* Load returned vtypes into registers if needed */
4376 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4377 ainfo = &cinfo->ret;
4378 switch (ainfo->storage) {
4380 if (ainfo->nslots != ainfo->nregs)
4383 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4384 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4385 for (i = 0; i < ainfo->nregs; ++i) {
4386 switch (ainfo->atype) {
4387 case AggregateNormal:
4388 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4390 case AggregateSingleHFA:
4391 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4393 case AggregateDoubleHFA:
4394 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4397 g_assert_not_reached ();
4405 ia64_begin_bundle (code);
4407 code.region_start = cfg->native_code;
4409 /* Label the unwind state at the start of the exception throwing region */
4410 //ia64_unw_label_state (code, 1234);
4412 if (cfg->arch.stack_alloc_size) {
4413 if (cfg->arch.omit_fp) {
4414 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4415 ia64_unw_pop_frames (code, 1);
4416 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4418 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4419 ia64_unw_pop_frames (code, 1);
4420 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4424 ia64_unw_pop_frames (code, 1);
4425 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4428 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4429 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4430 ia64_br_ret_reg (code, IA64_B0);
4432 ia64_codegen_close (code);
4434 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4435 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4437 cfg->code_len = code.buf - cfg->native_code;
4439 g_assert (cfg->code_len < cfg->code_size);
4443 mono_arch_emit_exceptions (MonoCompile *cfg)
4445 MonoJumpInfo *patch_info;
4447 Ia64CodegenState code;
4448 gboolean empty = TRUE;
4449 //unw_dyn_region_info_t *r_exceptions;
4450 MonoClass *exc_classes [16];
4451 guint8 *exc_throw_start [16], *exc_throw_end [16];
4452 guint32 code_size = 0;
4454 /* Compute needed space */
4455 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4456 if (patch_info->type == MONO_PATCH_INFO_EXC)
4458 if (patch_info->type == MONO_PATCH_INFO_R8)
4459 code_size += 8 + 7; /* sizeof (double) + alignment */
4460 if (patch_info->type == MONO_PATCH_INFO_R4)
4461 code_size += 4 + 7; /* sizeof (float) + alignment */
4467 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4468 cfg->code_size *= 2;
4469 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4470 mono_jit_stats.code_reallocs++;
4473 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4475 /* The unwind state here is the same as before the epilog */
4476 //ia64_unw_copy_state (code, 1234);
4478 /* add code to raise exceptions */
4479 /* FIXME: Optimize this */
4481 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4482 switch (patch_info->type) {
4483 case MONO_PATCH_INFO_EXC: {
4484 MonoClass *exc_class;
4487 guint64 exc_token_index;
4489 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4490 g_assert (exc_class);
4491 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4492 throw_ip = cfg->native_code + patch_info->ip.i;
4494 ia64_begin_bundle (code);
4496 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4498 /* Find a throw sequence for the same exception class */
4499 for (i = 0; i < nthrows; ++i)
4500 if (exc_classes [i] == exc_class)
4504 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4506 if (ia64_is_adds_imm (offset))
4507 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4509 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4511 buf = code.buf + code.nins;
4512 ia64_br_cond_pred (code, 0, 0);
4513 ia64_begin_bundle (code);
4514 ia64_patch (buf, exc_throw_start [i]);
4516 patch_info->type = MONO_PATCH_INFO_NONE;
4521 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4523 ia64_begin_bundle (code);
4526 exc_classes [nthrows] = exc_class;
4527 exc_throw_start [nthrows] = code.buf;
4531 if (ia64_is_adds_imm (exc_token_index))
4532 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4534 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4536 patch_info->data.name = "mono_arch_throw_corlib_exception";
4537 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4538 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4541 ia64_movl (code, GP_SCRATCH_REG, 0);
4542 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4543 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4544 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4546 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4548 /* Patch up the throw offset */
4549 ia64_begin_bundle (code);
4551 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4554 exc_throw_end [nthrows] = code.buf;
4568 /* The unwinder needs this to work */
4569 ia64_break_i (code, 0);
4571 ia64_codegen_close (code);
4574 //r_exceptions = mono_ia64_create_unwind_region (&code);
4575 //cfg->arch.r_epilog = r_exceptions;
4577 cfg->code_len = code.buf - cfg->native_code;
4579 g_assert (cfg->code_len < cfg->code_size);
4583 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4585 Ia64CodegenState code;
4586 CallInfo *cinfo = NULL;
4587 MonoMethodSignature *sig;
4589 int i, n, stack_area = 0;
4591 ia64_codegen_init (code, p);
4593 /* Keep this in sync with mono_arch_get_argument_info */
4595 if (enable_arguments) {
4596 /* Allocate a new area on the stack and save arguments there */
4597 sig = mono_method_signature (cfg->method);
4599 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4601 n = sig->param_count + sig->hasthis;
4603 stack_area = ALIGN_TO (n * 8, 16);
4606 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4608 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4610 /* FIXME: Allocate out registers */
4612 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4614 /* Required by the ABI */
4615 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4617 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4618 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4620 /* Save arguments to the stack */
4621 for (i = 0; i < n; ++i) {
4622 ins = cfg->args [i];
4624 if (ins->opcode == OP_REGVAR) {
4625 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4626 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4627 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4630 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4631 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4632 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4633 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4634 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4635 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4640 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4643 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4645 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4646 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4648 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4650 if (enable_arguments && stack_area) {
4651 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4653 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4655 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4658 ia64_codegen_close (code);
4664 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4666 Ia64CodegenState code;
4667 CallInfo *cinfo = NULL;
4668 MonoMethod *method = cfg->method;
4669 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4671 ia64_codegen_init (code, p);
4673 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4675 /* Save return value + pass it to func */
4676 switch (cinfo->ret.storage) {
4680 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4681 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4684 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4685 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4686 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4687 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4689 case ArgValuetypeAddrInIReg:
4690 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4699 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4700 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4701 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4703 /* Restore return value */
4704 switch (cinfo->ret.storage) {
4708 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4711 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4712 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4714 case ArgValuetypeAddrInIReg:
4722 ia64_codegen_close (code);
4728 mono_arch_save_unwind_info (MonoCompile *cfg)
4732 /* FIXME: Unregister this for dynamic methods */
4734 di = g_malloc0 (sizeof (unw_dyn_info_t));
4735 di->start_ip = (unw_word_t) cfg->native_code;
4736 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4738 di->format = UNW_INFO_FORMAT_DYNAMIC;
4739 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4740 di->u.pi.regions = cfg->arch.r_pro;
4742 _U_dyn_register (di);
4746 unw_dyn_region_info_t *region = di->u.pi.regions;
4748 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4750 printf (" [Region: %d]\n", region->insn_count);
4751 region = region->next;
4758 mono_arch_flush_icache (guint8 *code, gint size)
4760 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4761 guint8* end = (guint8*)((guint64)code + size);
4763 #ifdef __INTEL_COMPILER
4764 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4771 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4772 /* FIXME: This could be increased to 128 on some cpus */
4779 mono_arch_flush_register_windows (void)
4781 /* Not needed because of libunwind */
4785 mono_arch_is_inst_imm (gint64 imm)
4787 /* The lowering pass will take care of it */
4793 * Determine whenever the trap whose info is in SIGINFO is caused by
4797 mono_arch_is_int_overflow (void *sigctx, void *info)
4799 /* Division is emulated with explicit overflow checks */
4804 mono_arch_get_patch_offset (guint8 *code)
4812 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4814 guint8 *bundle2 = code - 48;
4815 guint8 *bundle3 = code - 32;
4816 guint8 *bundle4 = code - 16;
4817 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4818 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4819 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4820 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4821 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4822 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4823 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4824 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4825 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4828 * Virtual calls are made with:
4830 * [MII] ld8 r31=[r8]
4834 * mov.sptk b6=r31,0x2000000000f32a80
4841 * br.call.sptk.few b0=b6;;
4844 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4845 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4846 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4847 (ins31 == IA64_NOP_M) &&
4848 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4849 (ins33 == IA64_NOP_I) &&
4850 (ins41 == IA64_NOP_M) &&
4851 (ins42 == IA64_NOP_I) &&
4852 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4853 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4854 g_assert (ins21 == IA64_NOP_M);
4855 g_assert (ins23 == IA64_NOP_I);
4856 g_assert (ia64_ins_opcode (ins22) == 0);
4857 g_assert (ia64_ins_x3 (ins22) == 7);
4858 g_assert (ia64_ins_x (ins22) == 0);
4859 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4861 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4863 return regs [IA64_R11];
4870 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4874 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4877 return (gpointer*)(gpointer)((char*)vt + displacement);
4881 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4888 static gboolean tls_offset_inited = FALSE;
4891 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4893 if (!tls_offset_inited) {
4894 tls_offset_inited = TRUE;
4896 appdomain_tls_offset = mono_domain_get_tls_offset ();
4897 thread_tls_offset = mono_thread_get_tls_offset ();
4902 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4907 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4909 MonoCallInst *call = (MonoCallInst*)inst;
4910 int out_reg = cfg->arch.reg_out0;
4913 CallInfo * cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
4916 if (cinfo->ret.storage == ArgAggregate) {
4917 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4920 * The valuetype is in registers after the call, need to be copied
4921 * to the stack. Save the address to a local here, so the call
4922 * instruction can access it.
4924 g_assert (local->opcode == OP_REGOFFSET);
4925 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4928 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4929 vtarg->sreg1 = vt_reg;
4930 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4931 mono_bblock_add_inst (cfg->cbb, vtarg);
4933 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4939 /* add the this argument */
4940 if (this_reg != -1) {
4942 MONO_INST_NEW (cfg, this, OP_MOVE);
4943 this->type = this_type;
4944 this->sreg1 = this_reg;
4945 this->dreg = mono_regstate_next_int (cfg->rs);
4946 mono_bblock_add_inst (cfg->cbb, this);
4948 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4953 #ifdef MONO_ARCH_HAVE_IMT
4956 * LOCKING: called with the domain lock held
4959 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4963 guint8 *start, *buf;
4964 Ia64CodegenState code;
4967 buf = g_malloc0 (size);
4968 ia64_codegen_init (code, buf);
4970 /* IA64_R9 contains the IMT method */
4972 for (i = 0; i < count; ++i) {
4973 MonoIMTCheckItem *item = imt_entries [i];
4974 ia64_begin_bundle (code);
4975 item->code_target = (guint8*)code.buf + code.nins;
4976 if (item->is_equals) {
4977 if (item->check_target_idx) {
4978 if (!item->compare_done) {
4979 ia64_movl (code, GP_SCRATCH_REG, item->method);
4980 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4982 item->jmp_code = (guint8*)code.buf + code.nins;
4983 ia64_br_cond_pred (code, 7, 0);
4985 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4986 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4987 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4988 ia64_br_cond_reg (code, IA64_B6);
4990 /* enable the commented code to assert on wrong method */
4991 #if ENABLE_WRONG_METHOD_CHECK
4992 g_assert_not_reached ();
4994 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4995 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4996 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4997 ia64_br_cond_reg (code, IA64_B6);
4998 #if ENABLE_WRONG_METHOD_CHECK
4999 g_assert_not_reached ();
5003 ia64_movl (code, GP_SCRATCH_REG, item->method);
5004 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
5005 item->jmp_code = (guint8*)code.buf + code.nins;
5006 ia64_br_cond_pred (code, 6, 0);
5009 /* patch the branches to get to the target items */
5010 for (i = 0; i < count; ++i) {
5011 MonoIMTCheckItem *item = imt_entries [i];
5012 if (item->jmp_code) {
5013 if (item->check_target_idx) {
5014 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5019 ia64_codegen_close (code);
5020 g_assert (code.buf - buf <= size);
5022 size = code.buf - buf;
5023 start = mono_code_manager_reserve (domain->code_mp, size);
5024 memcpy (start, buf, size);
5026 mono_arch_flush_icache (start, size);
5028 mono_stats.imt_thunks_size += size;
5034 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
5036 return regs [IA64_R9];
5040 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
5042 /* Done by the implementation of the CALL_MEMBASE opcodes */
5047 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
5049 return (gpointer)regs [IA64_R10];
5053 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5055 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
5059 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5065 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5067 MonoInst *ins = NULL;
5069 if(cmethod->klass->image == mono_defaults.corlib &&
5070 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5071 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5073 * We don't use the generic version in mini_get_inst_for_method () since the
5074 * ia64 has atomic_add_imm opcodes.
5076 if (strcmp (cmethod->name, "Increment") == 0) {
5079 if (fsig->params [0]->type == MONO_TYPE_I4)
5080 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5081 else if (fsig->params [0]->type == MONO_TYPE_I8)
5082 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5084 g_assert_not_reached ();
5085 MONO_INST_NEW (cfg, ins, opcode);
5087 ins->inst_i0 = args [0];
5088 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5091 if (fsig->params [0]->type == MONO_TYPE_I4)
5092 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5093 else if (fsig->params [0]->type == MONO_TYPE_I8)
5094 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5096 g_assert_not_reached ();
5097 MONO_INST_NEW (cfg, ins, opcode);
5099 ins->inst_i0 = args [0];
5100 } else if (strcmp (cmethod->name, "Add") == 0) {
5103 if (fsig->params [0]->type == MONO_TYPE_I4)
5104 opcode = OP_ATOMIC_ADD_NEW_I4;
5105 else if (fsig->params [0]->type == MONO_TYPE_I8)
5106 opcode = OP_ATOMIC_ADD_NEW_I8;
5108 g_assert_not_reached ();
5110 MONO_INST_NEW (cfg, ins, opcode);
5112 ins->inst_i0 = args [0];
5113 ins->inst_i1 = args [1];
5121 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5123 MonoInst *ins = NULL;
5125 if (cmethod->klass->image == mono_defaults.corlib &&
5126 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5127 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5130 * We don't use the generic version in mini_emit_inst_for_method () since we
5131 * ia64 has atomic_add_imm opcodes.
5133 if (strcmp (cmethod->name, "Increment") == 0) {
5136 if (fsig->params [0]->type == MONO_TYPE_I4)
5137 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5138 else if (fsig->params [0]->type == MONO_TYPE_I8)
5139 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5141 g_assert_not_reached ();
5142 MONO_INST_NEW (cfg, ins, opcode);
5143 ins->dreg = mono_alloc_preg (cfg);
5145 ins->inst_basereg = args [0]->dreg;
5146 ins->inst_offset = 0;
5147 MONO_ADD_INS (cfg->cbb, ins);
5148 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5151 if (fsig->params [0]->type == MONO_TYPE_I4)
5152 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5153 else if (fsig->params [0]->type == MONO_TYPE_I8)
5154 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5156 g_assert_not_reached ();
5157 MONO_INST_NEW (cfg, ins, opcode);
5158 ins->dreg = mono_alloc_preg (cfg);
5160 ins->inst_basereg = args [0]->dreg;
5161 ins->inst_offset = 0;
5162 MONO_ADD_INS (cfg->cbb, ins);
5163 } else if (strcmp (cmethod->name, "Add") == 0) {
5165 gboolean is_imm = FALSE;
5168 if ((args [1]->opcode == OP_ICONST) || (args [1]->opcode == OP_I8CONST)) {
5169 imm = (args [1]->opcode == OP_ICONST) ? args [1]->inst_c0 : args [1]->inst_l;
5171 is_imm = (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
5175 if (fsig->params [0]->type == MONO_TYPE_I4)
5176 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
5177 else if (fsig->params [0]->type == MONO_TYPE_I8)
5178 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
5180 g_assert_not_reached ();
5182 MONO_INST_NEW (cfg, ins, opcode);
5183 ins->dreg = mono_alloc_ireg (cfg);
5184 ins->inst_basereg = args [0]->dreg;
5185 ins->inst_offset = 0;
5186 ins->inst_imm = imm;
5187 ins->type = (opcode == OP_ATOMIC_ADD_IMM_NEW_I4) ? STACK_I4 : STACK_I8;
5189 if (fsig->params [0]->type == MONO_TYPE_I4)
5190 opcode = OP_ATOMIC_ADD_NEW_I4;
5191 else if (fsig->params [0]->type == MONO_TYPE_I8)
5192 opcode = OP_ATOMIC_ADD_NEW_I8;
5194 g_assert_not_reached ();
5196 MONO_INST_NEW (cfg, ins, opcode);
5197 ins->dreg = mono_alloc_ireg (cfg);
5198 ins->inst_basereg = args [0]->dreg;
5199 ins->inst_offset = 0;
5200 ins->sreg2 = args [1]->dreg;
5201 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5203 MONO_ADD_INS (cfg->cbb, ins);
5211 mono_arch_print_tree (MonoInst *tree, int arity)
5216 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5220 if (appdomain_tls_offset == -1)
5223 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5224 ins->inst_offset = appdomain_tls_offset;
5228 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5232 if (thread_tls_offset == -1)
5235 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5236 ins->inst_offset = thread_tls_offset;
5241 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5243 /* FIXME: implement */
5244 g_assert_not_reached ();