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 ARGS_OFFSET 16
59 #define GP_SCRATCH_REG 31
60 #define GP_SCRATCH_REG2 30
61 #define FP_SCRATCH_REG 32
63 #define LOOP_ALIGNMENT 8
64 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
66 #define NOT_IMPLEMENTED g_assert_not_reached ()
68 static const char* gregs [] = {
69 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
70 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
71 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
72 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
73 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
74 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
75 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
76 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
77 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
78 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
79 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
80 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
81 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
85 mono_arch_regname (int reg)
93 static const char* fregs [] = {
94 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
95 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
96 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
97 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
98 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
99 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
100 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
101 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
102 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
103 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
104 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
105 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
106 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
110 mono_arch_fregname (int reg)
118 G_GNUC_UNUSED static void
123 G_GNUC_UNUSED static gboolean
126 static int count = 0;
129 if (count == atoi (getenv ("COUNT"))) {
133 if (count > atoi (getenv ("COUNT"))) {
141 debug_ins_sched (void)
144 return debug_count ();
154 return debug_count ();
161 ia64_patch (unsigned char* code, gpointer target);
167 ArgValuetypeAddrInIReg,
185 /* Only if storage == ArgAggregate */
195 gboolean need_stack_align;
201 #define DEBUG(a) if (cfg->verbose_level > 1) a
203 #define NEW_ICONST(cfg,dest,val) do { \
204 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
205 (dest)->opcode = OP_ICONST; \
206 (dest)->inst_c0 = (val); \
207 (dest)->type = STACK_I4; \
213 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
215 ainfo->offset = *stack_size;
217 if (*gr >= PARAM_REGS) {
218 ainfo->storage = ArgOnStack;
219 (*stack_size) += sizeof (gpointer);
222 ainfo->storage = ArgInIReg;
228 #define FLOAT_PARAM_REGS 8
231 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
233 ainfo->offset = *stack_size;
235 if (*gr >= PARAM_REGS) {
236 ainfo->storage = ArgOnStack;
237 (*stack_size) += sizeof (gpointer);
240 ainfo->storage = ArgInFloatReg;
241 ainfo->reg = 8 + *fr;
248 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
250 guint32 *gr, guint32 *fr, guint32 *stack_size)
254 MonoMarshalType *info;
255 gboolean is_hfa = TRUE;
256 guint32 hfa_type = 0;
258 klass = mono_class_from_mono_type (type);
259 if (type->type == MONO_TYPE_TYPEDBYREF)
260 size = 3 * sizeof (gpointer);
261 else if (sig->pinvoke)
262 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
264 size = mono_type_stack_size (&klass->byval_arg, NULL);
266 if (!sig->pinvoke || (size == 0)) {
267 /* Allways pass in memory */
268 ainfo->offset = *stack_size;
269 *stack_size += ALIGN_TO (size, 8);
270 ainfo->storage = ArgOnStack;
275 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
276 info = mono_marshal_load_type_info (klass);
278 for (i = 0; i < info->num_fields; ++i) {
279 guint32 ftype = info->fields [i].field->type->type;
280 if (!(info->fields [i].field->type->byref) &&
281 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
284 else if (hfa_type != ftype)
293 ainfo->storage = ArgAggregate;
294 ainfo->atype = AggregateNormal;
297 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
299 if (info->num_fields <= 8) {
301 ainfo->nregs = info->num_fields;
302 ainfo->nslots = ainfo->nregs;
308 if ((*fr) + info->num_fields > 8)
311 ainfo->reg = 8 + (*fr);
312 ainfo->nregs = info->num_fields;
313 ainfo->nslots = ainfo->nregs;
314 (*fr) += info->num_fields;
319 /* This also handles returning of TypedByRef used by some icalls */
322 ainfo->reg = IA64_R8;
323 ainfo->nregs = (size + 7) / 8;
324 ainfo->nslots = ainfo->nregs;
331 ainfo->offset = *stack_size;
332 ainfo->nslots = (size + 7) / 8;
334 if (((*gr) + ainfo->nslots) <= 8) {
335 /* Fits entirely in registers */
336 ainfo->nregs = ainfo->nslots;
337 (*gr) += ainfo->nregs;
341 ainfo->nregs = 8 - (*gr);
343 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
349 * Obtain information about a call according to the calling convention.
350 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
351 * Gude" document for more information.
354 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
358 int n = sig->hasthis + sig->param_count;
359 guint32 stack_size = 0;
362 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
369 ret_type = mono_type_get_underlying_type (sig->ret);
370 switch (ret_type->type) {
371 case MONO_TYPE_BOOLEAN:
382 case MONO_TYPE_FNPTR:
383 case MONO_TYPE_CLASS:
384 case MONO_TYPE_OBJECT:
385 case MONO_TYPE_SZARRAY:
386 case MONO_TYPE_ARRAY:
387 case MONO_TYPE_STRING:
388 cinfo->ret.storage = ArgInIReg;
389 cinfo->ret.reg = IA64_R8;
393 cinfo->ret.storage = ArgInIReg;
394 cinfo->ret.reg = IA64_R8;
398 cinfo->ret.storage = ArgInFloatReg;
401 case MONO_TYPE_VALUETYPE:
402 case MONO_TYPE_TYPEDBYREF: {
403 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
405 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
406 if (cinfo->ret.storage == ArgOnStack)
407 /* The caller passes the address where the value is stored */
408 add_general (&gr, &stack_size, &cinfo->ret);
409 if (cinfo->ret.storage == ArgInIReg)
410 cinfo->ret.storage = ArgValuetypeAddrInIReg;
414 cinfo->ret.storage = ArgNone;
417 g_error ("Can't handle as return value 0x%x", sig->ret->type);
423 add_general (&gr, &stack_size, cinfo->args + 0);
425 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
427 fr = FLOAT_PARAM_REGS;
429 /* Emit the signature cookie just before the implicit arguments */
430 add_general (&gr, &stack_size, &cinfo->sig_cookie);
433 for (i = 0; i < sig->param_count; ++i) {
434 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
437 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
438 /* We allways pass the sig cookie on the stack for simplicity */
440 * Prevent implicit arguments + the sig cookie from being passed
444 fr = FLOAT_PARAM_REGS;
446 /* Emit the signature cookie just before the implicit arguments */
447 add_general (&gr, &stack_size, &cinfo->sig_cookie);
450 if (sig->params [i]->byref) {
451 add_general (&gr, &stack_size, ainfo);
454 ptype = mono_type_get_underlying_type (sig->params [i]);
455 switch (ptype->type) {
456 case MONO_TYPE_BOOLEAN:
459 add_general (&gr, &stack_size, ainfo);
464 add_general (&gr, &stack_size, ainfo);
468 add_general (&gr, &stack_size, ainfo);
473 case MONO_TYPE_FNPTR:
474 case MONO_TYPE_CLASS:
475 case MONO_TYPE_OBJECT:
476 case MONO_TYPE_STRING:
477 case MONO_TYPE_SZARRAY:
478 case MONO_TYPE_ARRAY:
479 add_general (&gr, &stack_size, ainfo);
481 case MONO_TYPE_VALUETYPE:
482 case MONO_TYPE_TYPEDBYREF:
484 /* We allways pass valuetypes on the stack */
485 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
489 add_general (&gr, &stack_size, ainfo);
492 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
495 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
498 g_assert_not_reached ();
502 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
504 fr = FLOAT_PARAM_REGS;
506 /* Emit the signature cookie just before the implicit arguments */
507 add_general (&gr, &stack_size, &cinfo->sig_cookie);
510 cinfo->stack_usage = stack_size;
511 cinfo->reg_usage = gr;
512 cinfo->freg_usage = fr;
517 * mono_arch_get_argument_info:
518 * @csig: a method signature
519 * @param_count: the number of parameters to consider
520 * @arg_info: an array to store the result infos
522 * Gathers information on parameters such as size, alignment and
523 * padding. arg_info should be large enought to hold param_count + 1 entries.
525 * Returns the size of the argument area on the stack.
528 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
531 CallInfo *cinfo = get_call_info (csig, FALSE);
532 guint32 args_size = cinfo->stack_usage;
534 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
536 arg_info [0].offset = 0;
539 for (k = 0; k < param_count; k++) {
540 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
542 arg_info [k + 1].size = 0;
551 * Initialize the cpu to execute managed code.
554 mono_arch_cpu_init (void)
559 * This function returns the optimizations supported on this cpu.
562 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
570 mono_arch_break (void)
575 is_regsize_var (MonoType *t) {
578 t = mono_type_get_underlying_type (t);
589 case MONO_TYPE_FNPTR:
590 case MONO_TYPE_BOOLEAN:
592 case MONO_TYPE_OBJECT:
593 case MONO_TYPE_STRING:
594 case MONO_TYPE_CLASS:
595 case MONO_TYPE_SZARRAY:
596 case MONO_TYPE_ARRAY:
598 case MONO_TYPE_VALUETYPE:
605 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
609 MonoMethodSignature *sig;
610 MonoMethodHeader *header;
613 header = mono_method_get_header (cfg->method);
615 sig = mono_method_signature (cfg->method);
617 cinfo = get_call_info (sig, FALSE);
619 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
620 MonoInst *ins = cfg->varinfo [i];
622 ArgInfo *ainfo = &cinfo->args [i];
624 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
627 if (ainfo->storage == ArgInIReg) {
628 /* The input registers are non-volatile */
629 ins->opcode = OP_REGVAR;
630 ins->dreg = 32 + ainfo->reg;
634 for (i = 0; i < cfg->num_varinfo; i++) {
635 MonoInst *ins = cfg->varinfo [i];
636 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
639 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
642 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
643 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
646 if (is_regsize_var (ins->inst_vtype)) {
647 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
648 g_assert (i == vmv->idx);
649 vars = g_list_prepend (vars, vmv);
653 vars = mono_varlist_sort (cfg, vars, 0);
659 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
662 guint32 reserved_regs = 3;
664 if (cfg->arch.reg_local0 > 0)
668 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
670 /* Three registers are reserved for use by the prolog/epilog */
673 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
674 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
675 /* One registers is needed by instrument_epilog to save the return value */
677 if (cinfo->reg_usage < 2)
678 /* Number of arguments passed to function call in instrument_prolog */
679 cinfo->reg_usage = 2;
682 cfg->arch.reg_in0 = 32;
683 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
684 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
686 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
687 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
688 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 3;
690 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
691 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
692 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - 4;
696 * Need to allocate at least 2 out register for use by CEE_THROW / the system
697 * exception throwing code.
699 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
705 mono_arch_get_global_int_regs (MonoCompile *cfg)
710 mono_ia64_alloc_stacked_registers (cfg);
712 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
715 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
722 * mono_arch_regalloc_cost:
724 * Return the cost, in number of memory references, of the action of
725 * allocating the variable VMV into a register during global register
729 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
731 /* FIXME: Increase costs linearly to avoid using all local registers */
737 mono_arch_allocate_vars (MonoCompile *cfg)
739 MonoMethodSignature *sig;
740 MonoMethodHeader *header;
743 guint32 locals_stack_size, locals_stack_align;
747 header = mono_method_get_header (cfg->method);
749 sig = mono_method_signature (cfg->method);
751 cinfo = get_call_info (sig, FALSE);
754 * Determine whenever the frame pointer can be eliminated.
755 * FIXME: Remove some of the restrictions.
757 cfg->arch.omit_fp = TRUE;
759 if (!debug_omit_fp ())
760 cfg->arch.omit_fp = FALSE;
762 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
763 cfg->arch.omit_fp = FALSE;
764 if (header->num_clauses)
765 cfg->arch.omit_fp = FALSE;
767 cfg->arch.omit_fp = FALSE;
768 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
769 ArgInfo *ainfo = &cinfo->args [i];
771 if (ainfo->storage == ArgOnStack) {
773 * The stack offset can only be determined when the frame
776 cfg->arch.omit_fp = FALSE;
780 mono_ia64_alloc_stacked_registers (cfg);
783 * We use the ABI calling conventions for managed code as well.
784 * Exception: valuetypes are never passed or returned in registers.
787 if (cfg->arch.omit_fp) {
788 cfg->frame_reg = IA64_SP;
789 offset = ARGS_OFFSET;
792 /* Locals are allocated backwards from %fp */
793 cfg->frame_reg = cfg->arch.reg_saved_sp;
797 if (cfg->method->save_lmf) {
801 if (sig->ret->type != MONO_TYPE_VOID) {
802 switch (cinfo->ret.storage) {
804 cfg->ret->opcode = OP_REGVAR;
805 cfg->ret->inst_c0 = cinfo->ret.reg;
808 cfg->ret->opcode = OP_REGVAR;
809 cfg->ret->inst_c0 = cinfo->ret.reg;
811 case ArgValuetypeAddrInIReg:
812 cfg->ret->opcode = OP_REGVAR;
813 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
816 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
817 if (cfg->arch.omit_fp)
818 g_assert_not_reached ();
819 offset = ALIGN_TO (offset, 8);
820 offset += cinfo->ret.nslots * 8;
821 cfg->ret->opcode = OP_REGOFFSET;
822 cfg->ret->inst_basereg = cfg->frame_reg;
823 cfg->ret->inst_offset = - offset;
826 g_assert_not_reached ();
828 cfg->ret->dreg = cfg->ret->inst_c0;
831 /* Allocate locals */
832 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
833 if (locals_stack_align) {
834 offset = ALIGN_TO (offset, locals_stack_align);
836 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
837 if (offsets [i] != -1) {
838 MonoInst *inst = cfg->varinfo [i];
839 inst->opcode = OP_REGOFFSET;
840 inst->inst_basereg = cfg->frame_reg;
841 if (cfg->arch.omit_fp)
842 inst->inst_offset = (offset + offsets [i]);
844 inst->inst_offset = - (offset + offsets [i]);
845 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
849 offset += locals_stack_size;
851 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
852 if (cfg->arch.omit_fp)
853 g_assert_not_reached ();
854 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
855 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
858 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
859 inst = cfg->varinfo [i];
860 if (inst->opcode != OP_REGVAR) {
861 ArgInfo *ainfo = &cinfo->args [i];
862 gboolean inreg = TRUE;
865 if (sig->hasthis && (i == 0))
866 arg_type = &mono_defaults.object_class->byval_arg;
868 arg_type = sig->params [i - sig->hasthis];
870 /* FIXME: VOLATILE is only set if the liveness pass runs */
871 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
874 inst->opcode = OP_REGOFFSET;
876 switch (ainfo->storage) {
878 inst->opcode = OP_REGVAR;
879 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
883 * Since float regs are volatile, we save the arguments to
884 * the stack in the prolog.
889 if (cfg->arch.omit_fp)
890 g_assert_not_reached ();
891 inst->opcode = OP_REGOFFSET;
892 inst->inst_basereg = cfg->frame_reg;
893 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
902 if (!inreg && (ainfo->storage != ArgOnStack)) {
903 inst->opcode = OP_REGOFFSET;
904 inst->inst_basereg = cfg->frame_reg;
905 /* These arguments are saved to the stack in the prolog */
906 switch (ainfo->storage) {
908 if (ainfo->atype == AggregateSingleHFA)
909 offset += ainfo->nslots * 4;
911 offset += ainfo->nslots * 8;
914 offset += sizeof (gpointer);
917 offset = ALIGN_TO (offset, sizeof (gpointer));
918 if (cfg->arch.omit_fp)
919 inst->inst_offset = offset;
921 inst->inst_offset = - offset;
926 if (cfg->arch.omit_fp && offset == 16)
929 cfg->stack_offset = offset;
935 mono_arch_create_vars (MonoCompile *cfg)
937 MonoMethodSignature *sig;
940 sig = mono_method_signature (cfg->method);
942 cinfo = get_call_info (sig, FALSE);
944 if (cinfo->ret.storage == ArgAggregate)
945 cfg->ret_var_is_local = TRUE;
951 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
955 arg->opcode = OP_OUTARG_REG;
956 arg->inst_left = tree;
957 arg->inst_right = (MonoInst*)call;
959 call->used_iregs |= 1 << reg;
962 arg->opcode = OP_OUTARG_FREG;
963 arg->inst_left = tree;
964 arg->inst_right = (MonoInst*)call;
966 call->used_fregs |= 1 << reg;
969 g_assert_not_reached ();
974 * take the arguments and generate the arch-specific
975 * instructions to properly call the function in call.
976 * This includes pushing, moving arguments to the right register
978 * Issue: who does the spilling if needed, and when?
981 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
984 MonoMethodSignature *sig;
985 int i, n, stack_size;
991 mono_ia64_alloc_stacked_registers (cfg);
993 sig = call->signature;
994 n = sig->param_count + sig->hasthis;
996 cinfo = get_call_info (sig, sig->pinvoke);
998 if (cinfo->ret.storage == ArgAggregate) {
999 /* The code in emit_this_vret_arg needs a local */
1000 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1001 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1004 for (i = 0; i < n; ++i) {
1005 ainfo = cinfo->args + i;
1007 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1008 MonoMethodSignature *tmp_sig;
1010 /* Emit the signature cookie just before the implicit arguments */
1012 /* FIXME: Add support for signature tokens to AOT */
1013 cfg->disable_aot = TRUE;
1015 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1018 * mono_ArgIterator_Setup assumes the signature cookie is
1019 * passed first and all the arguments which were before it are
1020 * passed on the stack after the signature. So compensate by
1021 * passing a different signature.
1023 tmp_sig = mono_metadata_signature_dup (call->signature);
1024 tmp_sig->param_count -= call->signature->sentinelpos;
1025 tmp_sig->sentinelpos = 0;
1026 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1028 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1029 sig_arg->inst_p0 = tmp_sig;
1031 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1032 arg->inst_left = sig_arg;
1033 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1034 arg->type = STACK_PTR;
1036 /* prepend, so they get reversed */
1037 arg->next = call->out_args;
1038 call->out_args = arg;
1041 if (is_virtual && i == 0) {
1042 /* the argument will be attached to the call instruction */
1043 in = call->args [i];
1047 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1048 in = call->args [i];
1049 arg->cil_code = in->cil_code;
1050 arg->inst_left = in;
1051 arg->type = in->type;
1052 /* prepend, so they get reversed */
1053 arg->next = call->out_args;
1054 call->out_args = arg;
1056 if (sig->hasthis && (i == 0))
1057 arg_type = &mono_defaults.object_class->byval_arg;
1059 arg_type = sig->params [i - sig->hasthis];
1061 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1062 MonoInst *stack_addr;
1066 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1067 size = sizeof (MonoTypedRef);
1068 align = sizeof (gpointer);
1072 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1075 * Other backends use mono_type_stack_size (), but that
1076 * aligns the size to 8, which is larger than the size of
1077 * the source, leading to reads of invalid memory if the
1078 * source is at the end of address space.
1080 size = mono_class_value_size (in->klass, &align);
1083 if (ainfo->storage == ArgAggregate) {
1084 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1087 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1090 * Part of the structure is passed in registers.
1092 for (i = 0; i < ainfo->nregs; ++i) {
1093 int offset, load_op, dest_reg, arg_storage;
1095 slot = ainfo->reg + i;
1097 if (ainfo->atype == AggregateSingleHFA) {
1098 load_op = CEE_LDIND_R4;
1100 dest_reg = ainfo->reg + i;
1101 arg_storage = ArgInFloatReg;
1102 } else if (ainfo->atype == AggregateDoubleHFA) {
1103 load_op = CEE_LDIND_R8;
1105 dest_reg = ainfo->reg + i;
1106 arg_storage = ArgInFloatReg;
1108 load_op = CEE_LDIND_I;
1110 dest_reg = cfg->arch.reg_out0 + ainfo->reg + i;
1111 arg_storage = ArgInIReg;
1114 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1115 load->ssa_op = MONO_SSA_LOAD;
1116 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1118 NEW_ICONST (cfg, offset_ins, offset);
1119 MONO_INST_NEW (cfg, load2, CEE_ADD);
1120 load2->inst_left = load;
1121 load2->inst_right = offset_ins;
1123 MONO_INST_NEW (cfg, load, load_op);
1124 load->inst_left = load2;
1129 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1130 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1131 if (set_reg != call->out_args) {
1132 set_reg->next = call->out_args;
1133 call->out_args = set_reg;
1138 * Part of the structure is passed on the stack.
1140 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1143 slot = ainfo->reg + i;
1145 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1146 load->ssa_op = MONO_SSA_LOAD;
1147 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1149 NEW_ICONST (cfg, offset_ins, (i * sizeof (gpointer)));
1150 MONO_INST_NEW (cfg, load2, CEE_ADD);
1151 load2->inst_left = load;
1152 load2->inst_right = offset_ins;
1154 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1155 load->inst_left = load2;
1160 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1161 outarg->inst_left = load;
1162 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1164 if (outarg != call->out_args) {
1165 outarg->next = call->out_args;
1166 call->out_args = outarg;
1170 /* Trees can't be shared so make a copy */
1171 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1172 arg->cil_code = in->cil_code;
1173 arg->ssa_op = MONO_SSA_STORE;
1174 arg->inst_left = vtaddr;
1175 arg->inst_right = in;
1176 arg->type = in->type;
1178 /* prepend, so they get reversed */
1179 arg->next = call->out_args;
1180 call->out_args = arg;
1183 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1184 stack_addr->inst_basereg = IA64_SP;
1185 stack_addr->inst_offset = 16 + ainfo->offset;
1186 stack_addr->inst_imm = size;
1188 arg->opcode = OP_OUTARG_VT;
1189 arg->inst_right = stack_addr;
1193 switch (ainfo->storage) {
1195 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1198 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1201 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1202 arg->opcode = OP_OUTARG_R4;
1205 arg->opcode = OP_OUTARG;
1206 arg->inst_imm = 16 + ainfo->offset;
1209 g_assert_not_reached ();
1215 call->stack_usage = cinfo->stack_usage;
1216 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1217 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1218 cfg->flags |= MONO_CFG_HAS_CALLS;
1226 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1228 MonoInst *ins, *last_ins = NULL;
1232 switch (ins->opcode) {
1240 if (ins->dreg == ins->sreg1) {
1242 last_ins->next = ins->next;
1249 * OP_MOVE sreg, dreg
1250 * OP_MOVE dreg, sreg
1252 if (last_ins && last_ins->opcode == OP_MOVE &&
1253 ins->sreg1 == last_ins->dreg &&
1254 ins->dreg == last_ins->sreg1) {
1255 last_ins->next = ins->next;
1262 /* remove unnecessary multiplication with 1 */
1263 if (ins->inst_imm == 1) {
1264 if (ins->dreg != ins->sreg1) {
1265 ins->opcode = OP_MOVE;
1267 last_ins->next = ins->next;
1278 bb->last_ins = last_ins;
1301 opcode_to_cond (int opcode)
1310 case OP_COND_EXC_EQ:
1313 case OP_COND_EXC_NE_UN:
1326 case OP_COND_EXC_LT:
1334 case OP_COND_EXC_GT:
1343 case OP_COND_EXC_LE_UN:
1357 case OP_COND_EXC_LT_UN:
1360 case OP_COND_EXC_GT_UN:
1368 printf ("%s\n", mono_inst_name (opcode));
1374 opcode_to_type (int opcode, int cmp_opcode)
1376 if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1378 else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1380 else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLE_UN))
1382 else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1384 else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLE_UN))
1386 else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1388 else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
1389 switch (cmp_opcode) {
1391 case OP_ICOMPARE_IMM:
1397 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1402 int cond_to_ia64_cmp [][3] = {
1403 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1404 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1405 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1406 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1407 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1408 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1409 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1410 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1411 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1412 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1416 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1418 return cond_to_ia64_cmp [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1421 int cond_to_ia64_cmp_imm [][3] = {
1422 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1423 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1424 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1425 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1426 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1427 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1428 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1429 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1430 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1431 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1435 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1437 /* The condition needs to be reversed */
1438 return cond_to_ia64_cmp_imm [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1442 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1446 bb->code = to_insert;
1447 to_insert->next = ins;
1450 to_insert->next = ins->next;
1451 ins->next = to_insert;
1455 #define NEW_INS(cfg,dest,op) do { \
1456 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1457 (dest)->opcode = (op); \
1458 insert_after_ins (bb, last_ins, (dest)); \
1459 last_ins = (dest); \
1463 * mono_arch_lowering_pass:
1465 * Converts complex opcodes into simpler ones so that each IR instruction
1466 * corresponds to one machine instruction.
1469 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1471 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1474 if (bb->max_ireg > cfg->rs->next_vireg)
1475 cfg->rs->next_vireg = bb->max_ireg;
1476 if (bb->max_freg > cfg->rs->next_vfreg)
1477 cfg->rs->next_vfreg = bb->max_freg;
1480 switch (ins->opcode) {
1481 case OP_STOREI1_MEMBASE_IMM:
1482 case OP_STOREI2_MEMBASE_IMM:
1483 case OP_STOREI4_MEMBASE_IMM:
1484 case OP_STOREI8_MEMBASE_IMM:
1485 case OP_STORE_MEMBASE_IMM:
1486 /* There are no store_membase instructions on ia64 */
1487 if (ia64_is_imm14 (ins->inst_offset)) {
1488 NEW_INS (cfg, temp2, OP_ADD_IMM);
1489 temp2->sreg1 = ins->inst_destbasereg;
1490 temp2->inst_imm = ins->inst_offset;
1491 temp2->dreg = mono_regstate_next_int (cfg->rs);
1494 NEW_INS (cfg, temp, OP_I8CONST);
1495 temp->inst_c0 = ins->inst_offset;
1496 temp->dreg = mono_regstate_next_int (cfg->rs);
1497 NEW_INS (cfg, temp2, CEE_ADD);
1498 temp2->sreg1 = ins->inst_destbasereg;
1499 temp2->sreg2 = temp->dreg;
1500 temp2->dreg = mono_regstate_next_int (cfg->rs);
1503 switch (ins->opcode) {
1504 case OP_STOREI1_MEMBASE_IMM:
1505 ins->opcode = OP_STOREI1_MEMBASE_REG;
1507 case OP_STOREI2_MEMBASE_IMM:
1508 ins->opcode = OP_STOREI2_MEMBASE_REG;
1510 case OP_STOREI4_MEMBASE_IMM:
1511 ins->opcode = OP_STOREI4_MEMBASE_REG;
1513 case OP_STOREI8_MEMBASE_IMM:
1514 case OP_STORE_MEMBASE_IMM:
1515 ins->opcode = OP_STOREI8_MEMBASE_REG;
1518 g_assert_not_reached ();
1521 if (ins->inst_imm == 0)
1522 ins->sreg1 = IA64_R0;
1524 NEW_INS (cfg, temp3, OP_I8CONST);
1525 temp3->inst_c0 = ins->inst_imm;
1526 temp3->dreg = mono_regstate_next_int (cfg->rs);
1527 ins->sreg1 = temp3->dreg;
1530 ins->inst_offset = 0;
1531 ins->inst_destbasereg = temp2->dreg;
1533 case OP_STOREI1_MEMBASE_REG:
1534 case OP_STOREI2_MEMBASE_REG:
1535 case OP_STOREI4_MEMBASE_REG:
1536 case OP_STOREI8_MEMBASE_REG:
1537 case OP_STORER4_MEMBASE_REG:
1538 case OP_STORER8_MEMBASE_REG:
1539 case OP_STORE_MEMBASE_REG:
1540 /* There are no store_membase instructions on ia64 */
1541 if (ins->inst_offset == 0) {
1544 else if (ia64_is_imm14 (ins->inst_offset)) {
1545 NEW_INS (cfg, temp2, OP_ADD_IMM);
1546 temp2->sreg1 = ins->inst_destbasereg;
1547 temp2->inst_imm = ins->inst_offset;
1548 temp2->dreg = mono_regstate_next_int (cfg->rs);
1551 NEW_INS (cfg, temp, OP_I8CONST);
1552 temp->inst_c0 = ins->inst_offset;
1553 temp->dreg = mono_regstate_next_int (cfg->rs);
1554 NEW_INS (cfg, temp2, CEE_ADD);
1555 temp2->sreg1 = ins->inst_destbasereg;
1556 temp2->sreg2 = temp->dreg;
1557 temp2->dreg = mono_regstate_next_int (cfg->rs);
1560 ins->inst_offset = 0;
1561 ins->inst_destbasereg = temp2->dreg;
1563 case OP_LOADI1_MEMBASE:
1564 case OP_LOADU1_MEMBASE:
1565 case OP_LOADI2_MEMBASE:
1566 case OP_LOADU2_MEMBASE:
1567 case OP_LOADI4_MEMBASE:
1568 case OP_LOADU4_MEMBASE:
1569 case OP_LOADI8_MEMBASE:
1570 case OP_LOAD_MEMBASE:
1571 case OP_LOADR4_MEMBASE:
1572 case OP_LOADR8_MEMBASE:
1573 /* There are no load_membase instructions on ia64 */
1574 if (ins->inst_offset == 0) {
1577 else if (ia64_is_imm14 (ins->inst_offset)) {
1578 NEW_INS (cfg, temp2, OP_ADD_IMM);
1579 temp2->sreg1 = ins->inst_basereg;
1580 temp2->inst_imm = ins->inst_offset;
1581 temp2->dreg = mono_regstate_next_int (cfg->rs);
1584 NEW_INS (cfg, temp, OP_I8CONST);
1585 temp->inst_c0 = ins->inst_offset;
1586 temp->dreg = mono_regstate_next_int (cfg->rs);
1587 NEW_INS (cfg, temp2, CEE_ADD);
1588 temp2->sreg1 = ins->inst_basereg;
1589 temp2->sreg2 = temp->dreg;
1590 temp2->dreg = mono_regstate_next_int (cfg->rs);
1593 ins->inst_offset = 0;
1594 ins->inst_basereg = temp2->dreg;
1596 case OP_IA64_FETCHADD4_IMM:
1597 case OP_IA64_FETCHADD8_IMM:
1598 case OP_ATOMIC_EXCHANGE_I4:
1599 case OP_ATOMIC_EXCHANGE_I8:
1600 /* There are no membase instructions on ia64 */
1601 if (ia64_is_imm14 (ins->inst_offset)) {
1602 NEW_INS (cfg, temp2, OP_ADD_IMM);
1603 temp2->sreg1 = ins->inst_basereg;
1604 temp2->inst_imm = ins->inst_offset;
1605 temp2->dreg = mono_regstate_next_int (cfg->rs);
1608 NEW_INS (cfg, temp, OP_I8CONST);
1609 temp->inst_c0 = ins->inst_offset;
1610 temp->dreg = mono_regstate_next_int (cfg->rs);
1611 NEW_INS (cfg, temp2, CEE_ADD);
1612 temp2->sreg1 = ins->inst_basereg;
1613 temp2->sreg2 = temp->dreg;
1614 temp2->dreg = mono_regstate_next_int (cfg->rs);
1616 ins->inst_offset = 0;
1617 ins->inst_basereg = temp2->dreg;
1631 case OP_ISHR_UN_IMM:
1632 case OP_LSHR_UN_IMM: {
1633 gboolean is_imm = FALSE;
1634 gboolean switched = FALSE;
1636 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1637 ins->opcode = OP_ZEXT_I1;
1641 switch (ins->opcode) {
1644 is_imm = ia64_is_imm14 (ins->inst_imm);
1648 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1650 /* A = B - IMM -> A = B + (-IMM) */
1651 ins->inst_imm = - ins->inst_imm;
1652 ins->opcode = OP_IADD_IMM;
1660 is_imm = ia64_is_imm8 (ins->inst_imm);
1668 case OP_ISHR_UN_IMM:
1669 case OP_LSHR_UN_IMM:
1670 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1678 ins->sreg2 = ins->sreg1;
1682 switch (ins->opcode) {
1684 ins->opcode = CEE_ADD;
1687 ins->opcode = OP_IADD;
1690 ins->opcode = OP_ISUB;
1693 ins->opcode = OP_IAND;
1696 ins->opcode = OP_IOR;
1699 ins->opcode = OP_IXOR;
1702 ins->opcode = OP_ISHL;
1705 ins->opcode = OP_ISHR;
1707 case OP_ISHR_UN_IMM:
1708 ins->opcode = OP_ISHR_UN;
1711 ins->opcode = CEE_AND;
1714 ins->opcode = OP_LSHL;
1717 ins->opcode = OP_LSHL;
1720 ins->opcode = OP_LSHR;
1722 case OP_LSHR_UN_IMM:
1723 ins->opcode = OP_LSHR_UN;
1726 g_assert_not_reached ();
1729 if (ins->inst_imm == 0)
1730 ins->sreg2 = IA64_R0;
1732 NEW_INS (cfg, temp, OP_I8CONST);
1733 temp->inst_c0 = ins->inst_imm;
1734 temp->dreg = mono_regstate_next_int (cfg->rs);
1735 ins->sreg2 = temp->dreg;
1739 case OP_COMPARE_IMM:
1740 case OP_ICOMPARE_IMM: {
1741 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1745 * The compare_imm instructions have switched up arguments, and
1746 * some of them take an imm between -127 and 128.
1749 switch (next->opcode) {
1752 case OP_COND_EXC_LT:
1755 imm = ia64_is_imm8 (ins->inst_imm - 1);
1761 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1764 imm = ia64_is_imm8 (ins->inst_imm);
1769 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1770 ins->sreg2 = ins->sreg1;
1773 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1775 if (ins->inst_imm == 0)
1776 ins->sreg2 = IA64_R0;
1778 NEW_INS (cfg, temp, OP_I8CONST);
1779 temp->inst_c0 = ins->inst_imm;
1780 temp->dreg = mono_regstate_next_int (cfg->rs);
1781 ins->sreg2 = temp->dreg;
1785 switch (next->opcode) {
1806 next->opcode = OP_IA64_BR_COND;
1807 if (! (next->flags & MONO_INST_BRLABEL))
1808 next->inst_target_bb = next->inst_true_bb;
1810 case OP_COND_EXC_EQ:
1811 case OP_COND_EXC_GT:
1812 case OP_COND_EXC_LT:
1813 case OP_COND_EXC_GT_UN:
1814 case OP_COND_EXC_LE_UN:
1815 case OP_COND_EXC_NE_UN:
1816 case OP_COND_EXC_LT_UN:
1817 next->opcode = OP_IA64_COND_EXC;
1829 next->opcode = OP_IA64_CSET;
1832 printf ("%s\n", mono_inst_name (next->opcode));
1842 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1846 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1847 switch (next->opcode) {
1878 next->opcode = OP_IA64_BR_COND;
1879 if (! (next->flags & MONO_INST_BRLABEL))
1880 next->inst_target_bb = next->inst_true_bb;
1882 case OP_COND_EXC_LT:
1883 case OP_COND_EXC_GT:
1884 case OP_COND_EXC_GT_UN:
1885 case OP_COND_EXC_LE_UN:
1886 next->opcode = OP_IA64_COND_EXC;
1903 next->opcode = OP_IA64_CSET;
1906 printf ("%s\n", mono_inst_name (next->opcode));
1915 gboolean found = FALSE;
1916 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1918 /* First the easy cases */
1919 if (ins->inst_imm == 1) {
1920 ins->opcode = OP_MOVE;
1923 for (i = 1; i < 64; ++i)
1924 if (ins->inst_imm == (((gint64)1) << i)) {
1925 ins->opcode = shl_op;
1931 /* This could be optimized */
1934 for (i = 0; i < 64; ++i) {
1935 if (ins->inst_imm & (((gint64)1) << i)) {
1936 NEW_INS (cfg, temp, shl_op);
1937 temp->dreg = mono_regstate_next_int (cfg->rs);
1938 temp->sreg1 = ins->sreg1;
1942 sum_reg = temp->dreg;
1944 NEW_INS (cfg, temp2, CEE_ADD);
1945 temp2->dreg = mono_regstate_next_int (cfg->rs);
1946 temp2->sreg1 = sum_reg;
1947 temp2->sreg2 = temp->dreg;
1948 sum_reg = temp2->dreg;
1952 ins->opcode = OP_MOVE;
1953 ins->sreg1 = sum_reg;
1957 case CEE_CONV_OVF_U4:
1958 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1959 temp->sreg1 = ins->sreg1;
1960 temp->sreg2 = IA64_R0;
1962 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1963 temp->inst_p1 = (char*)"OverflowException";
1965 ins->opcode = OP_MOVE;
1967 case CEE_CONV_OVF_I4_UN:
1968 NEW_INS (cfg, temp, OP_ICONST);
1969 temp->inst_c0 = 0x7fffffff;
1970 temp->dreg = mono_regstate_next_int (cfg->rs);
1972 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1973 temp2->sreg1 = ins->sreg1;
1974 temp2->sreg2 = temp->dreg;
1976 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1977 temp->inst_p1 = (char*)"OverflowException";
1979 ins->opcode = OP_MOVE;
1981 case OP_FCONV_TO_I4:
1982 case OP_FCONV_TO_I2:
1983 case OP_FCONV_TO_U2:
1984 case OP_FCONV_TO_I1:
1985 case OP_FCONV_TO_U1:
1986 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1987 temp->sreg1 = ins->sreg1;
1988 temp->dreg = ins->dreg;
1990 switch (ins->opcode) {
1991 case OP_FCONV_TO_I4:
1992 ins->opcode = OP_SEXT_I4;
1994 case OP_FCONV_TO_I2:
1995 ins->opcode = OP_SEXT_I2;
1997 case OP_FCONV_TO_U2:
1998 ins->opcode = OP_ZEXT_I4;
2000 case OP_FCONV_TO_I1:
2001 ins->opcode = OP_SEXT_I1;
2003 case OP_FCONV_TO_U1:
2004 ins->opcode = OP_ZEXT_I1;
2007 g_assert_not_reached ();
2009 ins->sreg1 = ins->dreg;
2017 bb->last_ins = last_ins;
2019 bb->max_ireg = cfg->rs->next_vireg;
2020 bb->max_freg = cfg->rs->next_vfreg;
2024 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
2029 mono_arch_lowering_pass (cfg, bb);
2031 mono_local_regalloc (cfg, bb);
2035 * emit_load_volatile_arguments:
2037 * Load volatile arguments from the stack to the original input registers.
2038 * Required before a tail call.
2040 static Ia64CodegenState
2041 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
2043 MonoMethod *method = cfg->method;
2044 MonoMethodSignature *sig;
2049 /* FIXME: Generate intermediate code instead */
2051 sig = mono_method_signature (method);
2053 cinfo = get_call_info (sig, FALSE);
2055 /* This is the opposite of the code in emit_prolog */
2056 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2057 ArgInfo *ainfo = cinfo->args + i;
2058 gint32 stack_offset;
2060 ins = cfg->varinfo [i];
2062 if (sig->hasthis && (i == 0))
2063 arg_type = &mono_defaults.object_class->byval_arg;
2065 arg_type = sig->params [i - sig->hasthis];
2067 arg_type = mono_type_get_underlying_type (arg_type);
2069 stack_offset = ainfo->offset + ARGS_OFFSET;
2071 /* Save volatile arguments to the stack */
2072 if (ins->opcode != OP_REGVAR) {
2073 switch (ainfo->storage) {
2076 /* FIXME: big offsets */
2077 g_assert (ins->opcode == OP_REGOFFSET);
2078 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2079 if (arg_type->byref)
2080 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2082 switch (arg_type->type) {
2084 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
2087 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
2090 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2102 if (ins->opcode == OP_REGVAR) {
2103 /* Argument allocated to (non-volatile) register */
2104 switch (ainfo->storage) {
2106 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
2107 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
2110 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
2111 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2124 static Ia64CodegenState
2125 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2130 /* Move return value to the target register */
2131 switch (ins->opcode) {
2133 case OP_VOIDCALL_REG:
2134 case OP_VOIDCALL_MEMBASE:
2138 case OP_CALL_MEMBASE:
2141 case OP_LCALL_MEMBASE:
2142 g_assert (ins->dreg == IA64_R8);
2146 case OP_FCALL_MEMBASE:
2147 g_assert (ins->dreg == 8);
2151 case OP_VCALL_MEMBASE:
2152 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
2153 ArgStorage storage = cinfo->ret.storage;
2155 if (storage == ArgAggregate) {
2156 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2158 /* Load address of stack space allocated for the return value */
2159 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2160 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2161 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2163 for (i = 0; i < cinfo->ret.nregs; ++i) {
2164 switch (cinfo->ret.atype) {
2165 case AggregateNormal:
2166 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2168 case AggregateSingleHFA:
2169 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2171 case AggregateDoubleHFA:
2172 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2175 g_assert_not_reached ();
2182 g_assert_not_reached ();
2188 #define add_patch_info(cfg,code,patch_type,data) do { \
2189 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2192 static Ia64CodegenState
2193 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2195 add_patch_info (cfg, code, patch_type, data);
2197 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2199 /* mono_arch_nullify_class_init_trampoline will patch this */
2200 ia64_movl (code, GP_SCRATCH_REG, 0);
2201 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2202 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2203 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2204 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2207 /* Can't use a direct call since the displacement might be too small */
2208 /* mono_arch_patch_callsite will patch this */
2209 ia64_movl (code, GP_SCRATCH_REG, 0);
2210 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2211 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2217 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2220 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2225 Ia64CodegenState code;
2226 guint8 *code_start = cfg->native_code + cfg->code_len;
2227 MonoInst *last_ins = NULL;
2228 guint last_offset = 0;
2231 if (cfg->opt & MONO_OPT_PEEPHOLE)
2232 peephole_pass (cfg, bb);
2234 if (cfg->opt & MONO_OPT_LOOP) {
2238 if (cfg->verbose_level > 2)
2239 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2241 cpos = bb->max_offset;
2243 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2247 offset = code_start - cfg->native_code;
2249 ia64_codegen_init (code, code_start);
2252 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2258 offset = code.buf - cfg->native_code;
2260 max_len = ((int)(((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN])) + 128;
2262 while (offset + max_len + 16 > cfg->code_size) {
2263 ia64_codegen_close (code);
2265 offset = code.buf - cfg->native_code;
2267 cfg->code_size *= 2;
2268 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2269 code_start = cfg->native_code + offset;
2270 mono_jit_stats.code_reallocs++;
2272 ia64_codegen_init (code, code_start);
2275 mono_debug_record_line_number (cfg, ins, offset);
2277 switch (ins->opcode) {
2280 if (ia64_is_imm14 (ins->inst_c0))
2281 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2283 ia64_movl (code, ins->dreg, ins->inst_c0);
2286 ia64_mov (code, ins->dreg, ins->sreg1);
2289 case OP_IA64_BR_COND: {
2291 if (ins->opcode == OP_IA64_BR_COND)
2293 if (ins->flags & MONO_INST_BRLABEL) {
2294 if (ins->inst_i0->inst_c0) {
2297 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2298 ia64_br_cond_pred (code, pred, 0);
2301 if (ins->inst_target_bb->native_offset) {
2302 guint8 *pos = code.buf + code.nins;
2304 ia64_br_cond_pred (code, pred, 0);
2305 ia64_begin_bundle (code);
2306 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2308 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2309 ia64_br_cond_pred (code, pred, 0);
2315 ia64_begin_bundle (code);
2316 ins->inst_c0 = code.buf - cfg->native_code;
2321 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2322 ia64_br_cond_reg (code, IA64_B6);
2326 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2330 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2334 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2338 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2342 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2346 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2349 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2353 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2356 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2357 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2361 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2364 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2368 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2371 /* p6 and p7 is set if there is signed/unsigned overflow */
2373 /* Set p8-p9 == (sreg2 > 0) */
2374 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2376 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2378 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2379 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2380 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2381 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2383 /* res <u sreg1 => unsigned overflow */
2384 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2386 /* FIXME: Predicate this since this is a side effect */
2387 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2390 /* p6 and p7 is set if there is signed/unsigned overflow */
2392 /* Set p8-p9 == (sreg2 > 0) */
2393 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2395 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2397 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2398 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2399 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2400 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2402 /* sreg1 <u sreg2 => unsigned overflow */
2403 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2405 /* FIXME: Predicate this since this is a side effect */
2406 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2409 /* Same as OP_IADDCC */
2410 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2412 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2414 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2415 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2417 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2419 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2422 /* Same as OP_ISUBCC */
2424 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2426 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2428 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2429 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2431 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2433 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2437 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2441 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2444 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2447 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2452 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2455 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2458 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2460 case OP_ISHR_UN_IMM:
2461 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2462 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2464 case OP_LSHR_UN_IMM:
2465 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2468 case OP_STOREI1_MEMBASE_REG:
2469 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2471 case OP_STOREI2_MEMBASE_REG:
2472 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2474 case OP_STOREI4_MEMBASE_REG:
2475 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2477 case OP_STOREI8_MEMBASE_REG:
2478 case OP_STORE_MEMBASE_REG:
2479 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2482 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2483 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2485 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2486 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2488 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2489 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2491 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2492 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2495 case OP_LOADU1_MEMBASE:
2496 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2498 case OP_LOADU2_MEMBASE:
2499 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2501 case OP_LOADU4_MEMBASE:
2502 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2504 case OP_LOADI1_MEMBASE:
2505 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2506 ia64_sxt1 (code, ins->dreg, ins->dreg);
2508 case OP_LOADI2_MEMBASE:
2509 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2510 ia64_sxt2 (code, ins->dreg, ins->dreg);
2512 case OP_LOADI4_MEMBASE:
2513 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2514 ia64_sxt4 (code, ins->dreg, ins->dreg);
2516 case OP_LOAD_MEMBASE:
2517 case OP_LOADI8_MEMBASE:
2518 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2521 case OP_IA64_LOADU1_MEMBASE_INC:
2522 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2524 case OP_IA64_LOADU2_MEMBASE_INC:
2525 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2527 case OP_IA64_LOADU4_MEMBASE_INC:
2528 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2530 case OP_IA64_LOADI8_MEMBASE_INC:
2531 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2535 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2538 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2541 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2544 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2547 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2550 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2553 /* Compare opcodes */
2554 case OP_IA64_CMP4_EQ:
2555 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2557 case OP_IA64_CMP4_NE:
2558 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2560 case OP_IA64_CMP4_LE:
2561 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2563 case OP_IA64_CMP4_LT:
2564 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2566 case OP_IA64_CMP4_GE:
2567 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2569 case OP_IA64_CMP4_GT:
2570 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2572 case OP_IA64_CMP4_LT_UN:
2573 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2575 case OP_IA64_CMP4_LE_UN:
2576 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2578 case OP_IA64_CMP4_GT_UN:
2579 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2581 case OP_IA64_CMP4_GE_UN:
2582 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2584 case OP_IA64_CMP_EQ:
2585 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2587 case OP_IA64_CMP_NE:
2588 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2590 case OP_IA64_CMP_LE:
2591 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2593 case OP_IA64_CMP_LT:
2594 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2596 case OP_IA64_CMP_GE:
2597 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2599 case OP_IA64_CMP_GT:
2600 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2602 case OP_IA64_CMP_GT_UN:
2603 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2605 case OP_IA64_CMP_LT_UN:
2606 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2608 case OP_IA64_CMP_GE_UN:
2609 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2611 case OP_IA64_CMP_LE_UN:
2612 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2614 case OP_IA64_CMP4_EQ_IMM:
2615 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2617 case OP_IA64_CMP4_NE_IMM:
2618 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2620 case OP_IA64_CMP4_LE_IMM:
2621 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2623 case OP_IA64_CMP4_LT_IMM:
2624 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2626 case OP_IA64_CMP4_GE_IMM:
2627 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2629 case OP_IA64_CMP4_GT_IMM:
2630 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2632 case OP_IA64_CMP4_LT_UN_IMM:
2633 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2635 case OP_IA64_CMP4_LE_UN_IMM:
2636 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2638 case OP_IA64_CMP4_GT_UN_IMM:
2639 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2641 case OP_IA64_CMP4_GE_UN_IMM:
2642 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2644 case OP_IA64_CMP_EQ_IMM:
2645 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2647 case OP_IA64_CMP_NE_IMM:
2648 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2650 case OP_IA64_CMP_LE_IMM:
2651 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2653 case OP_IA64_CMP_LT_IMM:
2654 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2656 case OP_IA64_CMP_GE_IMM:
2657 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2659 case OP_IA64_CMP_GT_IMM:
2660 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2662 case OP_IA64_CMP_GT_UN_IMM:
2663 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2665 case OP_IA64_CMP_LT_UN_IMM:
2666 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2668 case OP_IA64_CMP_GE_UN_IMM:
2669 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2671 case OP_IA64_CMP_LE_UN_IMM:
2672 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2674 case OP_IA64_FCMP_EQ:
2675 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2677 case OP_IA64_FCMP_NE:
2678 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2680 case OP_IA64_FCMP_LT:
2681 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2683 case OP_IA64_FCMP_GT:
2684 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2686 case OP_IA64_FCMP_LE:
2687 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2689 case OP_IA64_FCMP_GE:
2690 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2692 case OP_IA64_FCMP_GT_UN:
2693 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2694 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2696 case OP_IA64_FCMP_LT_UN:
2697 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2698 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2700 case OP_IA64_FCMP_GE_UN:
2701 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2702 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2704 case OP_IA64_FCMP_LE_UN:
2705 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2706 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2709 case OP_COND_EXC_IOV:
2710 case OP_COND_EXC_OV:
2711 add_patch_info (cfg, code,
2712 MONO_PATCH_INFO_EXC, "OverflowException");
2713 ia64_br_cond_pred (code, 6, 0);
2715 case OP_COND_EXC_IC:
2717 add_patch_info (cfg, code,
2718 MONO_PATCH_INFO_EXC, "OverflowException");
2719 ia64_br_cond_pred (code, 7, 0);
2721 case OP_IA64_COND_EXC:
2722 add_patch_info (cfg, code,
2723 MONO_PATCH_INFO_EXC, ins->inst_p1);
2724 ia64_br_cond_pred (code, 6, 0);
2727 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2728 ia64_no_stop (code);
2729 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2732 /* FIXME: Is this needed ? */
2733 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2736 /* FIXME: Is this needed ? */
2737 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2740 /* FIXME: Is this needed ? */
2741 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2744 /* FIXME: Is this needed */
2745 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2748 /* FIXME: Is this needed */
2749 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2752 /* FIXME: Is this needed */
2753 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2757 /* FIXME: Sign extend ? */
2758 ia64_mov (code, ins->dreg, ins->sreg1);
2762 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2769 double d = *(double *)ins->inst_p0;
2771 if ((d == 0.0) && (mono_signbit (d) == 0))
2772 ia64_fmov (code, ins->dreg, 0);
2774 ia64_fmov (code, ins->dreg, 1);
2776 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2777 ia64_movl (code, GP_SCRATCH_REG, 0);
2778 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2783 float f = *(float *)ins->inst_p0;
2785 if ((f == 0.0) && (mono_signbit (f) == 0))
2786 ia64_fmov (code, ins->dreg, 0);
2788 ia64_fmov (code, ins->dreg, 1);
2790 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2791 ia64_movl (code, GP_SCRATCH_REG, 0);
2792 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2797 ia64_fmov (code, ins->dreg, ins->sreg1);
2799 case OP_STORER8_MEMBASE_REG:
2800 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2802 case OP_STORER4_MEMBASE_REG:
2803 ia64_stfs_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2805 case OP_LOADR8_MEMBASE:
2806 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2808 case OP_LOADR4_MEMBASE:
2809 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2812 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2813 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2814 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2817 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2818 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2819 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2821 case OP_LCONV_TO_R8:
2822 /* FIXME: Difference with CEE_CONV_R8 ? */
2823 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2824 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2825 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2827 case OP_LCONV_TO_R4:
2828 /* FIXME: Difference with CEE_CONV_R4 ? */
2829 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2830 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2831 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2833 case OP_FCONV_TO_R4:
2834 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2836 case OP_FCONV_TO_I8:
2837 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2838 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2841 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2844 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2847 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2850 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2854 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2855 add_patch_info (cfg, code,
2856 MONO_PATCH_INFO_EXC, "ArithmeticException");
2857 ia64_br_cond_pred (code, 6, 0);
2859 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2860 add_patch_info (cfg, code,
2861 MONO_PATCH_INFO_EXC, "ArithmeticException");
2862 ia64_br_cond_pred (code, 6, 0);
2863 /* Positive infinity */
2864 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2865 add_patch_info (cfg, code,
2866 MONO_PATCH_INFO_EXC, "ArithmeticException");
2867 ia64_br_cond_pred (code, 6, 0);
2868 /* Negative infinity */
2869 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2870 add_patch_info (cfg, code,
2871 MONO_PATCH_INFO_EXC, "ArithmeticException");
2872 ia64_br_cond_pred (code, 6, 0);
2877 /* ensure ins->sreg1 is not NULL */
2878 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2881 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2882 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2889 call = (MonoCallInst*)ins;
2891 if (ins->flags & MONO_INST_HAS_METHOD)
2892 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2894 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2896 code = emit_move_return_value (cfg, ins, code);
2903 case OP_VOIDCALL_REG:
2904 call = (MonoCallInst*)ins;
2908 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2911 ia64_mov (code, IA64_R8, ins->sreg1);
2912 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2913 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2914 ia64_ld8 (code, IA64_GP, IA64_R8);
2915 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2917 code = emit_move_return_value (cfg, ins, code);
2920 case OP_FCALL_MEMBASE:
2921 case OP_LCALL_MEMBASE:
2922 case OP_VCALL_MEMBASE:
2923 case OP_VOIDCALL_MEMBASE:
2924 case OP_CALL_MEMBASE:
2926 * There are no membase instructions on ia64, but we can't
2927 * lower this since get_vcall_slot_addr () needs to decode it.
2930 /* Keep this in synch with get_vcall_slot_addr */
2931 if (ia64_is_imm14 (ins->inst_offset))
2932 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2934 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2935 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2938 ia64_begin_bundle (code);
2939 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2941 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2943 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2946 * This nop will tell get_vcall_slot_addr that this is a virtual
2949 ia64_nop_i (code, 0x12345);
2951 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2953 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2955 code = emit_move_return_value (cfg, ins, code);
2959 * Keep in sync with the code in emit_epilog.
2962 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2965 g_assert (!cfg->method->save_lmf);
2967 /* Load arguments into their original registers */
2968 code = emit_load_volatile_arguments (cfg, code);
2970 if (cfg->arch.stack_alloc_size) {
2971 if (cfg->arch.omit_fp) {
2972 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2973 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2975 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2976 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2980 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2982 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2983 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2985 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2986 ia64_movl (code, GP_SCRATCH_REG, 0);
2987 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2988 ia64_br_cond_reg (code, IA64_B6);
2993 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2999 /* FIXME: Sigaltstack support */
3001 /* keep alignment */
3002 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->sreg1);
3003 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_FRAME_ALIGNMENT - 1));
3004 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3006 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3008 ia64_mov (code, ins->dreg, IA64_SP);
3010 /* An area at sp is reserved by the ABI for parameter passing */
3011 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
3012 if (ia64_is_adds_imm (abi_offset))
3013 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3015 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3016 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3019 if (ins->flags & MONO_INST_INIT) {
3021 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3023 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3026 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3027 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3028 ia64_br_cond_pred (code, 8, -2);
3030 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3032 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3038 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
3039 ia64_ld8 (code, ins->dreg, ins->dreg);
3042 /* Synchronization */
3043 case OP_MEMORY_BARRIER:
3046 case OP_IA64_FETCHADD4_IMM:
3047 g_assert (ins->inst_offset == 0);
3048 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3049 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3051 case OP_IA64_FETCHADD8_IMM:
3052 g_assert (ins->inst_offset == 0);
3053 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3054 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3056 case OP_ATOMIC_EXCHANGE_I4:
3057 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3058 ia64_sxt4 (code, ins->dreg, ins->dreg);
3060 case OP_ATOMIC_EXCHANGE_I8:
3061 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3064 /* Exception handling */
3065 case OP_CALL_HANDLER:
3067 * Using a call instruction would mess up the register stack, so
3068 * save the return address to a register and use a
3071 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3072 ia64_mov (code, IA64_R15, IA64_R0);
3073 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3074 /* Add the length of OP_CALL_HANDLER */
3075 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3076 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3077 ia64_movl (code, GP_SCRATCH_REG2, 0);
3078 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3079 ia64_br_cond_reg (code, IA64_B6);
3080 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3082 case OP_START_HANDLER: {
3084 * We receive the return address in GP_SCRATCH_REG.
3086 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3089 * We might be called by call_filter, in which case the
3090 * the register stack is not set up correctly. So do it now.
3091 * Allocate a stack frame and set the fp register from the value
3092 * passed in by the caller.
3093 * R15 is used since it is writable using libunwind.
3094 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3096 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3097 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3098 /* Alloc is not predictable so we have to use a branch */
3099 ia64_br_cond_pred (code, 6, 3);
3100 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);
3101 ia64_mov (code, cfg->frame_reg, IA64_R15);
3102 /* Save the return address */
3103 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3104 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3105 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3109 case CEE_ENDFINALLY: {
3110 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3111 /* Return the saved arp_pfs value to call_filter */
3112 ia64_mov (code, IA64_R9, cfg->arch.reg_saved_ar_pfs);
3113 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3114 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3115 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3116 ia64_br_cond_reg (code, IA64_B6);
3119 case OP_ENDFILTER: {
3120 /* FIXME: Return the value */
3121 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3122 /* Return the saved arp_pfs value to call_filter */
3123 ia64_mov (code, IA64_R9, cfg->arch.reg_saved_ar_pfs);
3124 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3125 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3126 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3127 ia64_br_cond_reg (code, IA64_B6);
3131 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3132 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3133 (gpointer)"mono_arch_throw_exception");
3136 * This might be the last instruction in the method, so add a dummy
3137 * instruction so the unwinder will work.
3139 ia64_break_i (code, 0);
3142 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3143 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3144 (gpointer)"mono_arch_rethrow_exception");
3146 ia64_break_i (code, 0);
3150 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3151 g_assert_not_reached ();
3154 if ((code.buf - cfg->native_code - offset) > max_len) {
3155 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3156 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3157 g_assert_not_reached ();
3163 last_offset = offset;
3168 ia64_codegen_close (code);
3170 cfg->code_len = code.buf - cfg->native_code;
3174 mono_arch_register_lowlevel_calls (void)
3176 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3179 static Ia64InsType ins_types_in_template [32][3] = {
3180 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3181 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3182 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3183 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3184 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3185 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3188 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3189 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3190 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3191 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3192 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3193 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3194 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3195 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3196 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3197 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3198 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3199 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3202 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3203 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3204 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3205 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3208 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3209 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3214 static gboolean stops_in_template [32][3] = {
3215 { FALSE, FALSE, FALSE },
3216 { FALSE, FALSE, TRUE },
3217 { FALSE, TRUE, FALSE },
3218 { FALSE, TRUE, TRUE },
3219 { FALSE, FALSE, FALSE },
3220 { FALSE, FALSE, TRUE },
3221 { FALSE, FALSE, FALSE },
3222 { FALSE, FALSE, FALSE },
3224 { FALSE, FALSE, FALSE },
3225 { FALSE, FALSE, TRUE },
3226 { TRUE, FALSE, FALSE },
3227 { TRUE, FALSE, TRUE },
3228 { FALSE, FALSE, FALSE },
3229 { FALSE, FALSE, TRUE },
3230 { FALSE, FALSE, FALSE },
3231 { FALSE, FALSE, TRUE },
3233 { FALSE, FALSE, FALSE },
3234 { FALSE, FALSE, TRUE },
3235 { FALSE, FALSE, FALSE },
3236 { FALSE, FALSE, TRUE },
3237 { FALSE, FALSE, FALSE },
3238 { FALSE, FALSE, FALSE },
3239 { FALSE, FALSE, FALSE },
3240 { FALSE, FALSE, TRUE },
3242 { FALSE, FALSE, FALSE },
3243 { FALSE, FALSE, TRUE },
3244 { FALSE, FALSE, FALSE },
3245 { FALSE, FALSE, FALSE },
3246 { FALSE, FALSE, FALSE },
3247 { FALSE, FALSE, TRUE },
3248 { FALSE, FALSE, FALSE },
3249 { FALSE, FALSE, FALSE }
3252 static int last_stop_in_template [32] = {
3253 -1, 2, 1, 2, -1, 2, -1, -1,
3254 -1, 2, 0, 2, -1, 2, -1, 2,
3255 -1, 2, -1, 2, -1, -1, -1, 2,
3256 -1, 2, -1, -1, -1, 2, -1, -1
3259 static guint64 nops_for_ins_types [6] = {
3268 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3275 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3277 #define DEBUG_INS_SCHED(a)
3281 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3283 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3284 guint8 *deps = code->dep_info;
3285 gboolean need_stop, no_stop;
3287 for (i = 0; i < code->nins; ++i)
3291 current_deps_start = 0;
3292 current_ins_start = 0;
3293 deps_start [ins_index] = current_ins_start;
3296 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3297 while (pos < code->dep_info_pos) {
3299 switch (deps [pos]) {
3300 case IA64_END_OF_INS:
3302 current_ins_start = pos + 2;
3303 deps_start [ins_index] = current_ins_start;
3305 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3310 reg = deps [pos + 1];
3312 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3313 for (i = current_deps_start; i < current_ins_start; i += 2)
3314 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3318 reg = code->dep_info [pos + 1];
3320 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3321 for (i = current_deps_start; i < current_ins_start; i += 2)
3322 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3326 reg = deps [pos + 1];
3328 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3329 for (i = current_deps_start; i < current_ins_start; i += 2)
3330 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3333 case IA64_READ_PR_BRANCH:
3334 reg = deps [pos + 1];
3336 /* Writes to prs by non-float instructions are visible to branches */
3337 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3338 for (i = current_deps_start; i < current_ins_start; i += 2)
3339 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3343 reg = code->dep_info [pos + 1];
3345 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3346 for (i = current_deps_start; i < current_ins_start; i += 2)
3347 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3350 case IA64_WRITE_PR_FLOAT:
3351 reg = code->dep_info [pos + 1];
3353 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3354 for (i = current_deps_start; i < current_ins_start; i += 2)
3355 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3359 reg = deps [pos + 1];
3361 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3362 for (i = current_deps_start; i < current_ins_start; i += 2)
3363 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3367 reg = code->dep_info [pos + 1];
3369 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3370 for (i = current_deps_start; i < current_ins_start; i += 2)
3371 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3374 case IA64_READ_BR_BRANCH:
3375 reg = deps [pos + 1];
3377 /* Writes to brs are visible to branches */
3378 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3381 reg = deps [pos + 1];
3383 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3384 for (i = current_deps_start; i < current_ins_start; i += 2)
3385 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3389 reg = code->dep_info [pos + 1];
3391 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3392 for (i = current_deps_start; i < current_ins_start; i += 2)
3393 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3397 reg = deps [pos + 1];
3399 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3400 for (i = current_deps_start; i < current_ins_start; i += 2)
3401 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3405 reg = code->dep_info [pos + 1];
3407 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3408 for (i = current_deps_start; i < current_ins_start; i += 2)
3409 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3414 * Explicitly indicate that a stop is not required. Useful for
3415 * example when two predicated instructions with negated predicates
3416 * write the same registers.
3421 g_assert_not_reached ();
3425 if (need_stop && !no_stop) {
3426 g_assert (ins_index > 0);
3427 stops [ins_index - 1] = 1;
3429 DEBUG_INS_SCHED (printf ("STOP\n"));
3430 current_deps_start = current_ins_start;
3432 /* Skip remaining deps for this instruction */
3433 while (deps [pos] != IA64_END_OF_INS)
3438 if (code->nins > 0) {
3439 /* No dependency info for the last instruction */
3440 stops [code->nins - 1] = 1;
3443 deps_start [code->nins] = code->dep_info_pos;
3447 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3449 g_assert (n <= code->nins);
3450 int stop_pos, i, deps_to_shift, dep_shift;
3452 // if (n > 1) printf ("FOUND: %ld.\n", template);
3454 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3456 stop_pos = last_stop_in_template [template] + 1;
3460 /* Compute the number of 'real' instructions before the stop */
3461 deps_to_shift = stop_pos;
3462 if (stop_pos >= 3 && (nops & (1 << 2)))
3464 if (stop_pos >= 2 && (nops & (1 << 1)))
3466 if (stop_pos >= 1 && (nops & (1 << 0)))
3470 * We have to keep some dependencies whose instructions have been shifted
3471 * out of the buffer. So nullify the end_of_ins markers in the dependency
3474 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3475 if (code->dep_info [i] == IA64_END_OF_INS)
3476 code->dep_info [i] = IA64_NONE;
3478 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3479 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3480 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3482 dep_shift = deps_start [deps_to_shift];
3483 for (i = 0; i < code->nins + 1 - n; ++i)
3484 deps_start [i] = deps_start [n + i] - dep_shift;
3486 /* Determine the exact positions of instructions with unwind ops */
3487 if (code->unw_op_count) {
3489 int curr_ins, curr_ins_pos;
3492 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3493 for (i = 0; i < 3; ++i) {
3494 if (! (nops & (1 << i))) {
3495 ins_pos [curr_ins] = curr_ins_pos + i;
3500 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3501 if (code->unw_ops_pos [i] < n) {
3502 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3503 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3506 if (code->unw_op_pos < code->unw_op_count)
3507 code->unw_op_pos += n;
3510 if (n == code->nins) {
3515 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3516 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3517 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3523 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3525 int i, ins_type, template, nins_to_emit;
3526 int deps_start [16];
3531 * We implement a simple scheduler which tries to put three instructions
3532 * per bundle, then two, then one.
3534 ia64_analyze_deps (code, deps_start, stops);
3536 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3537 /* Find a suitable template */
3538 for (template = 0; template < 32; ++template) {
3539 if (stops_in_template [template][0] != stops [0] ||
3540 stops_in_template [template][1] != stops [1] ||
3541 stops_in_template [template][2] != stops [2])
3545 for (i = 0; i < 3; ++i) {
3546 ins_type = ins_types_in_template [template][i];
3547 switch (code->itypes [i]) {
3548 case IA64_INS_TYPE_A:
3549 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3552 found &= (ins_type == code->itypes [i]);
3558 found = debug_ins_sched ();
3561 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3567 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3568 /* Wait for more instructions */
3571 /* If it didn't work out, try putting two instructions into one bundle */
3572 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3573 /* Try a nop at the end */
3574 for (template = 0; template < 32; ++template) {
3575 if (stops_in_template [template][0] != stops [0] ||
3576 ((stops_in_template [template][1] != stops [1]) &&
3577 (stops_in_template [template][2] != stops [1])))
3581 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3582 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3585 if (!debug_ins_sched ())
3588 ia64_real_emit_bundle (code, deps_start, stops, 2, template, code->instructions [0], code->instructions [1], nops_for_ins_types [ins_types_in_template [template][2]], 1 << 2);
3593 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3594 /* Wait for more instructions */
3597 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3598 /* Try a nop in the middle */
3599 for (template = 0; template < 32; ++template) {
3600 if (((stops_in_template [template][0] != stops [0]) &&
3601 (stops_in_template [template][1] != stops [0])) ||
3602 stops_in_template [template][2] != stops [1])
3605 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3606 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3609 if (!debug_ins_sched ())
3612 ia64_real_emit_bundle (code, deps_start, stops, 2, template, code->instructions [0], nops_for_ins_types [ins_types_in_template [template][1]], code->instructions [1], 1 << 1);
3617 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3618 /* Try a nop at the beginning */
3619 for (template = 0; template < 32; ++template) {
3620 if ((stops_in_template [template][1] != stops [0]) ||
3621 (stops_in_template [template][2] != stops [1]))
3624 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3625 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3628 if (!debug_ins_sched ())
3631 ia64_real_emit_bundle (code, deps_start, stops, 2, template, nops_for_ins_types [ins_types_in_template [template][0]], code->instructions [0], code->instructions [1], 1 << 0);
3636 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3637 /* Wait for more instructions */
3641 nins_to_emit = code->nins;
3645 while (nins_to_emit > 0) {
3646 if (!debug_ins_sched ())
3648 switch (code->itypes [0]) {
3649 case IA64_INS_TYPE_A:
3651 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3653 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3655 case IA64_INS_TYPE_I:
3657 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3659 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3661 case IA64_INS_TYPE_M:
3663 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3665 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3667 case IA64_INS_TYPE_B:
3669 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3671 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3673 case IA64_INS_TYPE_F:
3675 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3677 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3679 case IA64_INS_TYPE_LX:
3680 if (stops [0] || stops [1])
3681 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3683 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3687 g_assert_not_reached ();
3693 unw_dyn_region_info_t*
3694 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3696 unw_dyn_region_info_t *r;
3698 g_assert (code->nins == 0);
3699 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3700 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3701 r->op_count = code->unw_op_count;
3702 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3703 code->unw_op_count = 0;
3704 code->unw_op_pos = 0;
3705 code->region_start = code->buf;
3711 ia64_patch (unsigned char* code, gpointer target)
3714 guint64 instructions [3];
3715 guint8 gen_buf [16];
3716 Ia64CodegenState gen;
3721 * code encodes both the position inside the buffer and code.nins when
3722 * the instruction was emitted.
3724 ins_to_skip = (guint64)code % 16;
3725 code = (unsigned char*)((guint64)code & ~15);
3728 * Search for the first instruction which is 'patchable', skipping
3729 * ins_to_skip instructions.
3734 template = ia64_bundle_template (code);
3735 instructions [0] = ia64_bundle_ins1 (code);
3736 instructions [1] = ia64_bundle_ins2 (code);
3737 instructions [2] = ia64_bundle_ins3 (code);
3739 ia64_codegen_init (gen, gen_buf);
3742 for (i = 0; i < 3; ++i) {
3743 guint64 ins = instructions [i];
3744 int opcode = ia64_ins_opcode (ins);
3746 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3754 switch (ins_types_in_template [template][i]) {
3755 case IA64_INS_TYPE_A:
3756 case IA64_INS_TYPE_M:
3757 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3759 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3760 instructions [i] = gen.instructions [0];
3766 case IA64_INS_TYPE_B:
3767 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3769 gint64 disp = ((guint8*)target - code) >> 4;
3772 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3774 instructions [i] = gen.instructions [0];
3777 else if (opcode == 5) {
3779 gint64 disp = ((guint8*)target - code) >> 4;
3782 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3783 instructions [i] = gen.instructions [0];
3789 case IA64_INS_TYPE_LX:
3793 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3795 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3796 instructions [1] = gen.instructions [0];
3797 instructions [2] = gen.instructions [1];
3810 ia64_codegen_init (gen, code);
3811 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3821 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3823 MonoJumpInfo *patch_info;
3825 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3826 unsigned char *ip = patch_info->ip.i + code;
3827 const unsigned char *target;
3829 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3831 if (mono_compile_aot) {
3835 ia64_patch (ip, (gpointer)target);
3840 mono_arch_emit_prolog (MonoCompile *cfg)
3842 MonoMethod *method = cfg->method;
3843 MonoMethodSignature *sig;
3845 int alloc_size, pos, i;
3846 Ia64CodegenState code;
3849 sig = mono_method_signature (method);
3852 cinfo = get_call_info (sig, FALSE);
3854 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3856 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3857 cfg->code_size += 1024;
3858 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3859 cfg->code_size += 1024;
3861 cfg->native_code = g_malloc (cfg->code_size);
3863 ia64_codegen_init (code, cfg->native_code);
3865 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3866 if (cfg->param_area)
3867 alloc_size += cfg->param_area;
3871 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3873 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3874 /* Force sp to be saved/restored */
3875 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3877 cfg->arch.stack_alloc_size = alloc_size;
3881 if (method->save_lmf) {
3882 /* No LMF on IA64 */
3887 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3888 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);
3889 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3890 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3892 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3893 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->frame_reg);
3894 ia64_mov (code, cfg->frame_reg, IA64_SP);
3898 int pagesize = getpagesize ();
3900 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3901 if (alloc_size >= pagesize) {
3902 gint32 remaining_size = alloc_size;
3904 /* Generate stack touching code */
3905 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3906 while (remaining_size >= pagesize) {
3907 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3908 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3909 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3910 remaining_size -= pagesize;
3914 if (ia64_is_imm14 (-alloc_size)) {
3915 if (cfg->arch.omit_fp)
3916 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3917 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3920 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3921 if (cfg->arch.omit_fp)
3922 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3923 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3927 ia64_begin_bundle (code);
3929 /* Initialize unwind info */
3930 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3932 if (sig->ret->type != MONO_TYPE_VOID) {
3933 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3934 /* Save volatile arguments to the stack */
3939 /* Keep this in sync with emit_load_volatile_arguments */
3940 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3941 ArgInfo *ainfo = cinfo->args + i;
3942 gint32 stack_offset;
3944 inst = cfg->varinfo [i];
3946 if (sig->hasthis && (i == 0))
3947 arg_type = &mono_defaults.object_class->byval_arg;
3949 arg_type = sig->params [i - sig->hasthis];
3951 arg_type = mono_type_get_underlying_type (arg_type);
3953 stack_offset = ainfo->offset + ARGS_OFFSET;
3955 /* Save volatile arguments to the stack */
3956 if (inst->opcode != OP_REGVAR) {
3957 switch (ainfo->storage) {
3960 /* FIXME: big offsets */
3961 g_assert (inst->opcode == OP_REGOFFSET);
3962 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3963 if (arg_type->byref)
3964 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3966 switch (arg_type->type) {
3968 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3971 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3974 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3982 if (ainfo->nslots != ainfo->nregs)
3985 g_assert (inst->opcode == OP_REGOFFSET);
3986 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3987 for (i = 0; i < ainfo->nregs; ++i) {
3988 switch (ainfo->atype) {
3989 case AggregateNormal:
3990 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3992 case AggregateSingleHFA:
3993 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3995 case AggregateDoubleHFA:
3996 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4004 g_assert_not_reached ();
4008 if (inst->opcode == OP_REGVAR) {
4009 /* Argument allocated to (non-volatile) register */
4010 switch (ainfo->storage) {
4012 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4013 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4016 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4017 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4025 if (method->save_lmf) {
4026 /* No LMF on IA64 */
4029 if (strstr (cfg->method->name, "end_invoke_int_IAsyncResult"))
4030 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
4032 ia64_codegen_close (code);
4036 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4037 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4039 cfg->code_len = code.buf - cfg->native_code;
4041 g_assert (cfg->code_len < cfg->code_size);
4043 cfg->arch.prolog_end_offset = cfg->code_len;
4049 mono_arch_emit_epilog (MonoCompile *cfg)
4051 MonoMethod *method = cfg->method;
4053 int max_epilog_size = 16 * 4;
4054 Ia64CodegenState code;
4059 if (mono_jit_trace_calls != NULL)
4060 max_epilog_size += 1024;
4062 cfg->arch.epilog_begin_offset = cfg->code_len;
4064 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4065 cfg->code_size *= 2;
4066 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4067 mono_jit_stats.code_reallocs++;
4070 /* FIXME: Emit unwind info */
4072 buf = cfg->native_code + cfg->code_len;
4074 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4075 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4077 ia64_codegen_init (code, buf);
4079 /* the code restoring the registers must be kept in sync with CEE_JMP */
4082 if (method->save_lmf) {
4083 /* No LMF on IA64 */
4086 /* Load returned vtypes into registers if needed */
4087 cinfo = get_call_info (mono_method_signature (method), FALSE);
4088 ainfo = &cinfo->ret;
4089 switch (ainfo->storage) {
4091 if (ainfo->nslots != ainfo->nregs)
4094 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4095 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4096 for (i = 0; i < ainfo->nregs; ++i) {
4097 switch (ainfo->atype) {
4098 case AggregateNormal:
4099 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4101 case AggregateSingleHFA:
4102 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4104 case AggregateDoubleHFA:
4105 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4108 g_assert_not_reached ();
4117 ia64_begin_bundle (code);
4119 code.region_start = cfg->native_code;
4121 /* Label the unwind state at the start of the exception throwing region */
4122 //ia64_unw_label_state (code, 1234);
4124 if (cfg->arch.stack_alloc_size) {
4125 if (cfg->arch.omit_fp) {
4126 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4127 ia64_unw_pop_frames (code, 1);
4128 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4130 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4131 ia64_unw_pop_frames (code, 1);
4132 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4136 ia64_unw_pop_frames (code, 1);
4137 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4140 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4141 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4142 ia64_br_ret_reg (code, IA64_B0);
4144 ia64_codegen_close (code);
4146 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4147 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4149 cfg->code_len = code.buf - cfg->native_code;
4151 g_assert (cfg->code_len < cfg->code_size);
4155 mono_arch_emit_exceptions (MonoCompile *cfg)
4157 MonoJumpInfo *patch_info;
4159 Ia64CodegenState code;
4160 gboolean empty = TRUE;
4161 //unw_dyn_region_info_t *r_exceptions;
4164 MonoClass *exc_classes [16];
4165 guint8 *exc_throw_start [16], *exc_throw_end [16];
4167 guint32 code_size = 0;
4169 /* Compute needed space */
4170 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4171 if (patch_info->type == MONO_PATCH_INFO_EXC)
4173 if (patch_info->type == MONO_PATCH_INFO_R8)
4174 code_size += 8 + 7; /* sizeof (double) + alignment */
4175 if (patch_info->type == MONO_PATCH_INFO_R4)
4176 code_size += 4 + 7; /* sizeof (float) + alignment */
4182 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4183 cfg->code_size *= 2;
4184 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4185 mono_jit_stats.code_reallocs++;
4188 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4190 /* The unwind state here is the same as before the epilog */
4191 //ia64_unw_copy_state (code, 1234);
4193 /* add code to raise exceptions */
4194 /* FIXME: Optimize this */
4196 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4197 switch (patch_info->type) {
4198 case MONO_PATCH_INFO_EXC: {
4199 MonoClass *exc_class;
4203 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4204 g_assert (exc_class);
4205 throw_ip = cfg->native_code + patch_info->ip.i;
4207 ia64_begin_bundle (code);
4209 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4211 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_class->type_token);
4213 ia64_begin_bundle (code);
4215 patch_info->data.name = "mono_arch_throw_corlib_exception";
4216 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4217 patch_info->ip.i = code.buf - cfg->native_code;
4220 ia64_movl (code, GP_SCRATCH_REG, 0);
4221 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4222 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4223 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4225 /* Compute the offset */
4226 buf = code.buf + 32;
4227 ia64_movl (code, cfg->arch.reg_out0 + 1, buf - throw_ip);
4229 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4240 /* The unwinder needs this to work */
4241 ia64_break_i (code, 0);
4243 ia64_codegen_close (code);
4246 //r_exceptions = mono_ia64_create_unwind_region (&code);
4247 //cfg->arch.r_epilog = r_exceptions;
4249 cfg->code_len = code.buf - cfg->native_code;
4251 g_assert (cfg->code_len < cfg->code_size);
4255 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4257 Ia64CodegenState code;
4258 CallInfo *cinfo = NULL;
4259 MonoMethodSignature *sig;
4261 int i, n, stack_area = 0;
4263 ia64_codegen_init (code, p);
4265 /* Keep this in sync with mono_arch_get_argument_info */
4267 if (enable_arguments) {
4268 /* Allocate a new area on the stack and save arguments there */
4269 sig = mono_method_signature (cfg->method);
4271 cinfo = get_call_info (sig, FALSE);
4273 n = sig->param_count + sig->hasthis;
4275 stack_area = ALIGN_TO (n * 8, 16);
4278 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4280 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4282 /* FIXME: Allocate out registers */
4284 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4286 /* Required by the ABI */
4287 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4289 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4290 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4292 /* Save arguments to the stack */
4293 for (i = 0; i < n; ++i) {
4294 ins = cfg->varinfo [i];
4296 if (ins->opcode == OP_REGVAR) {
4297 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4298 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4299 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4302 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4303 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4304 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4305 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4306 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4307 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4312 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4315 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4317 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4318 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4320 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4322 if (enable_arguments && stack_area) {
4323 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4325 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4327 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4332 ia64_codegen_close (code);
4338 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4340 Ia64CodegenState code;
4341 CallInfo *cinfo = NULL;
4342 MonoMethod *method = cfg->method;
4343 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4345 ia64_codegen_init (code, p);
4347 cinfo = get_call_info (sig, FALSE);
4349 /* Save return value + pass it to func */
4350 switch (cinfo->ret.storage) {
4354 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4355 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4358 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4359 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4360 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4361 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4363 case ArgValuetypeAddrInIReg:
4364 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4375 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4376 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4377 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4379 /* Restore return value */
4380 switch (cinfo->ret.storage) {
4384 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4387 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4388 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4390 case ArgValuetypeAddrInIReg:
4398 ia64_codegen_close (code);
4404 mono_arch_save_unwind_info (MonoCompile *cfg)
4408 /* FIXME: Unregister this for dynamic methods */
4410 di = g_malloc0 (sizeof (unw_dyn_info_t));
4411 di->start_ip = (unw_word_t) cfg->native_code;
4412 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4414 di->format = UNW_INFO_FORMAT_DYNAMIC;
4415 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4416 di->u.pi.regions = cfg->arch.r_pro;
4418 _U_dyn_register (di);
4422 unw_dyn_region_info_t *region = di->u.pi.regions;
4424 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4426 printf (" [Region: %d]\n", region->insn_count);
4427 region = region->next;
4434 mono_arch_flush_icache (guint8 *code, gint size)
4436 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4437 guint8* end = (guint8*)((guint64)code + size);
4439 #ifdef __INTEL_COMPILER
4440 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4447 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4448 /* FIXME: This could be increased to 128 on some cpus */
4455 mono_arch_flush_register_windows (void)
4457 /* Not needed because of libunwind */
4461 mono_arch_is_inst_imm (gint64 imm)
4463 /* The lowering pass will take care of it */
4469 * Determine whenever the trap whose info is in SIGINFO is caused by
4473 mono_arch_is_int_overflow (void *sigctx, void *info)
4475 /* Division is emulated with explicit overflow checks */
4480 mono_arch_get_patch_offset (guint8 *code)
4488 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4490 guint8 *bundle2 = code - 48;
4491 guint8 *bundle3 = code - 32;
4492 guint8 *bundle4 = code - 16;
4493 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4494 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4495 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4496 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4497 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4498 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4499 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4500 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4501 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4505 * Virtual calls are made with:
4507 * [MII] ld8 r31=[r8]
4511 * mov.sptk b6=r31,0x2000000000f32a80
4518 * br.call.sptk.few b0=b6;;
4521 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4522 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4523 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4524 (ins31 == IA64_NOP_M) &&
4525 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4526 (ins33 == IA64_NOP_I) &&
4527 (ins41 == IA64_NOP_M) &&
4528 (ins42 == IA64_NOP_I) &&
4529 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4530 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4531 g_assert (ins21 == IA64_NOP_M);
4532 g_assert (ins23 == IA64_NOP_I);
4533 g_assert (ia64_ins_opcode (ins22) == 0);
4534 g_assert (ia64_ins_x3 (ins22) == 7);
4535 g_assert (ia64_ins_x (ins22) == 0);
4536 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4541 * Must be a scratch register, since only those are saved by the trampoline
4543 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4545 g_assert (regs [reg]);
4554 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4561 static gboolean tls_offset_inited = FALSE;
4564 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4566 if (!tls_offset_inited) {
4567 tls_offset_inited = TRUE;
4569 appdomain_tls_offset = mono_domain_get_tls_offset ();
4570 thread_tls_offset = mono_thread_get_tls_offset ();
4575 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4580 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4582 MonoCallInst *call = (MonoCallInst*)inst;
4583 int out_reg = cfg->arch.reg_out0;
4586 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4589 if (cinfo->ret.storage == ArgAggregate) {
4590 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4593 * The valuetype is in registers after the call, need to be copied
4594 * to the stack. Save the address to a local here, so the call
4595 * instruction can access it.
4597 g_assert (local->opcode == OP_REGOFFSET);
4598 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4601 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4602 vtarg->sreg1 = vt_reg;
4603 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4604 mono_bblock_add_inst (cfg->cbb, vtarg);
4606 mono_call_inst_add_outarg_reg (call, vtarg->dreg, out_reg, FALSE);
4614 /* add the this argument */
4615 if (this_reg != -1) {
4617 MONO_INST_NEW (cfg, this, OP_MOVE);
4618 this->type = this_type;
4619 this->sreg1 = this_reg;
4620 this->dreg = mono_regstate_next_int (cfg->rs);
4621 mono_bblock_add_inst (cfg->cbb, this);
4623 mono_call_inst_add_outarg_reg (call, this->dreg, out_reg, FALSE);
4628 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4630 MonoInst *ins = NULL;
4632 if (cmethod->klass == mono_defaults.thread_class &&
4633 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4634 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4635 } else if(cmethod->klass->image == mono_defaults.corlib &&
4636 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4637 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4639 if (strcmp (cmethod->name, "Increment") == 0) {
4640 MonoInst *ins_iconst;
4643 if (fsig->params [0]->type == MONO_TYPE_I4)
4644 opcode = OP_ATOMIC_ADD_NEW_I4;
4645 else if (fsig->params [0]->type == MONO_TYPE_I8)
4646 opcode = OP_ATOMIC_ADD_NEW_I8;
4648 g_assert_not_reached ();
4649 MONO_INST_NEW (cfg, ins, opcode);
4650 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4651 ins_iconst->inst_imm = 1;
4653 ins->inst_i0 = args [0];
4654 ins->inst_i1 = ins_iconst;
4655 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4656 MonoInst *ins_iconst;
4659 if (fsig->params [0]->type == MONO_TYPE_I4)
4660 opcode = OP_ATOMIC_ADD_NEW_I4;
4661 else if (fsig->params [0]->type == MONO_TYPE_I8)
4662 opcode = OP_ATOMIC_ADD_NEW_I8;
4664 g_assert_not_reached ();
4665 MONO_INST_NEW (cfg, ins, opcode);
4666 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4667 ins_iconst->inst_imm = -1;
4669 ins->inst_i0 = args [0];
4670 ins->inst_i1 = ins_iconst;
4672 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4675 if (fsig->params [0]->type == MONO_TYPE_I4)
4676 opcode = OP_ATOMIC_EXCHANGE_I4;
4677 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4678 (fsig->params [0]->type == MONO_TYPE_I) ||
4679 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4680 opcode = OP_ATOMIC_EXCHANGE_I8;
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, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4689 /* 64 bit reads are already atomic */
4690 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4691 ins->inst_i0 = args [0];
4699 mono_arch_print_tree (MonoInst *tree, int arity)
4704 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4708 if (appdomain_tls_offset == -1)
4711 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4712 ins->inst_offset = appdomain_tls_offset;
4716 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4720 if (thread_tls_offset == -1)
4723 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4724 ins->inst_offset = thread_tls_offset;