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"
30 static gint appdomain_tls_offset = -1;
31 static gint thread_tls_offset = -1;
33 const char * const ia64_desc [OP_LAST];
34 static const char*const * ins_spec = ia64_desc;
36 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
38 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
41 * IA64 register usage:
42 * - local registers are used for global register allocation
43 * - r8..r11, r14..r30 is used for local register allocation
44 * - r31 is a scratch register used within opcode implementations
45 * - FIXME: Use out registers as well
46 * - the first three locals are used for saving ar.pfst, b0, and sp
47 * - compare instructions allways set p6 and p7
51 * There are a lot of places where generated code is disassembled/patched.
52 * The automatic bundling of instructions done by the code generation macros
53 * could complicate things, so it is best to call
54 * ia64_codegen_set_one_ins_per_bundle () at those places.
57 #define SIGNAL_STACK_SIZE (64 * 1024)
59 #define ARGS_OFFSET 16
61 #define GP_SCRATCH_REG 31
62 #define GP_SCRATCH_REG2 30
63 #define FP_SCRATCH_REG 32
65 #define LOOP_ALIGNMENT 8
66 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
68 #define NOT_IMPLEMENTED g_assert_not_reached ()
70 static const char* gregs [] = {
71 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
72 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
73 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
74 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
75 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
76 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
77 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
78 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
79 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
80 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
81 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
82 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
83 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
87 mono_arch_regname (int reg)
95 static const char* fregs [] = {
96 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
97 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
98 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
99 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
100 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
101 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
102 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
103 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
104 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
105 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
106 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
107 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
108 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
112 mono_arch_fregname (int reg)
120 G_GNUC_UNUSED static void
125 G_GNUC_UNUSED static gboolean
128 static int count = 0;
131 if (count == atoi (getenv ("COUNT"))) {
135 if (count > atoi (getenv ("COUNT"))) {
143 debug_ins_sched (void)
146 return debug_count ();
156 return debug_count ();
163 ia64_patch (unsigned char* code, gpointer target);
169 ArgValuetypeAddrInIReg,
187 /* Only if storage == ArgAggregate */
197 gboolean need_stack_align;
203 #define DEBUG(a) if (cfg->verbose_level > 1) a
205 #define NEW_ICONST(cfg,dest,val) do { \
206 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
207 (dest)->opcode = OP_ICONST; \
208 (dest)->inst_c0 = (val); \
209 (dest)->type = STACK_I4; \
215 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
217 ainfo->offset = *stack_size;
219 if (*gr >= PARAM_REGS) {
220 ainfo->storage = ArgOnStack;
221 (*stack_size) += sizeof (gpointer);
224 ainfo->storage = ArgInIReg;
230 #define FLOAT_PARAM_REGS 8
233 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
235 ainfo->offset = *stack_size;
237 if (*gr >= PARAM_REGS) {
238 ainfo->storage = ArgOnStack;
239 (*stack_size) += sizeof (gpointer);
242 ainfo->storage = ArgInFloatReg;
243 ainfo->reg = 8 + *fr;
250 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
252 guint32 *gr, guint32 *fr, guint32 *stack_size)
256 MonoMarshalType *info;
257 gboolean is_hfa = TRUE;
258 guint32 hfa_type = 0;
260 klass = mono_class_from_mono_type (type);
261 if (type->type == MONO_TYPE_TYPEDBYREF)
262 size = 3 * sizeof (gpointer);
263 else if (sig->pinvoke)
264 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
266 size = mono_type_stack_size (&klass->byval_arg, NULL);
268 if (!sig->pinvoke || (size == 0)) {
269 /* Allways pass in memory */
270 ainfo->offset = *stack_size;
271 *stack_size += ALIGN_TO (size, 8);
272 ainfo->storage = ArgOnStack;
277 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
278 info = mono_marshal_load_type_info (klass);
280 for (i = 0; i < info->num_fields; ++i) {
281 guint32 ftype = info->fields [i].field->type->type;
282 if (!(info->fields [i].field->type->byref) &&
283 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
286 else if (hfa_type != ftype)
295 ainfo->storage = ArgAggregate;
296 ainfo->atype = AggregateNormal;
299 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
301 if (info->num_fields <= 8) {
303 ainfo->nregs = info->num_fields;
304 ainfo->nslots = ainfo->nregs;
310 if ((*fr) + info->num_fields > 8)
313 ainfo->reg = 8 + (*fr);
314 ainfo->nregs = info->num_fields;
315 ainfo->nslots = ainfo->nregs;
316 (*fr) += info->num_fields;
321 /* This also handles returning of TypedByRef used by some icalls */
324 ainfo->reg = IA64_R8;
325 ainfo->nregs = (size + 7) / 8;
326 ainfo->nslots = ainfo->nregs;
333 ainfo->offset = *stack_size;
334 ainfo->nslots = (size + 7) / 8;
336 if (((*gr) + ainfo->nslots) <= 8) {
337 /* Fits entirely in registers */
338 ainfo->nregs = ainfo->nslots;
339 (*gr) += ainfo->nregs;
343 ainfo->nregs = 8 - (*gr);
345 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
351 * Obtain information about a call according to the calling convention.
352 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
353 * Gude" document for more information.
356 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
360 int n = sig->hasthis + sig->param_count;
361 guint32 stack_size = 0;
364 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
371 ret_type = mono_type_get_underlying_type (sig->ret);
372 switch (ret_type->type) {
373 case MONO_TYPE_BOOLEAN:
384 case MONO_TYPE_FNPTR:
385 case MONO_TYPE_CLASS:
386 case MONO_TYPE_OBJECT:
387 case MONO_TYPE_SZARRAY:
388 case MONO_TYPE_ARRAY:
389 case MONO_TYPE_STRING:
390 cinfo->ret.storage = ArgInIReg;
391 cinfo->ret.reg = IA64_R8;
395 cinfo->ret.storage = ArgInIReg;
396 cinfo->ret.reg = IA64_R8;
400 cinfo->ret.storage = ArgInFloatReg;
403 case MONO_TYPE_VALUETYPE:
404 case MONO_TYPE_TYPEDBYREF: {
405 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
407 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
408 if (cinfo->ret.storage == ArgOnStack)
409 /* The caller passes the address where the value is stored */
410 add_general (&gr, &stack_size, &cinfo->ret);
411 if (cinfo->ret.storage == ArgInIReg)
412 cinfo->ret.storage = ArgValuetypeAddrInIReg;
416 cinfo->ret.storage = ArgNone;
419 g_error ("Can't handle as return value 0x%x", sig->ret->type);
425 add_general (&gr, &stack_size, cinfo->args + 0);
427 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
429 fr = FLOAT_PARAM_REGS;
431 /* Emit the signature cookie just before the implicit arguments */
432 add_general (&gr, &stack_size, &cinfo->sig_cookie);
435 for (i = 0; i < sig->param_count; ++i) {
436 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
439 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
440 /* We allways pass the sig cookie on the stack for simplicity */
442 * Prevent implicit arguments + the sig cookie from being passed
446 fr = FLOAT_PARAM_REGS;
448 /* Emit the signature cookie just before the implicit arguments */
449 add_general (&gr, &stack_size, &cinfo->sig_cookie);
452 if (sig->params [i]->byref) {
453 add_general (&gr, &stack_size, ainfo);
456 ptype = mono_type_get_underlying_type (sig->params [i]);
457 switch (ptype->type) {
458 case MONO_TYPE_BOOLEAN:
461 add_general (&gr, &stack_size, ainfo);
466 add_general (&gr, &stack_size, ainfo);
470 add_general (&gr, &stack_size, ainfo);
475 case MONO_TYPE_FNPTR:
476 case MONO_TYPE_CLASS:
477 case MONO_TYPE_OBJECT:
478 case MONO_TYPE_STRING:
479 case MONO_TYPE_SZARRAY:
480 case MONO_TYPE_ARRAY:
481 add_general (&gr, &stack_size, ainfo);
483 case MONO_TYPE_VALUETYPE:
484 case MONO_TYPE_TYPEDBYREF:
486 /* We allways pass valuetypes on the stack */
487 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
491 add_general (&gr, &stack_size, ainfo);
494 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
497 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
500 g_assert_not_reached ();
504 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
506 fr = FLOAT_PARAM_REGS;
508 /* Emit the signature cookie just before the implicit arguments */
509 add_general (&gr, &stack_size, &cinfo->sig_cookie);
512 cinfo->stack_usage = stack_size;
513 cinfo->reg_usage = gr;
514 cinfo->freg_usage = fr;
519 * mono_arch_get_argument_info:
520 * @csig: a method signature
521 * @param_count: the number of parameters to consider
522 * @arg_info: an array to store the result infos
524 * Gathers information on parameters such as size, alignment and
525 * padding. arg_info should be large enought to hold param_count + 1 entries.
527 * Returns the size of the argument area on the stack.
530 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
533 CallInfo *cinfo = get_call_info (csig, FALSE);
534 guint32 args_size = cinfo->stack_usage;
536 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
538 arg_info [0].offset = 0;
541 for (k = 0; k < param_count; k++) {
542 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
544 arg_info [k + 1].size = 0;
553 * Initialize the cpu to execute managed code.
556 mono_arch_cpu_init (void)
561 * This function returns the optimizations supported on this cpu.
564 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
572 mono_arch_break (void)
577 is_regsize_var (MonoType *t) {
580 t = mono_type_get_underlying_type (t);
591 case MONO_TYPE_FNPTR:
592 case MONO_TYPE_BOOLEAN:
594 case MONO_TYPE_OBJECT:
595 case MONO_TYPE_STRING:
596 case MONO_TYPE_CLASS:
597 case MONO_TYPE_SZARRAY:
598 case MONO_TYPE_ARRAY:
600 case MONO_TYPE_VALUETYPE:
607 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
611 MonoMethodSignature *sig;
612 MonoMethodHeader *header;
615 header = mono_method_get_header (cfg->method);
617 sig = mono_method_signature (cfg->method);
619 cinfo = get_call_info (sig, FALSE);
621 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
622 MonoInst *ins = cfg->varinfo [i];
624 ArgInfo *ainfo = &cinfo->args [i];
626 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
629 if (ainfo->storage == ArgInIReg) {
630 /* The input registers are non-volatile */
631 ins->opcode = OP_REGVAR;
632 ins->dreg = 32 + ainfo->reg;
636 for (i = 0; i < cfg->num_varinfo; i++) {
637 MonoInst *ins = cfg->varinfo [i];
638 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
641 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
644 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
645 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
648 if (is_regsize_var (ins->inst_vtype)) {
649 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
650 g_assert (i == vmv->idx);
651 vars = g_list_prepend (vars, vmv);
655 vars = mono_varlist_sort (cfg, vars, 0);
661 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
664 guint32 reserved_regs = 3;
666 if (cfg->arch.reg_local0 > 0)
670 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
672 /* Three registers are reserved for use by the prolog/epilog */
675 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
676 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
677 /* One registers is needed by instrument_epilog to save the return value */
679 if (cinfo->reg_usage < 2)
680 /* Number of arguments passed to function call in instrument_prolog */
681 cinfo->reg_usage = 2;
684 cfg->arch.reg_in0 = 32;
685 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
686 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
688 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
689 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
690 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 3;
692 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
693 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
694 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - 4;
698 * Need to allocate at least 2 out register for use by CEE_THROW / the system
699 * exception throwing code.
701 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
707 mono_arch_get_global_int_regs (MonoCompile *cfg)
712 mono_ia64_alloc_stacked_registers (cfg);
714 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
717 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
724 * mono_arch_regalloc_cost:
726 * Return the cost, in number of memory references, of the action of
727 * allocating the variable VMV into a register during global register
731 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
733 /* FIXME: Increase costs linearly to avoid using all local registers */
739 mono_arch_allocate_vars (MonoCompile *cfg)
741 MonoMethodSignature *sig;
742 MonoMethodHeader *header;
745 guint32 locals_stack_size, locals_stack_align;
749 header = mono_method_get_header (cfg->method);
751 sig = mono_method_signature (cfg->method);
753 cinfo = get_call_info (sig, FALSE);
756 * Determine whenever the frame pointer can be eliminated.
757 * FIXME: Remove some of the restrictions.
759 cfg->arch.omit_fp = TRUE;
761 if (!debug_omit_fp ())
762 cfg->arch.omit_fp = FALSE;
764 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
765 cfg->arch.omit_fp = FALSE;
766 if (header->num_clauses)
767 cfg->arch.omit_fp = FALSE;
769 cfg->arch.omit_fp = FALSE;
770 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
771 ArgInfo *ainfo = &cinfo->args [i];
773 if (ainfo->storage == ArgOnStack) {
775 * The stack offset can only be determined when the frame
778 cfg->arch.omit_fp = FALSE;
782 mono_ia64_alloc_stacked_registers (cfg);
785 * We use the ABI calling conventions for managed code as well.
786 * Exception: valuetypes are never passed or returned in registers.
789 if (cfg->arch.omit_fp) {
790 cfg->frame_reg = IA64_SP;
791 offset = ARGS_OFFSET;
794 /* Locals are allocated backwards from %fp */
795 cfg->frame_reg = cfg->arch.reg_saved_sp;
799 if (cfg->method->save_lmf) {
803 if (sig->ret->type != MONO_TYPE_VOID) {
804 switch (cinfo->ret.storage) {
806 cfg->ret->opcode = OP_REGVAR;
807 cfg->ret->inst_c0 = cinfo->ret.reg;
810 cfg->ret->opcode = OP_REGVAR;
811 cfg->ret->inst_c0 = cinfo->ret.reg;
813 case ArgValuetypeAddrInIReg:
814 cfg->ret->opcode = OP_REGVAR;
815 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
818 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
819 if (cfg->arch.omit_fp)
820 g_assert_not_reached ();
821 offset = ALIGN_TO (offset, 8);
822 offset += cinfo->ret.nslots * 8;
823 cfg->ret->opcode = OP_REGOFFSET;
824 cfg->ret->inst_basereg = cfg->frame_reg;
825 cfg->ret->inst_offset = - offset;
828 g_assert_not_reached ();
830 cfg->ret->dreg = cfg->ret->inst_c0;
833 /* Allocate locals */
834 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
835 if (locals_stack_align) {
836 offset = ALIGN_TO (offset, locals_stack_align);
838 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
839 if (offsets [i] != -1) {
840 MonoInst *inst = cfg->varinfo [i];
841 inst->opcode = OP_REGOFFSET;
842 inst->inst_basereg = cfg->frame_reg;
843 if (cfg->arch.omit_fp)
844 inst->inst_offset = (offset + offsets [i]);
846 inst->inst_offset = - (offset + offsets [i]);
847 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
851 offset += locals_stack_size;
853 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
854 if (cfg->arch.omit_fp)
855 g_assert_not_reached ();
856 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
857 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
860 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
861 inst = cfg->varinfo [i];
862 if (inst->opcode != OP_REGVAR) {
863 ArgInfo *ainfo = &cinfo->args [i];
864 gboolean inreg = TRUE;
867 if (sig->hasthis && (i == 0))
868 arg_type = &mono_defaults.object_class->byval_arg;
870 arg_type = sig->params [i - sig->hasthis];
872 /* FIXME: VOLATILE is only set if the liveness pass runs */
873 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
876 inst->opcode = OP_REGOFFSET;
878 switch (ainfo->storage) {
880 inst->opcode = OP_REGVAR;
881 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
885 * Since float regs are volatile, we save the arguments to
886 * the stack in the prolog.
891 if (cfg->arch.omit_fp)
892 g_assert_not_reached ();
893 inst->opcode = OP_REGOFFSET;
894 inst->inst_basereg = cfg->frame_reg;
895 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
904 if (!inreg && (ainfo->storage != ArgOnStack)) {
905 inst->opcode = OP_REGOFFSET;
906 inst->inst_basereg = cfg->frame_reg;
907 /* These arguments are saved to the stack in the prolog */
908 switch (ainfo->storage) {
910 if (ainfo->atype == AggregateSingleHFA)
911 offset += ainfo->nslots * 4;
913 offset += ainfo->nslots * 8;
916 offset += sizeof (gpointer);
919 offset = ALIGN_TO (offset, sizeof (gpointer));
920 if (cfg->arch.omit_fp)
921 inst->inst_offset = offset;
923 inst->inst_offset = - offset;
928 if (cfg->arch.omit_fp && offset == 16)
931 cfg->stack_offset = offset;
937 mono_arch_create_vars (MonoCompile *cfg)
939 MonoMethodSignature *sig;
942 sig = mono_method_signature (cfg->method);
944 cinfo = get_call_info (sig, FALSE);
946 if (cinfo->ret.storage == ArgAggregate)
947 cfg->ret_var_is_local = TRUE;
953 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
957 arg->opcode = OP_OUTARG_REG;
958 arg->inst_left = tree;
959 arg->inst_right = (MonoInst*)call;
961 call->used_iregs |= 1 << reg;
964 arg->opcode = OP_OUTARG_FREG;
965 arg->inst_left = tree;
966 arg->inst_right = (MonoInst*)call;
968 call->used_fregs |= 1 << reg;
971 g_assert_not_reached ();
976 * take the arguments and generate the arch-specific
977 * instructions to properly call the function in call.
978 * This includes pushing, moving arguments to the right register
980 * Issue: who does the spilling if needed, and when?
983 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
986 MonoMethodSignature *sig;
987 int i, n, stack_size;
993 mono_ia64_alloc_stacked_registers (cfg);
995 sig = call->signature;
996 n = sig->param_count + sig->hasthis;
998 cinfo = get_call_info (sig, sig->pinvoke);
1000 if (cinfo->ret.storage == ArgAggregate) {
1001 /* The code in emit_this_vret_arg needs a local */
1002 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1003 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1006 for (i = 0; i < n; ++i) {
1007 ainfo = cinfo->args + i;
1009 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1010 MonoMethodSignature *tmp_sig;
1012 /* Emit the signature cookie just before the implicit arguments */
1014 /* FIXME: Add support for signature tokens to AOT */
1015 cfg->disable_aot = TRUE;
1017 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1020 * mono_ArgIterator_Setup assumes the signature cookie is
1021 * passed first and all the arguments which were before it are
1022 * passed on the stack after the signature. So compensate by
1023 * passing a different signature.
1025 tmp_sig = mono_metadata_signature_dup (call->signature);
1026 tmp_sig->param_count -= call->signature->sentinelpos;
1027 tmp_sig->sentinelpos = 0;
1028 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1030 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1031 sig_arg->inst_p0 = tmp_sig;
1033 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1034 arg->inst_left = sig_arg;
1035 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1036 arg->type = STACK_PTR;
1038 /* prepend, so they get reversed */
1039 arg->next = call->out_args;
1040 call->out_args = arg;
1043 if (is_virtual && i == 0) {
1044 /* the argument will be attached to the call instruction */
1045 in = call->args [i];
1049 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1050 in = call->args [i];
1051 arg->cil_code = in->cil_code;
1052 arg->inst_left = in;
1053 arg->type = in->type;
1054 /* prepend, so they get reversed */
1055 arg->next = call->out_args;
1056 call->out_args = arg;
1058 if (sig->hasthis && (i == 0))
1059 arg_type = &mono_defaults.object_class->byval_arg;
1061 arg_type = sig->params [i - sig->hasthis];
1063 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1064 MonoInst *stack_addr;
1068 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1069 size = sizeof (MonoTypedRef);
1070 align = sizeof (gpointer);
1074 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1077 * Other backends use mono_type_stack_size (), but that
1078 * aligns the size to 8, which is larger than the size of
1079 * the source, leading to reads of invalid memory if the
1080 * source is at the end of address space.
1082 size = mono_class_value_size (in->klass, &align);
1085 if (ainfo->storage == ArgAggregate) {
1086 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1089 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1092 * Part of the structure is passed in registers.
1094 for (i = 0; i < ainfo->nregs; ++i) {
1095 int offset, load_op, dest_reg, arg_storage;
1097 slot = ainfo->reg + i;
1099 if (ainfo->atype == AggregateSingleHFA) {
1100 load_op = CEE_LDIND_R4;
1102 dest_reg = ainfo->reg + i;
1103 arg_storage = ArgInFloatReg;
1104 } else if (ainfo->atype == AggregateDoubleHFA) {
1105 load_op = CEE_LDIND_R8;
1107 dest_reg = ainfo->reg + i;
1108 arg_storage = ArgInFloatReg;
1110 load_op = CEE_LDIND_I;
1112 dest_reg = cfg->arch.reg_out0 + ainfo->reg + i;
1113 arg_storage = ArgInIReg;
1116 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1117 load->ssa_op = MONO_SSA_LOAD;
1118 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1120 NEW_ICONST (cfg, offset_ins, offset);
1121 MONO_INST_NEW (cfg, load2, CEE_ADD);
1122 load2->inst_left = load;
1123 load2->inst_right = offset_ins;
1125 MONO_INST_NEW (cfg, load, load_op);
1126 load->inst_left = load2;
1131 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1132 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1133 if (set_reg != call->out_args) {
1134 set_reg->next = call->out_args;
1135 call->out_args = set_reg;
1140 * Part of the structure is passed on the stack.
1142 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1145 slot = ainfo->reg + i;
1147 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1148 load->ssa_op = MONO_SSA_LOAD;
1149 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1151 NEW_ICONST (cfg, offset_ins, (i * sizeof (gpointer)));
1152 MONO_INST_NEW (cfg, load2, CEE_ADD);
1153 load2->inst_left = load;
1154 load2->inst_right = offset_ins;
1156 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1157 load->inst_left = load2;
1162 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1163 outarg->inst_left = load;
1164 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1166 if (outarg != call->out_args) {
1167 outarg->next = call->out_args;
1168 call->out_args = outarg;
1172 /* Trees can't be shared so make a copy */
1173 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1174 arg->cil_code = in->cil_code;
1175 arg->ssa_op = MONO_SSA_STORE;
1176 arg->inst_left = vtaddr;
1177 arg->inst_right = in;
1178 arg->type = in->type;
1180 /* prepend, so they get reversed */
1181 arg->next = call->out_args;
1182 call->out_args = arg;
1185 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1186 stack_addr->inst_basereg = IA64_SP;
1187 stack_addr->inst_offset = 16 + ainfo->offset;
1188 stack_addr->inst_imm = size;
1190 arg->opcode = OP_OUTARG_VT;
1191 arg->inst_right = stack_addr;
1195 switch (ainfo->storage) {
1197 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1200 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1203 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1204 arg->opcode = OP_OUTARG_R4;
1207 arg->opcode = OP_OUTARG;
1208 arg->inst_imm = 16 + ainfo->offset;
1211 g_assert_not_reached ();
1217 call->stack_usage = cinfo->stack_usage;
1218 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1219 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1220 cfg->flags |= MONO_CFG_HAS_CALLS;
1228 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1230 MonoInst *ins, *last_ins = NULL;
1234 switch (ins->opcode) {
1243 if (ins->dreg == ins->sreg1) {
1245 last_ins->next = ins->next;
1252 * OP_MOVE sreg, dreg
1253 * OP_MOVE dreg, sreg
1255 if (last_ins && last_ins->opcode == OP_MOVE &&
1256 ins->sreg1 == last_ins->dreg &&
1257 ins->dreg == last_ins->sreg1) {
1258 last_ins->next = ins->next;
1265 /* remove unnecessary multiplication with 1 */
1266 if (ins->inst_imm == 1) {
1267 if (ins->dreg != ins->sreg1) {
1268 ins->opcode = OP_MOVE;
1270 last_ins->next = ins->next;
1281 bb->last_ins = last_ins;
1304 opcode_to_cond (int opcode)
1313 case OP_COND_EXC_EQ:
1316 case OP_COND_EXC_NE_UN:
1329 case OP_COND_EXC_LT:
1337 case OP_COND_EXC_GT:
1346 case OP_COND_EXC_LE_UN:
1360 case OP_COND_EXC_LT_UN:
1363 case OP_COND_EXC_GT_UN:
1371 printf ("%s\n", mono_inst_name (opcode));
1377 opcode_to_type (int opcode, int cmp_opcode)
1379 if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1381 else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1383 else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLE_UN))
1385 else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1387 else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLE_UN))
1389 else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1391 else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
1392 switch (cmp_opcode) {
1394 case OP_ICOMPARE_IMM:
1400 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1405 int cond_to_ia64_cmp [][3] = {
1406 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1407 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1408 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1409 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1410 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1411 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1412 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1413 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1414 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1415 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1419 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1421 return cond_to_ia64_cmp [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1424 int cond_to_ia64_cmp_imm [][3] = {
1425 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1426 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1427 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1428 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1429 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1430 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1431 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1432 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1433 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1434 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1438 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1440 /* The condition needs to be reversed */
1441 return cond_to_ia64_cmp_imm [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1445 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1449 bb->code = to_insert;
1450 to_insert->next = ins;
1453 to_insert->next = ins->next;
1454 ins->next = to_insert;
1458 #define NEW_INS(cfg,dest,op) do { \
1459 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1460 (dest)->opcode = (op); \
1461 insert_after_ins (bb, last_ins, (dest)); \
1462 last_ins = (dest); \
1466 * mono_arch_lowering_pass:
1468 * Converts complex opcodes into simpler ones so that each IR instruction
1469 * corresponds to one machine instruction.
1472 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1474 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1477 if (bb->max_ireg > cfg->rs->next_vireg)
1478 cfg->rs->next_vireg = bb->max_ireg;
1479 if (bb->max_freg > cfg->rs->next_vfreg)
1480 cfg->rs->next_vfreg = bb->max_freg;
1483 switch (ins->opcode) {
1484 case OP_STOREI1_MEMBASE_IMM:
1485 case OP_STOREI2_MEMBASE_IMM:
1486 case OP_STOREI4_MEMBASE_IMM:
1487 case OP_STOREI8_MEMBASE_IMM:
1488 case OP_STORE_MEMBASE_IMM:
1489 /* There are no store_membase instructions on ia64 */
1490 if (ia64_is_imm14 (ins->inst_offset)) {
1491 NEW_INS (cfg, temp2, OP_ADD_IMM);
1492 temp2->sreg1 = ins->inst_destbasereg;
1493 temp2->inst_imm = ins->inst_offset;
1494 temp2->dreg = mono_regstate_next_int (cfg->rs);
1497 NEW_INS (cfg, temp, OP_I8CONST);
1498 temp->inst_c0 = ins->inst_offset;
1499 temp->dreg = mono_regstate_next_int (cfg->rs);
1500 NEW_INS (cfg, temp2, CEE_ADD);
1501 temp2->sreg1 = ins->inst_destbasereg;
1502 temp2->sreg2 = temp->dreg;
1503 temp2->dreg = mono_regstate_next_int (cfg->rs);
1506 switch (ins->opcode) {
1507 case OP_STOREI1_MEMBASE_IMM:
1508 ins->opcode = OP_STOREI1_MEMBASE_REG;
1510 case OP_STOREI2_MEMBASE_IMM:
1511 ins->opcode = OP_STOREI2_MEMBASE_REG;
1513 case OP_STOREI4_MEMBASE_IMM:
1514 ins->opcode = OP_STOREI4_MEMBASE_REG;
1516 case OP_STOREI8_MEMBASE_IMM:
1517 case OP_STORE_MEMBASE_IMM:
1518 ins->opcode = OP_STOREI8_MEMBASE_REG;
1521 g_assert_not_reached ();
1524 if (ins->inst_imm == 0)
1525 ins->sreg1 = IA64_R0;
1527 NEW_INS (cfg, temp3, OP_I8CONST);
1528 temp3->inst_c0 = ins->inst_imm;
1529 temp3->dreg = mono_regstate_next_int (cfg->rs);
1530 ins->sreg1 = temp3->dreg;
1533 ins->inst_offset = 0;
1534 ins->inst_destbasereg = temp2->dreg;
1536 case OP_STOREI1_MEMBASE_REG:
1537 case OP_STOREI2_MEMBASE_REG:
1538 case OP_STOREI4_MEMBASE_REG:
1539 case OP_STOREI8_MEMBASE_REG:
1540 case OP_STORER4_MEMBASE_REG:
1541 case OP_STORER8_MEMBASE_REG:
1542 case OP_STORE_MEMBASE_REG:
1543 /* There are no store_membase instructions on ia64 */
1544 if (ins->inst_offset == 0) {
1547 else if (ia64_is_imm14 (ins->inst_offset)) {
1548 NEW_INS (cfg, temp2, OP_ADD_IMM);
1549 temp2->sreg1 = ins->inst_destbasereg;
1550 temp2->inst_imm = ins->inst_offset;
1551 temp2->dreg = mono_regstate_next_int (cfg->rs);
1554 NEW_INS (cfg, temp, OP_I8CONST);
1555 temp->inst_c0 = ins->inst_offset;
1556 temp->dreg = mono_regstate_next_int (cfg->rs);
1557 NEW_INS (cfg, temp2, CEE_ADD);
1558 temp2->sreg1 = ins->inst_destbasereg;
1559 temp2->sreg2 = temp->dreg;
1560 temp2->dreg = mono_regstate_next_int (cfg->rs);
1563 ins->inst_offset = 0;
1564 ins->inst_destbasereg = temp2->dreg;
1566 case OP_LOADI1_MEMBASE:
1567 case OP_LOADU1_MEMBASE:
1568 case OP_LOADI2_MEMBASE:
1569 case OP_LOADU2_MEMBASE:
1570 case OP_LOADI4_MEMBASE:
1571 case OP_LOADU4_MEMBASE:
1572 case OP_LOADI8_MEMBASE:
1573 case OP_LOAD_MEMBASE:
1574 case OP_LOADR4_MEMBASE:
1575 case OP_LOADR8_MEMBASE:
1576 /* There are no load_membase instructions on ia64 */
1577 if (ins->inst_offset == 0) {
1580 else if (ia64_is_imm14 (ins->inst_offset)) {
1581 NEW_INS (cfg, temp2, OP_ADD_IMM);
1582 temp2->sreg1 = ins->inst_basereg;
1583 temp2->inst_imm = ins->inst_offset;
1584 temp2->dreg = mono_regstate_next_int (cfg->rs);
1587 NEW_INS (cfg, temp, OP_I8CONST);
1588 temp->inst_c0 = ins->inst_offset;
1589 temp->dreg = mono_regstate_next_int (cfg->rs);
1590 NEW_INS (cfg, temp2, CEE_ADD);
1591 temp2->sreg1 = ins->inst_basereg;
1592 temp2->sreg2 = temp->dreg;
1593 temp2->dreg = mono_regstate_next_int (cfg->rs);
1596 ins->inst_offset = 0;
1597 ins->inst_basereg = temp2->dreg;
1611 case OP_ISHR_UN_IMM:
1612 case OP_LSHR_UN_IMM: {
1613 gboolean is_imm = FALSE;
1614 gboolean switched = FALSE;
1616 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1617 ins->opcode = OP_ZEXT_I1;
1621 switch (ins->opcode) {
1624 is_imm = ia64_is_imm14 (ins->inst_imm);
1628 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1630 /* A = B - IMM -> A = B + (-IMM) */
1631 ins->inst_imm = - ins->inst_imm;
1632 ins->opcode = OP_IADD_IMM;
1640 is_imm = ia64_is_imm8 (ins->inst_imm);
1648 case OP_ISHR_UN_IMM:
1649 case OP_LSHR_UN_IMM:
1650 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1658 ins->sreg2 = ins->sreg1;
1662 switch (ins->opcode) {
1664 ins->opcode = CEE_ADD;
1667 ins->opcode = OP_IADD;
1670 ins->opcode = OP_ISUB;
1673 ins->opcode = OP_IAND;
1676 ins->opcode = OP_IOR;
1679 ins->opcode = OP_IXOR;
1682 ins->opcode = OP_ISHL;
1685 ins->opcode = OP_ISHR;
1687 case OP_ISHR_UN_IMM:
1688 ins->opcode = OP_ISHR_UN;
1691 ins->opcode = CEE_AND;
1694 ins->opcode = OP_LSHL;
1697 ins->opcode = OP_LSHL;
1700 ins->opcode = OP_LSHR;
1702 case OP_LSHR_UN_IMM:
1703 ins->opcode = OP_LSHR_UN;
1706 g_assert_not_reached ();
1709 if (ins->inst_imm == 0)
1710 ins->sreg2 = IA64_R0;
1712 NEW_INS (cfg, temp, OP_I8CONST);
1713 temp->inst_c0 = ins->inst_imm;
1714 temp->dreg = mono_regstate_next_int (cfg->rs);
1715 ins->sreg2 = temp->dreg;
1719 case OP_COMPARE_IMM:
1720 case OP_ICOMPARE_IMM: {
1721 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1725 * The compare_imm instructions have switched up arguments, and
1726 * some of them take an imm between -127 and 128.
1729 switch (next->opcode) {
1732 case OP_COND_EXC_LT:
1735 imm = ia64_is_imm8 (ins->inst_imm - 1);
1741 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1744 imm = ia64_is_imm8 (ins->inst_imm);
1749 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1750 ins->sreg2 = ins->sreg1;
1753 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1755 if (ins->inst_imm == 0)
1756 ins->sreg2 = IA64_R0;
1758 NEW_INS (cfg, temp, OP_I8CONST);
1759 temp->inst_c0 = ins->inst_imm;
1760 temp->dreg = mono_regstate_next_int (cfg->rs);
1761 ins->sreg2 = temp->dreg;
1765 switch (next->opcode) {
1786 next->opcode = OP_IA64_BR_COND;
1787 if (! (next->flags & MONO_INST_BRLABEL))
1788 next->inst_target_bb = next->inst_true_bb;
1790 case OP_COND_EXC_EQ:
1791 case OP_COND_EXC_GT:
1792 case OP_COND_EXC_LT:
1793 case OP_COND_EXC_GT_UN:
1794 case OP_COND_EXC_LE_UN:
1795 case OP_COND_EXC_NE_UN:
1796 case OP_COND_EXC_LT_UN:
1797 next->opcode = OP_IA64_COND_EXC;
1809 next->opcode = OP_IA64_CSET;
1812 printf ("%s\n", mono_inst_name (next->opcode));
1822 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1826 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1827 switch (next->opcode) {
1858 next->opcode = OP_IA64_BR_COND;
1859 if (! (next->flags & MONO_INST_BRLABEL))
1860 next->inst_target_bb = next->inst_true_bb;
1862 case OP_COND_EXC_LT:
1863 case OP_COND_EXC_GT:
1864 case OP_COND_EXC_GT_UN:
1865 case OP_COND_EXC_LE_UN:
1866 next->opcode = OP_IA64_COND_EXC;
1883 next->opcode = OP_IA64_CSET;
1886 printf ("%s\n", mono_inst_name (next->opcode));
1894 gboolean found = FALSE;
1895 int shl_op = ins->opcode == OP_MUL_IMM ? OP_SHL_IMM : OP_ISHL_IMM;
1897 /* First the easy cases */
1898 if (ins->inst_imm == 1) {
1899 ins->opcode = OP_MOVE;
1902 for (i = 1; i < 64; ++i)
1903 if (ins->inst_imm == (((gint64)1) << i)) {
1904 ins->opcode = shl_op;
1910 /* This could be optimized */
1913 for (i = 0; i < 64; ++i) {
1914 if (ins->inst_imm & (((gint64)1) << i)) {
1915 NEW_INS (cfg, temp, shl_op);
1916 temp->dreg = mono_regstate_next_int (cfg->rs);
1917 temp->sreg1 = ins->sreg1;
1921 sum_reg = temp->dreg;
1923 NEW_INS (cfg, temp2, CEE_ADD);
1924 temp2->dreg = mono_regstate_next_int (cfg->rs);
1925 temp2->sreg1 = sum_reg;
1926 temp2->sreg2 = temp->dreg;
1927 sum_reg = temp2->dreg;
1931 ins->opcode = OP_MOVE;
1932 ins->sreg1 = sum_reg;
1936 case CEE_CONV_OVF_U4:
1937 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1938 temp->sreg1 = ins->sreg1;
1939 temp->sreg2 = IA64_R0;
1941 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1942 temp->inst_p1 = (char*)"OverflowException";
1944 ins->opcode = OP_MOVE;
1946 case CEE_CONV_OVF_I4_UN:
1947 NEW_INS (cfg, temp, OP_ICONST);
1948 temp->inst_c0 = 0x7fffffff;
1949 temp->dreg = mono_regstate_next_int (cfg->rs);
1951 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1952 temp2->sreg1 = ins->sreg1;
1953 temp2->sreg2 = temp->dreg;
1955 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1956 temp->inst_p1 = (char*)"OverflowException";
1958 ins->opcode = OP_MOVE;
1960 case OP_FCONV_TO_I4:
1961 case OP_FCONV_TO_I2:
1962 case OP_FCONV_TO_U2:
1963 case OP_FCONV_TO_I1:
1964 case OP_FCONV_TO_U1:
1965 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1966 temp->sreg1 = ins->sreg1;
1967 temp->dreg = ins->dreg;
1969 switch (ins->opcode) {
1970 case OP_FCONV_TO_I4:
1971 ins->opcode = OP_SEXT_I4;
1973 case OP_FCONV_TO_I2:
1974 ins->opcode = OP_SEXT_I2;
1976 case OP_FCONV_TO_U2:
1977 ins->opcode = OP_ZEXT_I4;
1979 case OP_FCONV_TO_I1:
1980 ins->opcode = OP_SEXT_I1;
1982 case OP_FCONV_TO_U1:
1983 ins->opcode = OP_ZEXT_I1;
1986 g_assert_not_reached ();
1988 ins->sreg1 = ins->dreg;
1996 bb->last_ins = last_ins;
1998 bb->max_ireg = cfg->rs->next_vireg;
1999 bb->max_freg = cfg->rs->next_vfreg;
2003 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
2008 mono_arch_lowering_pass (cfg, bb);
2010 mono_local_regalloc (cfg, bb);
2014 * emit_load_volatile_arguments:
2016 * Load volatile arguments from the stack to the original input registers.
2017 * Required before a tail call.
2019 static Ia64CodegenState
2020 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
2022 MonoMethod *method = cfg->method;
2023 MonoMethodSignature *sig;
2028 /* FIXME: Generate intermediate code instead */
2030 sig = mono_method_signature (method);
2032 cinfo = get_call_info (sig, FALSE);
2034 /* This is the opposite of the code in emit_prolog */
2035 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2036 ArgInfo *ainfo = cinfo->args + i;
2037 gint32 stack_offset;
2039 ins = cfg->varinfo [i];
2041 if (sig->hasthis && (i == 0))
2042 arg_type = &mono_defaults.object_class->byval_arg;
2044 arg_type = sig->params [i - sig->hasthis];
2046 arg_type = mono_type_get_underlying_type (arg_type);
2048 stack_offset = ainfo->offset + ARGS_OFFSET;
2050 /* Save volatile arguments to the stack */
2051 if (ins->opcode != OP_REGVAR) {
2052 switch (ainfo->storage) {
2055 /* FIXME: big offsets */
2056 g_assert (ins->opcode == OP_REGOFFSET);
2057 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2058 if (arg_type->byref)
2059 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2061 switch (arg_type->type) {
2063 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
2066 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
2069 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2081 if (ins->opcode == OP_REGVAR) {
2082 /* Argument allocated to (non-volatile) register */
2083 switch (ainfo->storage) {
2085 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
2086 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
2089 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
2090 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2103 static Ia64CodegenState
2104 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2109 /* Move return value to the target register */
2110 switch (ins->opcode) {
2112 case OP_VOIDCALL_REG:
2113 case OP_VOIDCALL_MEMBASE:
2117 case OP_CALL_MEMBASE:
2120 case OP_LCALL_MEMBASE:
2121 g_assert (ins->dreg == IA64_R8);
2125 case OP_FCALL_MEMBASE:
2126 g_assert (ins->dreg == 8);
2130 case OP_VCALL_MEMBASE:
2131 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
2132 ArgStorage storage = cinfo->ret.storage;
2134 if (storage == ArgAggregate) {
2135 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2137 /* Load address of stack space allocated for the return value */
2138 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2139 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2140 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2142 for (i = 0; i < cinfo->ret.nregs; ++i) {
2143 switch (cinfo->ret.atype) {
2144 case AggregateNormal:
2145 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2147 case AggregateSingleHFA:
2148 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2150 case AggregateDoubleHFA:
2151 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2154 g_assert_not_reached ();
2161 g_assert_not_reached ();
2167 #define add_patch_info(cfg,code,patch_type,data) do { \
2168 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2171 static Ia64CodegenState
2172 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2174 add_patch_info (cfg, code, patch_type, data);
2176 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2178 /* mono_arch_nullify_class_init_trampoline will patch this */
2179 ia64_movl (code, GP_SCRATCH_REG, 0);
2180 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2181 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2182 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2183 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2186 /* Can't use a direct call since the displacement might be too small */
2187 /* mono_arch_patch_callsite will patch this */
2188 ia64_movl (code, GP_SCRATCH_REG, 0);
2189 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2190 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2196 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2199 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2204 Ia64CodegenState code;
2205 guint8 *code_start = cfg->native_code + cfg->code_len;
2206 MonoInst *last_ins = NULL;
2207 guint last_offset = 0;
2210 if (cfg->opt & MONO_OPT_PEEPHOLE)
2211 peephole_pass (cfg, bb);
2213 if (cfg->opt & MONO_OPT_LOOP) {
2217 if (cfg->verbose_level > 2)
2218 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2220 cpos = bb->max_offset;
2222 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2226 offset = code_start - cfg->native_code;
2228 ia64_codegen_init (code, code_start);
2231 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2237 offset = code.buf - cfg->native_code;
2239 max_len = ((int)(((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN])) + 128;
2241 while (offset + max_len + 16 > cfg->code_size) {
2242 ia64_codegen_close (code);
2244 offset = code.buf - cfg->native_code;
2246 cfg->code_size *= 2;
2247 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2248 code_start = cfg->native_code + offset;
2249 mono_jit_stats.code_reallocs++;
2251 ia64_codegen_init (code, code_start);
2254 mono_debug_record_line_number (cfg, ins, offset);
2256 switch (ins->opcode) {
2259 if (ia64_is_imm14 (ins->inst_c0))
2260 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2262 ia64_movl (code, ins->dreg, ins->inst_c0);
2265 ia64_mov (code, ins->dreg, ins->sreg1);
2268 case OP_IA64_BR_COND: {
2270 if (ins->opcode == OP_IA64_BR_COND)
2272 if (ins->flags & MONO_INST_BRLABEL) {
2273 if (ins->inst_i0->inst_c0) {
2276 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2277 ia64_br_cond_pred (code, pred, 0);
2280 if (ins->inst_target_bb->native_offset) {
2281 guint8 *pos = code.buf + code.nins;
2283 ia64_br_cond_pred (code, pred, 0);
2284 ia64_begin_bundle (code);
2285 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2287 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2288 ia64_br_cond_pred (code, pred, 0);
2294 ia64_begin_bundle (code);
2295 ins->inst_c0 = code.buf - cfg->native_code;
2300 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2301 ia64_br_cond_reg (code, IA64_B6);
2305 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2309 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2313 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2317 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2321 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2325 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2328 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2332 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2335 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2336 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2340 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2343 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2347 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2350 /* p6 and p7 is set if there is signed/unsigned overflow */
2352 /* Set p8-p9 == (sreg2 > 0) */
2353 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2355 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2357 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2358 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2359 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2360 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2362 /* res <u sreg1 => unsigned overflow */
2363 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2365 /* FIXME: Predicate this since this is a side effect */
2366 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2369 /* p6 and p7 is set if there is signed/unsigned overflow */
2371 /* Set p8-p9 == (sreg2 > 0) */
2372 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2374 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2376 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2377 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2378 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2379 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2381 /* sreg1 <u sreg2 => unsigned overflow */
2382 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2384 /* FIXME: Predicate this since this is a side effect */
2385 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2388 /* Same as OP_IADDCC */
2389 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2391 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2393 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2394 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2396 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2398 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2401 /* Same as OP_ISUBCC */
2403 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2405 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2407 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2408 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2410 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2412 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2416 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2420 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2423 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2426 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2431 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2434 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2437 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2439 case OP_ISHR_UN_IMM:
2440 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2441 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2443 case OP_LSHR_UN_IMM:
2444 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2447 case OP_STOREI1_MEMBASE_REG:
2448 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2450 case OP_STOREI2_MEMBASE_REG:
2451 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2453 case OP_STOREI4_MEMBASE_REG:
2454 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2456 case OP_STOREI8_MEMBASE_REG:
2457 case OP_STORE_MEMBASE_REG:
2458 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2461 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2462 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2464 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2465 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2467 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2468 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2470 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2471 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2474 case OP_LOADU1_MEMBASE:
2475 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2477 case OP_LOADU2_MEMBASE:
2478 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2480 case OP_LOADU4_MEMBASE:
2481 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2483 case OP_LOADI1_MEMBASE:
2484 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2485 ia64_sxt1 (code, ins->dreg, ins->dreg);
2487 case OP_LOADI2_MEMBASE:
2488 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2489 ia64_sxt2 (code, ins->dreg, ins->dreg);
2491 case OP_LOADI4_MEMBASE:
2492 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2493 ia64_sxt4 (code, ins->dreg, ins->dreg);
2495 case OP_LOAD_MEMBASE:
2496 case OP_LOADI8_MEMBASE:
2497 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2500 case OP_IA64_LOADU1_MEMBASE_INC:
2501 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2503 case OP_IA64_LOADU2_MEMBASE_INC:
2504 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2506 case OP_IA64_LOADU4_MEMBASE_INC:
2507 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2509 case OP_IA64_LOADI8_MEMBASE_INC:
2510 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2514 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2517 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2520 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2523 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2526 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2529 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2532 /* Compare opcodes */
2533 case OP_IA64_CMP4_EQ:
2534 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2536 case OP_IA64_CMP4_NE:
2537 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2539 case OP_IA64_CMP4_LE:
2540 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2542 case OP_IA64_CMP4_LT:
2543 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2545 case OP_IA64_CMP4_GE:
2546 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2548 case OP_IA64_CMP4_GT:
2549 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2551 case OP_IA64_CMP4_LT_UN:
2552 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2554 case OP_IA64_CMP4_LE_UN:
2555 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2557 case OP_IA64_CMP4_GT_UN:
2558 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2560 case OP_IA64_CMP4_GE_UN:
2561 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2563 case OP_IA64_CMP_EQ:
2564 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2566 case OP_IA64_CMP_NE:
2567 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2569 case OP_IA64_CMP_LE:
2570 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2572 case OP_IA64_CMP_LT:
2573 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2575 case OP_IA64_CMP_GE:
2576 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2578 case OP_IA64_CMP_GT:
2579 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2581 case OP_IA64_CMP_GT_UN:
2582 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2584 case OP_IA64_CMP_LT_UN:
2585 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2587 case OP_IA64_CMP_GE_UN:
2588 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2590 case OP_IA64_CMP_LE_UN:
2591 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2593 case OP_IA64_CMP4_EQ_IMM:
2594 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2596 case OP_IA64_CMP4_NE_IMM:
2597 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2599 case OP_IA64_CMP4_LE_IMM:
2600 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2602 case OP_IA64_CMP4_LT_IMM:
2603 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2605 case OP_IA64_CMP4_GE_IMM:
2606 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2608 case OP_IA64_CMP4_GT_IMM:
2609 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2611 case OP_IA64_CMP4_LT_UN_IMM:
2612 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2614 case OP_IA64_CMP4_LE_UN_IMM:
2615 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2617 case OP_IA64_CMP4_GT_UN_IMM:
2618 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2620 case OP_IA64_CMP4_GE_UN_IMM:
2621 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2623 case OP_IA64_CMP_EQ_IMM:
2624 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2626 case OP_IA64_CMP_NE_IMM:
2627 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2629 case OP_IA64_CMP_LE_IMM:
2630 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2632 case OP_IA64_CMP_LT_IMM:
2633 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2635 case OP_IA64_CMP_GE_IMM:
2636 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2638 case OP_IA64_CMP_GT_IMM:
2639 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2641 case OP_IA64_CMP_GT_UN_IMM:
2642 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2644 case OP_IA64_CMP_LT_UN_IMM:
2645 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2647 case OP_IA64_CMP_GE_UN_IMM:
2648 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2650 case OP_IA64_CMP_LE_UN_IMM:
2651 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2653 case OP_IA64_FCMP_EQ:
2654 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2656 case OP_IA64_FCMP_NE:
2657 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2659 case OP_IA64_FCMP_LT:
2660 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2662 case OP_IA64_FCMP_GT:
2663 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2665 case OP_IA64_FCMP_LE:
2666 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2668 case OP_IA64_FCMP_GE:
2669 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2671 case OP_IA64_FCMP_GT_UN:
2672 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2673 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2675 case OP_IA64_FCMP_LT_UN:
2676 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2677 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2679 case OP_IA64_FCMP_GE_UN:
2680 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2681 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2683 case OP_IA64_FCMP_LE_UN:
2684 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2685 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2688 case OP_COND_EXC_IOV:
2689 case OP_COND_EXC_OV:
2690 add_patch_info (cfg, code,
2691 MONO_PATCH_INFO_EXC, "OverflowException");
2692 ia64_br_cond_pred (code, 6, 0);
2694 case OP_COND_EXC_IC:
2696 add_patch_info (cfg, code,
2697 MONO_PATCH_INFO_EXC, "OverflowException");
2698 ia64_br_cond_pred (code, 7, 0);
2700 case OP_IA64_COND_EXC:
2701 add_patch_info (cfg, code,
2702 MONO_PATCH_INFO_EXC, ins->inst_p1);
2703 ia64_br_cond_pred (code, 6, 0);
2706 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2707 ia64_no_stop (code);
2708 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2711 /* FIXME: Is this needed ? */
2712 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2715 /* FIXME: Is this needed ? */
2716 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2719 /* FIXME: Is this needed ? */
2720 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2723 /* FIXME: Is this needed */
2724 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2727 /* FIXME: Is this needed */
2728 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2731 /* FIXME: Is this needed */
2732 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2736 /* FIXME: Sign extend ? */
2737 ia64_mov (code, ins->dreg, ins->sreg1);
2741 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2748 double d = *(double *)ins->inst_p0;
2750 if ((d == 0.0) && (mono_signbit (d) == 0))
2751 ia64_fmov (code, ins->dreg, 0);
2753 ia64_fmov (code, ins->dreg, 1);
2755 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2756 ia64_movl (code, GP_SCRATCH_REG, 0);
2757 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2762 float f = *(float *)ins->inst_p0;
2764 if ((f == 0.0) && (mono_signbit (f) == 0))
2765 ia64_fmov (code, ins->dreg, 0);
2767 ia64_fmov (code, ins->dreg, 1);
2769 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2770 ia64_movl (code, GP_SCRATCH_REG, 0);
2771 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2776 ia64_fmov (code, ins->dreg, ins->sreg1);
2778 case OP_STORER8_MEMBASE_REG:
2779 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2781 case OP_STORER4_MEMBASE_REG:
2782 ia64_stfs_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2784 case OP_LOADR8_MEMBASE:
2785 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2787 case OP_LOADR4_MEMBASE:
2788 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2791 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2792 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2793 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2796 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2797 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2798 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2800 case OP_LCONV_TO_R8:
2801 /* FIXME: Difference with CEE_CONV_R8 ? */
2802 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2803 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2804 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2806 case OP_LCONV_TO_R4:
2807 /* FIXME: Difference with CEE_CONV_R4 ? */
2808 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2809 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2810 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2812 case OP_FCONV_TO_R4:
2813 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2815 case OP_FCONV_TO_I8:
2816 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2817 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2820 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2823 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2826 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2829 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2833 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2834 add_patch_info (cfg, code,
2835 MONO_PATCH_INFO_EXC, "ArithmeticException");
2836 ia64_br_cond_pred (code, 6, 0);
2838 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2839 add_patch_info (cfg, code,
2840 MONO_PATCH_INFO_EXC, "ArithmeticException");
2841 ia64_br_cond_pred (code, 6, 0);
2842 /* Positive infinity */
2843 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2844 add_patch_info (cfg, code,
2845 MONO_PATCH_INFO_EXC, "ArithmeticException");
2846 ia64_br_cond_pred (code, 6, 0);
2847 /* Negative infinity */
2848 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2849 add_patch_info (cfg, code,
2850 MONO_PATCH_INFO_EXC, "ArithmeticException");
2851 ia64_br_cond_pred (code, 6, 0);
2856 /* ensure ins->sreg1 is not NULL */
2857 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2860 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2861 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2868 call = (MonoCallInst*)ins;
2870 if (ins->flags & MONO_INST_HAS_METHOD)
2871 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2873 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2875 code = emit_move_return_value (cfg, ins, code);
2882 case OP_VOIDCALL_REG:
2883 call = (MonoCallInst*)ins;
2887 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2890 ia64_mov (code, IA64_R8, ins->sreg1);
2891 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2892 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2893 ia64_ld8 (code, IA64_GP, IA64_R8);
2894 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2896 code = emit_move_return_value (cfg, ins, code);
2899 case OP_FCALL_MEMBASE:
2900 case OP_LCALL_MEMBASE:
2901 case OP_VCALL_MEMBASE:
2902 case OP_VOIDCALL_MEMBASE:
2903 case OP_CALL_MEMBASE:
2905 * There are no membase instructions on ia64, but we can't
2906 * lower this since get_vcall_slot_addr () needs to decode it.
2909 /* Keep this in synch with get_vcall_slot_addr */
2910 if (ia64_is_imm14 (ins->inst_offset))
2911 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2913 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2914 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2917 ia64_begin_bundle (code);
2918 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2920 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2922 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2925 * This nop will tell get_vcall_slot_addr that this is a virtual
2928 ia64_nop_i (code, 0x12345);
2930 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2932 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2934 code = emit_move_return_value (cfg, ins, code);
2938 * Keep in sync with the code in emit_epilog.
2941 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2944 g_assert (!cfg->method->save_lmf);
2946 /* Load arguments into their original registers */
2947 code = emit_load_volatile_arguments (cfg, code);
2949 if (cfg->arch.stack_alloc_size) {
2950 if (cfg->arch.omit_fp) {
2951 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2952 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2954 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2955 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2959 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2961 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2962 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2964 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2965 ia64_movl (code, GP_SCRATCH_REG, 0);
2966 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2967 ia64_br_cond_reg (code, IA64_B6);
2975 /* keep alignment */
2976 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->sreg1);
2977 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_FRAME_ALIGNMENT - 1));
2978 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2980 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2982 ia64_mov (code, ins->dreg, IA64_SP);
2984 /* An area at sp is reserved by the ABI for parameter passing */
2985 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
2986 if (ia64_is_adds_imm (abi_offset))
2987 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2989 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2990 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2993 if (ins->flags & MONO_INST_INIT) {
2995 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2997 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3000 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3001 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3002 ia64_br_cond_pred (code, 8, -2);
3004 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3006 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3012 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
3013 ia64_ld8 (code, ins->dreg, ins->dreg);
3016 /* Exception handling */
3017 case OP_CALL_HANDLER:
3019 * Using a call instruction would mess up the register stack, so
3020 * save the return address to a register and use a
3023 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3024 ia64_mov (code, IA64_R15, IA64_R0);
3025 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3026 /* Add the length of OP_CALL_HANDLER */
3027 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3028 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3029 ia64_movl (code, GP_SCRATCH_REG2, 0);
3030 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3031 ia64_br_cond_reg (code, IA64_B6);
3032 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3034 case OP_START_HANDLER: {
3036 * We receive the return address in GP_SCRATCH_REG.
3038 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3041 * We might be called by call_filter, in which case the
3042 * the register stack is not set up correctly. So do it now.
3043 * Allocate a stack frame and set the fp register from the value
3044 * passed in by the caller.
3045 * R15 is used since it is writable using libunwind.
3046 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3048 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3049 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3050 /* Alloc is not predictable so we have to use a branch */
3051 ia64_br_cond_pred (code, 6, 3);
3052 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);
3053 ia64_mov (code, cfg->frame_reg, IA64_R15);
3054 /* Save the return address */
3055 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3056 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3057 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3061 case CEE_ENDFINALLY: {
3062 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3063 /* Return the saved arp_pfs value to call_filter */
3064 ia64_mov (code, IA64_R9, cfg->arch.reg_saved_ar_pfs);
3065 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3066 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3067 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3068 ia64_br_cond_reg (code, IA64_B6);
3071 case OP_ENDFILTER: {
3072 /* FIXME: Return the value */
3073 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3074 /* Return the saved arp_pfs value to call_filter */
3075 ia64_mov (code, IA64_R9, cfg->arch.reg_saved_ar_pfs);
3076 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3077 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3078 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3079 ia64_br_cond_reg (code, IA64_B6);
3083 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3084 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3085 (gpointer)"mono_arch_throw_exception");
3088 * This might be the last instruction in the method, so add a dummy
3089 * instruction so the unwinder will work.
3091 ia64_break_i (code, 0);
3094 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3095 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3096 (gpointer)"mono_arch_rethrow_exception");
3098 ia64_break_i (code, 0);
3102 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3103 g_assert_not_reached ();
3106 if ((code.buf - cfg->native_code - offset) > max_len) {
3107 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3108 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3109 g_assert_not_reached ();
3115 last_offset = offset;
3120 ia64_codegen_close (code);
3122 cfg->code_len = code.buf - cfg->native_code;
3126 mono_arch_register_lowlevel_calls (void)
3128 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3131 static Ia64InsType ins_types_in_template [32][3] = {
3132 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3133 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3134 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3135 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3136 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3137 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3140 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3141 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3142 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3143 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3144 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3145 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3146 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3147 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3148 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3149 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3150 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3151 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3154 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3155 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3156 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3157 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3160 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3161 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3166 static gboolean stops_in_template [32][3] = {
3167 { FALSE, FALSE, FALSE },
3168 { FALSE, FALSE, TRUE },
3169 { FALSE, TRUE, FALSE },
3170 { FALSE, TRUE, TRUE },
3171 { FALSE, FALSE, FALSE },
3172 { FALSE, FALSE, TRUE },
3173 { FALSE, FALSE, FALSE },
3174 { FALSE, FALSE, FALSE },
3176 { FALSE, FALSE, FALSE },
3177 { FALSE, FALSE, TRUE },
3178 { TRUE, FALSE, FALSE },
3179 { TRUE, FALSE, TRUE },
3180 { FALSE, FALSE, FALSE },
3181 { FALSE, FALSE, TRUE },
3182 { FALSE, FALSE, FALSE },
3183 { FALSE, FALSE, TRUE },
3185 { FALSE, FALSE, FALSE },
3186 { FALSE, FALSE, TRUE },
3187 { FALSE, FALSE, FALSE },
3188 { FALSE, FALSE, TRUE },
3189 { FALSE, FALSE, FALSE },
3190 { FALSE, FALSE, FALSE },
3191 { FALSE, FALSE, FALSE },
3192 { FALSE, FALSE, TRUE },
3194 { FALSE, FALSE, FALSE },
3195 { FALSE, FALSE, TRUE },
3196 { FALSE, FALSE, FALSE },
3197 { FALSE, FALSE, FALSE },
3198 { FALSE, FALSE, FALSE },
3199 { FALSE, FALSE, TRUE },
3200 { FALSE, FALSE, FALSE },
3201 { FALSE, FALSE, FALSE }
3204 static int last_stop_in_template [32] = {
3205 -1, 2, 1, 2, -1, 2, -1, -1,
3206 -1, 2, 0, 2, -1, 2, -1, 2,
3207 -1, 2, -1, 2, -1, -1, -1, 2,
3208 -1, 2, -1, -1, -1, 2, -1, -1
3211 static guint64 nops_for_ins_types [6] = {
3220 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3227 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3229 #define DEBUG_INS_SCHED(a)
3233 ia64_emit_bundle_manual (Ia64CodegenState *code)
3235 int j, ins_type, template;
3237 if (code->nins == 0)
3240 g_assert (code->nins == 3 || ((code->nins == 2) && code->itypes [1] == IA64_INS_TYPE_LX));
3242 /* Verify template is correct */
3243 template = code->template;
3244 for (j = 0; j < 3; ++j) {
3245 if (code->stops [j])
3246 g_assert (stops_in_template [template]);
3248 ins_type = ins_types_in_template [template][j];
3249 switch (code->itypes [j]) {
3250 case IA64_INS_TYPE_A:
3251 g_assert ((ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M));
3253 case IA64_INS_TYPE_LX:
3255 g_assert (ins_type == IA64_INS_TYPE_LX);
3259 g_assert (ins_type == code->itypes [j]);
3263 ia64_emit_bundle_template (code, template, code->instructions [0], code->instructions [1], code->instructions [2]);
3266 code->dep_info_pos = 0;
3270 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start)
3272 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3273 guint8 *deps = code->dep_info;
3274 gboolean need_stop, no_stop;
3276 for (i = 0; i < code->nins; ++i)
3277 code->stops [i] = FALSE;
3280 current_deps_start = 0;
3281 current_ins_start = 0;
3282 deps_start [ins_index] = current_ins_start;
3285 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3286 while (pos < code->dep_info_pos) {
3288 switch (deps [pos]) {
3289 case IA64_END_OF_INS:
3291 current_ins_start = pos + 2;
3292 deps_start [ins_index] = current_ins_start;
3294 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3299 reg = deps [pos + 1];
3301 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3302 for (i = current_deps_start; i < current_ins_start; i += 2)
3303 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3307 reg = code->dep_info [pos + 1];
3309 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3310 for (i = current_deps_start; i < current_ins_start; i += 2)
3311 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3315 reg = deps [pos + 1];
3317 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3318 for (i = current_deps_start; i < current_ins_start; i += 2)
3319 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3322 case IA64_READ_PR_BRANCH:
3323 reg = deps [pos + 1];
3325 /* Writes to prs by non-float instructions are visible to branches */
3326 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3327 for (i = current_deps_start; i < current_ins_start; i += 2)
3328 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3332 reg = code->dep_info [pos + 1];
3334 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3335 for (i = current_deps_start; i < current_ins_start; i += 2)
3336 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3339 case IA64_WRITE_PR_FLOAT:
3340 reg = code->dep_info [pos + 1];
3342 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3343 for (i = current_deps_start; i < current_ins_start; i += 2)
3344 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3348 reg = deps [pos + 1];
3350 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3351 for (i = current_deps_start; i < current_ins_start; i += 2)
3352 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3356 reg = code->dep_info [pos + 1];
3358 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3359 for (i = current_deps_start; i < current_ins_start; i += 2)
3360 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3363 case IA64_READ_BR_BRANCH:
3364 reg = deps [pos + 1];
3366 /* Writes to brs are visible to branches */
3367 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3370 reg = deps [pos + 1];
3372 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3373 for (i = current_deps_start; i < current_ins_start; i += 2)
3374 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3378 reg = code->dep_info [pos + 1];
3380 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3381 for (i = current_deps_start; i < current_ins_start; i += 2)
3382 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3386 reg = deps [pos + 1];
3388 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3389 for (i = current_deps_start; i < current_ins_start; i += 2)
3390 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3394 reg = code->dep_info [pos + 1];
3396 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3397 for (i = current_deps_start; i < current_ins_start; i += 2)
3398 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3403 * Explicitly indicate that a stop is not required. Useful for
3404 * example when two predicated instructions with negated predicates
3405 * write the same registers.
3410 g_assert_not_reached ();
3414 if (need_stop && !no_stop) {
3415 g_assert (ins_index > 0);
3416 code->stops [ins_index - 1] = 1;
3418 DEBUG_INS_SCHED (printf ("STOP\n"));
3419 current_deps_start = current_ins_start;
3421 /* Skip remaining deps for this instruction */
3422 while (deps [pos] != IA64_END_OF_INS)
3427 if (code->nins > 0) {
3428 /* No dependency info for the last instruction */
3429 code->stops [code->nins - 1] = 1;
3432 deps_start [code->nins] = code->dep_info_pos;
3436 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3438 g_assert (n <= code->nins);
3439 int stop_pos, i, deps_to_shift, dep_shift;
3441 // if (n > 1) printf ("FOUND: %ld.\n", template);
3443 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3445 stop_pos = last_stop_in_template [template] + 1;
3449 /* Compute the number of 'real' instructions before the stop */
3450 deps_to_shift = stop_pos;
3451 if (stop_pos >= 3 && (nops & (1 << 2)))
3453 if (stop_pos >= 2 && (nops & (1 << 1)))
3455 if (stop_pos >= 1 && (nops & (1 << 0)))
3459 * We have to keep some dependencies whose instructions have been shifted
3460 * out of the buffer. So nullify the end_of_ins markers in the dependency
3463 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3464 if (code->dep_info [i] == IA64_END_OF_INS)
3465 code->dep_info [i] = IA64_NONE;
3467 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3468 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3469 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3471 dep_shift = deps_start [deps_to_shift];
3472 for (i = 0; i < code->nins + 1 - n; ++i)
3473 deps_start [i] = deps_start [n + i] - dep_shift;
3475 if (n == code->nins) {
3480 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3481 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3482 memcpy (&code->stops [0], &code->stops [n], (code->nins - n) * sizeof (int));
3488 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3490 int i, ins_type, template, nins_to_emit;
3491 int deps_start [16];
3494 if (!code->automatic) {
3495 ia64_emit_bundle_manual (code);
3500 * We implement a simple scheduler which tries to put three instructions
3501 * per bundle, then two, then one.
3504 ia64_analyze_deps (code, deps_start);
3506 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3507 /* Find a suitable template */
3508 for (template = 0; template < 32; ++template) {
3509 if (stops_in_template [template][0] != code->stops [0] ||
3510 stops_in_template [template][1] != code->stops [1] ||
3511 stops_in_template [template][2] != code->stops [2])
3515 for (i = 0; i < 3; ++i) {
3516 ins_type = ins_types_in_template [template][i];
3517 switch (code->itypes [i]) {
3518 case IA64_INS_TYPE_A:
3519 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3522 found &= (ins_type == code->itypes [i]);
3528 found = debug_ins_sched ();
3531 ia64_real_emit_bundle (code, deps_start, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3537 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3538 /* Wait for more instructions */
3541 /* If it didn't work out, try putting two instructions into one bundle */
3542 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3543 /* Try a nop at the end */
3544 for (template = 0; template < 32; ++template) {
3545 if (stops_in_template [template][0] != code->stops [0] ||
3546 ((stops_in_template [template][1] != code->stops [1]) &&
3547 (stops_in_template [template][2] != code->stops [1])))
3551 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3552 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3555 if (!debug_ins_sched ())
3558 ia64_real_emit_bundle (code, deps_start, 2, template, code->instructions [0], code->instructions [1], nops_for_ins_types [ins_types_in_template [template][2]], 1 << 2);
3563 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3564 /* Wait for more instructions */
3567 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3568 /* Try a nop in the middle */
3569 for (template = 0; template < 32; ++template) {
3570 if (((stops_in_template [template][0] != code->stops [0]) &&
3571 (stops_in_template [template][1] != code->stops [0])) ||
3572 stops_in_template [template][2] != code->stops [1])
3575 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3576 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3579 if (!debug_ins_sched ())
3582 ia64_real_emit_bundle (code, deps_start, 2, template, code->instructions [0], nops_for_ins_types [ins_types_in_template [template][1]], code->instructions [1], 1 << 1);
3587 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3588 /* Try a nop at the beginning */
3589 for (template = 0; template < 32; ++template) {
3590 if ((stops_in_template [template][1] != code->stops [0]) ||
3591 (stops_in_template [template][2] != code->stops [1]))
3594 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3595 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3598 if (!debug_ins_sched ())
3601 ia64_real_emit_bundle (code, deps_start, 2, template, nops_for_ins_types [ins_types_in_template [template][0]], code->instructions [0], code->instructions [1], 1 << 0);
3606 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3607 /* Wait for more instructions */
3611 nins_to_emit = code->nins;
3615 while (nins_to_emit > 0) {
3616 if (!debug_ins_sched ())
3617 code->stops [0] = 1;
3618 switch (code->itypes [0]) {
3619 case IA64_INS_TYPE_A:
3620 if (code->stops [0])
3621 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3623 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3625 case IA64_INS_TYPE_I:
3626 if (code->stops [0])
3627 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3629 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3631 case IA64_INS_TYPE_M:
3632 if (code->stops [0])
3633 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3635 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3637 case IA64_INS_TYPE_B:
3638 if (code->stops [0])
3639 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3641 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3643 case IA64_INS_TYPE_F:
3644 if (code->stops [0])
3645 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3647 ia64_real_emit_bundle (code, deps_start, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3649 case IA64_INS_TYPE_LX:
3650 if (code->stops [0] || code->stops [1])
3651 ia64_real_emit_bundle (code, deps_start, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3653 ia64_real_emit_bundle (code, deps_start, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3657 g_assert_not_reached ();
3665 ia64_patch (unsigned char* code, gpointer target)
3668 guint64 instructions [3];
3669 guint8 gen_buf [16];
3670 Ia64CodegenState gen;
3675 * code encodes both the position inside the buffer and code.nins when
3676 * the instruction was emitted.
3678 ins_to_skip = (guint64)code % 16;
3679 code = (unsigned char*)((guint64)code & ~15);
3682 * Search for the first instruction which is 'patchable', skipping
3683 * ins_to_skip instructions.
3688 template = ia64_bundle_template (code);
3689 instructions [0] = ia64_bundle_ins1 (code);
3690 instructions [1] = ia64_bundle_ins2 (code);
3691 instructions [2] = ia64_bundle_ins3 (code);
3693 ia64_codegen_init (gen, gen_buf);
3696 for (i = 0; i < 3; ++i) {
3697 guint64 ins = instructions [i];
3698 int opcode = ia64_ins_opcode (ins);
3700 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3708 switch (ins_types_in_template [template][i]) {
3709 case IA64_INS_TYPE_A:
3710 case IA64_INS_TYPE_M:
3711 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3713 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3714 instructions [i] = gen.instructions [0];
3720 case IA64_INS_TYPE_B:
3721 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3723 gint64 disp = ((guint8*)target - code) >> 4;
3726 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3728 instructions [i] = gen.instructions [0];
3731 else if (opcode == 5) {
3733 gint64 disp = ((guint8*)target - code) >> 4;
3736 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3737 instructions [i] = gen.instructions [0];
3743 case IA64_INS_TYPE_LX:
3747 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3749 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3750 instructions [1] = gen.instructions [0];
3751 instructions [2] = gen.instructions [1];
3764 ia64_codegen_init (gen, code);
3765 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3775 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3777 MonoJumpInfo *patch_info;
3779 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3780 unsigned char *ip = patch_info->ip.i + code;
3781 const unsigned char *target;
3783 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3785 if (mono_compile_aot) {
3789 ia64_patch (ip, (gpointer)target);
3794 mono_arch_emit_prolog (MonoCompile *cfg)
3796 MonoMethod *method = cfg->method;
3797 MonoMethodSignature *sig;
3799 int alloc_size, pos, i;
3800 Ia64CodegenState code;
3802 unw_dyn_region_info_t *r_pro;
3805 sig = mono_method_signature (method);
3808 cinfo = get_call_info (sig, FALSE);
3810 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3812 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3813 cfg->code_size += 1024;
3814 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3815 cfg->code_size += 1024;
3817 cfg->native_code = g_malloc (cfg->code_size);
3819 ia64_codegen_init (code, cfg->native_code);
3820 ia64_codegen_set_automatic (code, FALSE);
3822 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3823 if (cfg->param_area)
3824 alloc_size += cfg->param_area;
3828 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3830 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3831 /* Force sp to be saved/restored */
3832 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3834 cfg->arch.stack_alloc_size = alloc_size;
3838 if (method->save_lmf) {
3839 /* No LMF on IA64 */
3844 /* Initialize unwind info */
3845 r_pro = g_malloc0 (_U_dyn_region_info_size (3));
3848 ia64_begin_bundle_template (code, IA64_TEMPLATE_MIIS);
3849 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);
3850 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3852 _U_dyn_op_save_reg (&r_pro->op[unw_op_count++], _U_QP_TRUE, /* when=*/ 0,
3853 /* reg=*/ UNW_IA64_AR_PFS, /* dst=*/ UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3854 _U_dyn_op_save_reg (&r_pro->op[unw_op_count++], _U_QP_TRUE, /* when=*/ 1,
3855 /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + cfg->arch.reg_saved_b0);
3857 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3858 ia64_mov (code, cfg->frame_reg, IA64_SP);
3859 _U_dyn_op_save_reg (&r_pro->op[unw_op_count++], _U_QP_TRUE, /* when=*/ 2,
3860 /* reg=*/ UNW_IA64_SP, /* dst=*/ UNW_IA64_GR + cfg->frame_reg);
3863 if (cfg->arch.omit_fp && alloc_size && ia64_is_imm14 (-alloc_size)) {
3864 /* FIXME: Add unwind info */
3865 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3868 ia64_nop_i (code, 0);
3871 ia64_begin_bundle (code);
3873 /* Finish unwind info */
3874 r_pro->op_count = unw_op_count;
3875 r_pro->insn_count = (code.buf - cfg->native_code) >> 4;
3877 cfg->arch.r_pro = r_pro;
3879 ia64_codegen_set_automatic (code, TRUE);
3882 /* See mono_emit_stack_alloc */
3883 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3887 if (ia64_is_imm14 (-alloc_size)) {
3888 if (cfg->arch.omit_fp)
3892 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3895 ia64_movl (code, GP_SCRATCH_REG, -alloc_size); ia64_stop (code);
3896 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3901 if (sig->ret->type != MONO_TYPE_VOID) {
3902 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3903 /* Save volatile arguments to the stack */
3908 /* Keep this in sync with emit_load_volatile_arguments */
3909 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3910 ArgInfo *ainfo = cinfo->args + i;
3911 gint32 stack_offset;
3913 inst = cfg->varinfo [i];
3915 if (sig->hasthis && (i == 0))
3916 arg_type = &mono_defaults.object_class->byval_arg;
3918 arg_type = sig->params [i - sig->hasthis];
3920 arg_type = mono_type_get_underlying_type (arg_type);
3922 stack_offset = ainfo->offset + ARGS_OFFSET;
3924 /* Save volatile arguments to the stack */
3925 if (inst->opcode != OP_REGVAR) {
3926 switch (ainfo->storage) {
3929 /* FIXME: big offsets */
3930 g_assert (inst->opcode == OP_REGOFFSET);
3931 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3932 if (arg_type->byref)
3933 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3935 switch (arg_type->type) {
3937 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3940 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3943 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3951 if (ainfo->nslots != ainfo->nregs)
3954 g_assert (inst->opcode == OP_REGOFFSET);
3955 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3956 for (i = 0; i < ainfo->nregs; ++i) {
3957 switch (ainfo->atype) {
3958 case AggregateNormal:
3959 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3961 case AggregateSingleHFA:
3962 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3964 case AggregateDoubleHFA:
3965 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3973 g_assert_not_reached ();
3977 if (inst->opcode == OP_REGVAR) {
3978 /* Argument allocated to (non-volatile) register */
3979 switch (ainfo->storage) {
3981 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3982 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3985 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3986 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3994 if (method->save_lmf) {
3995 /* No LMF on IA64 */
3998 ia64_codegen_close (code);
4002 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4003 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4005 cfg->code_len = code.buf - cfg->native_code;
4007 g_assert (cfg->code_len < cfg->code_size);
4009 cfg->arch.prolog_end_offset = cfg->code_len;
4015 mono_arch_emit_epilog (MonoCompile *cfg)
4017 MonoMethod *method = cfg->method;
4019 int max_epilog_size = 16 * 4;
4020 Ia64CodegenState code;
4025 if (mono_jit_trace_calls != NULL)
4026 max_epilog_size += 1024;
4028 cfg->arch.epilog_begin_offset = cfg->code_len;
4030 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4031 cfg->code_size *= 2;
4032 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4033 mono_jit_stats.code_reallocs++;
4036 /* FIXME: Emit unwind info */
4038 buf = cfg->native_code + cfg->code_len;
4040 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4041 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4043 ia64_codegen_init (code, buf);
4045 /* the code restoring the registers must be kept in sync with CEE_JMP */
4048 if (method->save_lmf) {
4049 /* No LMF on IA64 */
4052 /* Load returned vtypes into registers if needed */
4053 cinfo = get_call_info (mono_method_signature (method), FALSE);
4054 ainfo = &cinfo->ret;
4055 switch (ainfo->storage) {
4057 if (ainfo->nslots != ainfo->nregs)
4060 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4061 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4062 for (i = 0; i < ainfo->nregs; ++i) {
4063 switch (ainfo->atype) {
4064 case AggregateNormal:
4065 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4067 case AggregateSingleHFA:
4068 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4070 case AggregateDoubleHFA:
4071 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4074 g_assert_not_reached ();
4083 ia64_begin_bundle (code);
4084 ia64_codegen_set_automatic (code, FALSE);
4086 if (cfg->arch.stack_alloc_size && cfg->arch.omit_fp && !ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4087 ia64_begin_bundle_template (code, IA64_TEMPLATE_MLXS);
4088 ia64_nop_m (code, 0);
4089 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4091 ia64_begin_bundle (code);
4094 ia64_begin_bundle_template (code, IA64_TEMPLATE_MII);
4095 if (cfg->arch.stack_alloc_size) {
4096 if (cfg->arch.omit_fp) {
4097 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
4098 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4100 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4103 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4106 /* FIXME: Optimize this away */
4107 ia64_nop_m (code, 0);
4108 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4109 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4110 ia64_begin_bundle (code);
4112 ia64_begin_bundle_template (code, IA64_TEMPLATE_BBBS);
4113 ia64_br_ret_reg (code, IA64_B0);
4114 ia64_nop_b (code, 0);
4115 ia64_nop_b (code, 0); ia64_stop (code);
4116 ia64_begin_bundle (code);
4118 ia64_codegen_set_automatic (code, TRUE);
4119 ia64_codegen_close (code);
4121 cfg->code_len = code.buf - cfg->native_code;
4123 g_assert (cfg->code_len < cfg->code_size);
4127 mono_arch_emit_exceptions (MonoCompile *cfg)
4129 MonoJumpInfo *patch_info;
4131 Ia64CodegenState code;
4132 gboolean empty = TRUE;
4134 MonoClass *exc_classes [16];
4135 guint8 *exc_throw_start [16], *exc_throw_end [16];
4137 guint32 code_size = 0;
4139 /* Compute needed space */
4140 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4141 if (patch_info->type == MONO_PATCH_INFO_EXC)
4143 if (patch_info->type == MONO_PATCH_INFO_R8)
4144 code_size += 8 + 7; /* sizeof (double) + alignment */
4145 if (patch_info->type == MONO_PATCH_INFO_R4)
4146 code_size += 4 + 7; /* sizeof (float) + alignment */
4149 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4150 cfg->code_size *= 2;
4151 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4152 mono_jit_stats.code_reallocs++;
4155 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4157 /* add code to raise exceptions */
4158 /* FIXME: Optimize this */
4160 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4161 switch (patch_info->type) {
4162 case MONO_PATCH_INFO_EXC: {
4163 MonoClass *exc_class;
4167 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4168 g_assert (exc_class);
4169 throw_ip = cfg->native_code + patch_info->ip.i;
4171 ia64_begin_bundle (code);
4173 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4175 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_class->type_token);
4177 ia64_begin_bundle (code);
4179 patch_info->data.name = "mono_arch_throw_corlib_exception";
4180 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4181 patch_info->ip.i = code.buf - cfg->native_code;
4184 ia64_movl (code, GP_SCRATCH_REG, 0);
4185 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4186 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4187 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4189 /* Compute the offset */
4190 buf = code.buf + 32;
4191 ia64_movl (code, cfg->arch.reg_out0 + 1, buf - throw_ip);
4193 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4204 /* The unwinder needs this to work */
4205 ia64_break_i (code, 0);
4207 ia64_codegen_close (code);
4209 cfg->code_len = code.buf - cfg->native_code;
4211 g_assert (cfg->code_len < cfg->code_size);
4215 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4217 Ia64CodegenState code;
4218 CallInfo *cinfo = NULL;
4219 MonoMethodSignature *sig;
4221 int i, n, stack_area = 0;
4223 ia64_codegen_init (code, p);
4225 /* Keep this in sync with mono_arch_get_argument_info */
4227 if (enable_arguments) {
4228 /* Allocate a new area on the stack and save arguments there */
4229 sig = mono_method_signature (cfg->method);
4231 cinfo = get_call_info (sig, FALSE);
4233 n = sig->param_count + sig->hasthis;
4235 stack_area = ALIGN_TO (n * 8, 16);
4238 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4240 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4242 /* FIXME: Allocate out registers */
4244 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4246 /* Required by the ABI */
4247 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4249 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4250 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4252 /* Save arguments to the stack */
4253 for (i = 0; i < n; ++i) {
4254 ins = cfg->varinfo [i];
4256 if (ins->opcode == OP_REGVAR) {
4257 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4258 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4259 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4262 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4263 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4264 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4265 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4266 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4267 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4272 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4275 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4277 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4278 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4280 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4282 if (enable_arguments && stack_area) {
4283 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4285 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4287 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4292 ia64_codegen_close (code);
4298 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4300 Ia64CodegenState code;
4301 CallInfo *cinfo = NULL;
4302 MonoMethod *method = cfg->method;
4303 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4305 ia64_codegen_init (code, p);
4307 cinfo = get_call_info (sig, FALSE);
4309 /* Save return value + pass it to func */
4310 switch (cinfo->ret.storage) {
4314 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4315 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4318 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4319 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4320 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4321 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4323 case ArgValuetypeAddrInIReg:
4324 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4335 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4336 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4337 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4339 /* Restore return value */
4340 switch (cinfo->ret.storage) {
4344 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4347 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4348 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4350 case ArgValuetypeAddrInIReg:
4358 ia64_codegen_close (code);
4364 mono_arch_save_unwind_info (MonoCompile *cfg)
4368 /* FIXME: Unregister this for dynamic methods */
4370 di = g_malloc0 (sizeof (unw_dyn_info_t));
4371 di->start_ip = (unw_word_t) cfg->native_code;
4372 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4374 di->format = UNW_INFO_FORMAT_DYNAMIC;
4375 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4376 di->u.pi.regions = cfg->arch.r_pro;
4378 _U_dyn_register (di);
4382 mono_arch_flush_icache (guint8 *code, gint size)
4384 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4385 guint8* end = (guint8*)((guint64)code + size);
4387 #ifdef __INTEL_COMPILER
4388 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4395 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4396 /* FIXME: This could be increased to 128 on some cpus */
4403 mono_arch_flush_register_windows (void)
4405 /* Not needed because of libunwind */
4409 mono_arch_is_inst_imm (gint64 imm)
4411 /* The lowering pass will take care of it */
4417 * Determine whenever the trap whose info is in SIGINFO is caused by
4421 mono_arch_is_int_overflow (void *sigctx, void *info)
4423 /* Division is emulated with explicit overflow checks */
4428 mono_arch_get_patch_offset (guint8 *code)
4436 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4438 guint8 *bundle2 = code - 48;
4439 guint8 *bundle3 = code - 32;
4440 guint8 *bundle4 = code - 16;
4441 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4442 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4443 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4444 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4445 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4446 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4447 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4448 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4449 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4453 * Virtual calls are made with:
4455 * [MII] ld8 r31=[r8]
4459 * mov.sptk b6=r31,0x2000000000f32a80
4466 * br.call.sptk.few b0=b6;;
4469 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4470 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4471 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4472 (ins31 == IA64_NOP_M) &&
4473 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4474 (ins33 == IA64_NOP_I) &&
4475 (ins41 == IA64_NOP_M) &&
4476 (ins42 == IA64_NOP_I) &&
4477 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4478 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4479 g_assert (ins21 == IA64_NOP_M);
4480 g_assert (ins23 == IA64_NOP_I);
4481 g_assert (ia64_ins_opcode (ins22) == 0);
4482 g_assert (ia64_ins_x3 (ins22) == 7);
4483 g_assert (ia64_ins_x (ins22) == 0);
4484 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4489 * Must be a scratch register, since only those are saved by the trampoline
4491 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4493 g_assert (regs [reg]);
4502 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4509 static gboolean tls_offset_inited = FALSE;
4511 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
4514 setup_stack (MonoJitTlsData *tls)
4522 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4524 if (!tls_offset_inited) {
4525 tls_offset_inited = TRUE;
4527 appdomain_tls_offset = mono_domain_get_tls_offset ();
4528 thread_tls_offset = mono_thread_get_tls_offset ();
4531 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
4537 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4539 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
4540 struct sigaltstack sa;
4542 sa.ss_sp = tls->signal_stack;
4543 sa.ss_size = SIGNAL_STACK_SIZE;
4544 sa.ss_flags = SS_DISABLE;
4545 sigaltstack (&sa, NULL);
4547 if (tls->signal_stack)
4548 munmap (tls->signal_stack, SIGNAL_STACK_SIZE);
4553 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4555 MonoCallInst *call = (MonoCallInst*)inst;
4556 int out_reg = cfg->arch.reg_out0;
4559 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4562 if (cinfo->ret.storage == ArgAggregate) {
4563 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4566 * The valuetype is in registers after the call, need to be copied
4567 * to the stack. Save the address to a local here, so the call
4568 * instruction can access it.
4570 g_assert (local->opcode == OP_REGOFFSET);
4571 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4574 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4575 vtarg->sreg1 = vt_reg;
4576 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4577 mono_bblock_add_inst (cfg->cbb, vtarg);
4579 mono_call_inst_add_outarg_reg (call, vtarg->dreg, out_reg, FALSE);
4587 /* add the this argument */
4588 if (this_reg != -1) {
4590 MONO_INST_NEW (cfg, this, OP_MOVE);
4591 this->type = this_type;
4592 this->sreg1 = this_reg;
4593 this->dreg = mono_regstate_next_int (cfg->rs);
4594 mono_bblock_add_inst (cfg->cbb, this);
4596 mono_call_inst_add_outarg_reg (call, this->dreg, out_reg, FALSE);
4601 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4603 MonoInst *ins = NULL;
4608 if (cmethod->klass == mono_defaults.math_class) {
4609 if (strcmp (cmethod->name, "Sin") == 0) {
4610 MONO_INST_NEW (cfg, ins, OP_SIN);
4611 ins->inst_i0 = args [0];
4612 } else if (strcmp (cmethod->name, "Cos") == 0) {
4613 MONO_INST_NEW (cfg, ins, OP_COS);
4614 ins->inst_i0 = args [0];
4615 } else if (strcmp (cmethod->name, "Tan") == 0) {
4617 MONO_INST_NEW (cfg, ins, OP_TAN);
4618 ins->inst_i0 = args [0];
4619 } else if (strcmp (cmethod->name, "Atan") == 0) {
4621 MONO_INST_NEW (cfg, ins, OP_ATAN);
4622 ins->inst_i0 = args [0];
4623 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4624 MONO_INST_NEW (cfg, ins, OP_SQRT);
4625 ins->inst_i0 = args [0];
4626 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4627 MONO_INST_NEW (cfg, ins, OP_ABS);
4628 ins->inst_i0 = args [0];
4631 /* OP_FREM is not IEEE compatible */
4632 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
4633 MONO_INST_NEW (cfg, ins, OP_FREM);
4634 ins->inst_i0 = args [0];
4635 ins->inst_i1 = args [1];
4638 } else if(cmethod->klass->image == mono_defaults.corlib &&
4639 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4640 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4642 if (strcmp (cmethod->name, "Increment") == 0) {
4643 MonoInst *ins_iconst;
4646 if (fsig->params [0]->type == MONO_TYPE_I4)
4647 opcode = OP_ATOMIC_ADD_NEW_I4;
4648 else if (fsig->params [0]->type == MONO_TYPE_I8)
4649 opcode = OP_ATOMIC_ADD_NEW_I8;
4651 g_assert_not_reached ();
4652 MONO_INST_NEW (cfg, ins, opcode);
4653 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4654 ins_iconst->inst_c0 = 1;
4656 ins->inst_i0 = args [0];
4657 ins->inst_i1 = ins_iconst;
4658 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4659 MonoInst *ins_iconst;
4662 if (fsig->params [0]->type == MONO_TYPE_I4)
4663 opcode = OP_ATOMIC_ADD_NEW_I4;
4664 else if (fsig->params [0]->type == MONO_TYPE_I8)
4665 opcode = OP_ATOMIC_ADD_NEW_I8;
4667 g_assert_not_reached ();
4668 MONO_INST_NEW (cfg, ins, opcode);
4669 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4670 ins_iconst->inst_c0 = -1;
4672 ins->inst_i0 = args [0];
4673 ins->inst_i1 = ins_iconst;
4674 } else if (strcmp (cmethod->name, "Add") == 0) {
4677 if (fsig->params [0]->type == MONO_TYPE_I4)
4678 opcode = OP_ATOMIC_ADD_I4;
4679 else if (fsig->params [0]->type == MONO_TYPE_I8)
4680 opcode = OP_ATOMIC_ADD_I8;
4682 g_assert_not_reached ();
4684 MONO_INST_NEW (cfg, ins, opcode);
4686 ins->inst_i0 = args [0];
4687 ins->inst_i1 = args [1];
4688 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4691 if (fsig->params [0]->type == MONO_TYPE_I4)
4692 opcode = OP_ATOMIC_EXCHANGE_I4;
4693 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4694 (fsig->params [0]->type == MONO_TYPE_I) ||
4695 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4696 opcode = OP_ATOMIC_EXCHANGE_I8;
4700 MONO_INST_NEW (cfg, ins, opcode);
4702 ins->inst_i0 = args [0];
4703 ins->inst_i1 = args [1];
4704 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4705 /* 64 bit reads are already atomic */
4706 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4707 ins->inst_i0 = args [0];
4711 * Can't implement CompareExchange methods this way since they have
4720 mono_arch_print_tree (MonoInst *tree, int arity)
4725 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4729 if (appdomain_tls_offset == -1)
4732 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4733 ins->inst_offset = appdomain_tls_offset;
4737 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4741 if (thread_tls_offset == -1)
4744 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4745 ins->inst_offset = thread_tls_offset;