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;
663 MonoMethodHeader *header;
665 if (cfg->arch.reg_local0 > 0)
669 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
671 header = mono_method_get_header (cfg->method);
673 /* Some registers are reserved for use by the prolog/epilog */
674 reserved_regs = header->num_clauses ? 4 : 3;
676 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
677 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
678 /* One registers is needed by instrument_epilog to save the return value */
680 if (cinfo->reg_usage < 2)
681 /* Number of arguments passed to function call in instrument_prolog */
682 cinfo->reg_usage = 2;
685 cfg->arch.reg_in0 = 32;
686 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
687 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
689 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
690 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
691 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
694 * Frames without handlers save sp to fp, frames with handlers save it into
695 * a dedicated register.
697 if (header->num_clauses)
698 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
700 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
702 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
703 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
704 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
708 * Need to allocate at least 2 out register for use by CEE_THROW / the system
709 * exception throwing code.
711 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
717 mono_arch_get_global_int_regs (MonoCompile *cfg)
722 mono_ia64_alloc_stacked_registers (cfg);
724 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
727 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
734 * mono_arch_regalloc_cost:
736 * Return the cost, in number of memory references, of the action of
737 * allocating the variable VMV into a register during global register
741 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
743 /* FIXME: Increase costs linearly to avoid using all local registers */
749 mono_arch_allocate_vars (MonoCompile *cfg)
751 MonoMethodSignature *sig;
752 MonoMethodHeader *header;
755 guint32 locals_stack_size, locals_stack_align;
759 header = mono_method_get_header (cfg->method);
761 sig = mono_method_signature (cfg->method);
763 cinfo = get_call_info (sig, FALSE);
766 * Determine whenever the frame pointer can be eliminated.
767 * FIXME: Remove some of the restrictions.
769 cfg->arch.omit_fp = TRUE;
771 if (!debug_omit_fp ())
772 cfg->arch.omit_fp = FALSE;
774 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
775 cfg->arch.omit_fp = FALSE;
776 if (header->num_clauses)
777 cfg->arch.omit_fp = FALSE;
779 cfg->arch.omit_fp = FALSE;
780 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
781 ArgInfo *ainfo = &cinfo->args [i];
783 if (ainfo->storage == ArgOnStack) {
785 * The stack offset can only be determined when the frame
788 cfg->arch.omit_fp = FALSE;
792 mono_ia64_alloc_stacked_registers (cfg);
795 * We use the ABI calling conventions for managed code as well.
796 * Exception: valuetypes are never passed or returned in registers.
799 if (cfg->arch.omit_fp) {
800 cfg->frame_reg = IA64_SP;
801 offset = ARGS_OFFSET;
804 /* Locals are allocated backwards from %fp */
805 cfg->frame_reg = cfg->arch.reg_fp;
809 if (cfg->method->save_lmf) {
813 if (sig->ret->type != MONO_TYPE_VOID) {
814 switch (cinfo->ret.storage) {
816 cfg->ret->opcode = OP_REGVAR;
817 cfg->ret->inst_c0 = cinfo->ret.reg;
820 cfg->ret->opcode = OP_REGVAR;
821 cfg->ret->inst_c0 = cinfo->ret.reg;
823 case ArgValuetypeAddrInIReg:
824 cfg->ret->opcode = OP_REGVAR;
825 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
828 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
829 if (cfg->arch.omit_fp)
830 g_assert_not_reached ();
831 offset = ALIGN_TO (offset, 8);
832 offset += cinfo->ret.nslots * 8;
833 cfg->ret->opcode = OP_REGOFFSET;
834 cfg->ret->inst_basereg = cfg->frame_reg;
835 cfg->ret->inst_offset = - offset;
838 g_assert_not_reached ();
840 cfg->ret->dreg = cfg->ret->inst_c0;
843 /* Allocate locals */
844 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
845 if (locals_stack_align) {
846 offset = ALIGN_TO (offset, locals_stack_align);
848 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
849 if (offsets [i] != -1) {
850 MonoInst *inst = cfg->varinfo [i];
851 inst->opcode = OP_REGOFFSET;
852 inst->inst_basereg = cfg->frame_reg;
853 if (cfg->arch.omit_fp)
854 inst->inst_offset = (offset + offsets [i]);
856 inst->inst_offset = - (offset + offsets [i]);
857 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
861 offset += locals_stack_size;
863 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
864 if (cfg->arch.omit_fp)
865 g_assert_not_reached ();
866 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
867 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
870 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
871 inst = cfg->varinfo [i];
872 if (inst->opcode != OP_REGVAR) {
873 ArgInfo *ainfo = &cinfo->args [i];
874 gboolean inreg = TRUE;
877 if (sig->hasthis && (i == 0))
878 arg_type = &mono_defaults.object_class->byval_arg;
880 arg_type = sig->params [i - sig->hasthis];
882 /* FIXME: VOLATILE is only set if the liveness pass runs */
883 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
886 inst->opcode = OP_REGOFFSET;
888 switch (ainfo->storage) {
890 inst->opcode = OP_REGVAR;
891 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
895 * Since float regs are volatile, we save the arguments to
896 * the stack in the prolog.
901 if (cfg->arch.omit_fp)
902 g_assert_not_reached ();
903 inst->opcode = OP_REGOFFSET;
904 inst->inst_basereg = cfg->frame_reg;
905 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
914 if (!inreg && (ainfo->storage != ArgOnStack)) {
915 inst->opcode = OP_REGOFFSET;
916 inst->inst_basereg = cfg->frame_reg;
917 /* These arguments are saved to the stack in the prolog */
918 switch (ainfo->storage) {
920 if (ainfo->atype == AggregateSingleHFA)
921 offset += ainfo->nslots * 4;
923 offset += ainfo->nslots * 8;
926 offset += sizeof (gpointer);
929 offset = ALIGN_TO (offset, sizeof (gpointer));
930 if (cfg->arch.omit_fp)
931 inst->inst_offset = offset;
933 inst->inst_offset = - offset;
938 if (cfg->arch.omit_fp && offset == 16)
941 cfg->stack_offset = offset;
947 mono_arch_create_vars (MonoCompile *cfg)
949 MonoMethodSignature *sig;
952 sig = mono_method_signature (cfg->method);
954 cinfo = get_call_info (sig, FALSE);
956 if (cinfo->ret.storage == ArgAggregate)
957 cfg->ret_var_is_local = TRUE;
963 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
967 arg->opcode = OP_OUTARG_REG;
968 arg->inst_left = tree;
969 arg->inst_right = (MonoInst*)call;
971 call->used_iregs |= 1 << reg;
974 arg->opcode = OP_OUTARG_FREG;
975 arg->inst_left = tree;
976 arg->inst_right = (MonoInst*)call;
978 call->used_fregs |= 1 << reg;
981 g_assert_not_reached ();
986 * take the arguments and generate the arch-specific
987 * instructions to properly call the function in call.
988 * This includes pushing, moving arguments to the right register
990 * Issue: who does the spilling if needed, and when?
993 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
996 MonoMethodSignature *sig;
997 int i, n, stack_size;
1003 mono_ia64_alloc_stacked_registers (cfg);
1005 sig = call->signature;
1006 n = sig->param_count + sig->hasthis;
1008 cinfo = get_call_info (sig, sig->pinvoke);
1010 if (cinfo->ret.storage == ArgAggregate) {
1011 /* The code in emit_this_vret_arg needs a local */
1012 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1013 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1016 for (i = 0; i < n; ++i) {
1017 ainfo = cinfo->args + i;
1019 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1020 MonoMethodSignature *tmp_sig;
1022 /* Emit the signature cookie just before the implicit arguments */
1024 /* FIXME: Add support for signature tokens to AOT */
1025 cfg->disable_aot = TRUE;
1027 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1030 * mono_ArgIterator_Setup assumes the signature cookie is
1031 * passed first and all the arguments which were before it are
1032 * passed on the stack after the signature. So compensate by
1033 * passing a different signature.
1035 tmp_sig = mono_metadata_signature_dup (call->signature);
1036 tmp_sig->param_count -= call->signature->sentinelpos;
1037 tmp_sig->sentinelpos = 0;
1038 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1040 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1041 sig_arg->inst_p0 = tmp_sig;
1043 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1044 arg->inst_left = sig_arg;
1045 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1046 arg->type = STACK_PTR;
1048 /* prepend, so they get reversed */
1049 arg->next = call->out_args;
1050 call->out_args = arg;
1053 if (is_virtual && i == 0) {
1054 /* the argument will be attached to the call instruction */
1055 in = call->args [i];
1059 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1060 in = call->args [i];
1061 arg->cil_code = in->cil_code;
1062 arg->inst_left = in;
1063 arg->type = in->type;
1064 /* prepend, so they get reversed */
1065 arg->next = call->out_args;
1066 call->out_args = arg;
1068 if (sig->hasthis && (i == 0))
1069 arg_type = &mono_defaults.object_class->byval_arg;
1071 arg_type = sig->params [i - sig->hasthis];
1073 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1074 MonoInst *stack_addr;
1078 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1079 size = sizeof (MonoTypedRef);
1080 align = sizeof (gpointer);
1084 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1087 * Other backends use mono_type_stack_size (), but that
1088 * aligns the size to 8, which is larger than the size of
1089 * the source, leading to reads of invalid memory if the
1090 * source is at the end of address space.
1092 size = mono_class_value_size (in->klass, &align);
1095 if (ainfo->storage == ArgAggregate) {
1096 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1099 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1102 * Part of the structure is passed in registers.
1104 for (i = 0; i < ainfo->nregs; ++i) {
1105 int offset, load_op, dest_reg, arg_storage;
1107 slot = ainfo->reg + i;
1109 if (ainfo->atype == AggregateSingleHFA) {
1110 load_op = CEE_LDIND_R4;
1112 dest_reg = ainfo->reg + i;
1113 arg_storage = ArgInFloatReg;
1114 } else if (ainfo->atype == AggregateDoubleHFA) {
1115 load_op = CEE_LDIND_R8;
1117 dest_reg = ainfo->reg + i;
1118 arg_storage = ArgInFloatReg;
1120 load_op = CEE_LDIND_I;
1122 dest_reg = cfg->arch.reg_out0 + ainfo->reg + i;
1123 arg_storage = ArgInIReg;
1126 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1127 load->ssa_op = MONO_SSA_LOAD;
1128 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1130 NEW_ICONST (cfg, offset_ins, offset);
1131 MONO_INST_NEW (cfg, load2, CEE_ADD);
1132 load2->inst_left = load;
1133 load2->inst_right = offset_ins;
1135 MONO_INST_NEW (cfg, load, load_op);
1136 load->inst_left = load2;
1141 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1142 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1143 if (set_reg != call->out_args) {
1144 set_reg->next = call->out_args;
1145 call->out_args = set_reg;
1150 * Part of the structure is passed on the stack.
1152 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1155 slot = ainfo->reg + i;
1157 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1158 load->ssa_op = MONO_SSA_LOAD;
1159 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1161 NEW_ICONST (cfg, offset_ins, (i * sizeof (gpointer)));
1162 MONO_INST_NEW (cfg, load2, CEE_ADD);
1163 load2->inst_left = load;
1164 load2->inst_right = offset_ins;
1166 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1167 load->inst_left = load2;
1172 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1173 outarg->inst_left = load;
1174 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1176 if (outarg != call->out_args) {
1177 outarg->next = call->out_args;
1178 call->out_args = outarg;
1182 /* Trees can't be shared so make a copy */
1183 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1184 arg->cil_code = in->cil_code;
1185 arg->ssa_op = MONO_SSA_STORE;
1186 arg->inst_left = vtaddr;
1187 arg->inst_right = in;
1188 arg->type = in->type;
1190 /* prepend, so they get reversed */
1191 arg->next = call->out_args;
1192 call->out_args = arg;
1195 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1196 stack_addr->inst_basereg = IA64_SP;
1197 stack_addr->inst_offset = 16 + ainfo->offset;
1198 stack_addr->inst_imm = size;
1200 arg->opcode = OP_OUTARG_VT;
1201 arg->inst_right = stack_addr;
1205 switch (ainfo->storage) {
1207 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1210 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1213 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1214 arg->opcode = OP_OUTARG_R4;
1217 arg->opcode = OP_OUTARG;
1218 arg->inst_imm = 16 + ainfo->offset;
1221 g_assert_not_reached ();
1227 call->stack_usage = cinfo->stack_usage;
1228 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1229 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1230 cfg->flags |= MONO_CFG_HAS_CALLS;
1238 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1240 MonoInst *ins, *last_ins = NULL;
1244 switch (ins->opcode) {
1253 if (ins->dreg == ins->sreg1) {
1255 last_ins->next = ins->next;
1262 * OP_MOVE sreg, dreg
1263 * OP_MOVE dreg, sreg
1265 if (last_ins && last_ins->opcode == OP_MOVE &&
1266 ins->sreg1 == last_ins->dreg &&
1267 ins->dreg == last_ins->sreg1) {
1268 last_ins->next = ins->next;
1275 /* remove unnecessary multiplication with 1 */
1276 if (ins->inst_imm == 1) {
1277 if (ins->dreg != ins->sreg1) {
1278 ins->opcode = OP_MOVE;
1280 last_ins->next = ins->next;
1291 bb->last_ins = last_ins;
1314 opcode_to_cond (int opcode)
1323 case OP_COND_EXC_EQ:
1326 case OP_COND_EXC_NE_UN:
1339 case OP_COND_EXC_LT:
1347 case OP_COND_EXC_GT:
1356 case OP_COND_EXC_LE_UN:
1370 case OP_COND_EXC_LT_UN:
1373 case OP_COND_EXC_GT_UN:
1381 printf ("%s\n", mono_inst_name (opcode));
1387 opcode_to_type (int opcode, int cmp_opcode)
1389 if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1391 else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1393 else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLE_UN))
1395 else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1397 else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLE_UN))
1399 else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1401 else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN)) {
1402 switch (cmp_opcode) {
1404 case OP_ICOMPARE_IMM:
1410 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1415 int cond_to_ia64_cmp [][3] = {
1416 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1417 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1418 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1419 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1420 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1421 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1422 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1423 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1424 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1425 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1429 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1431 return cond_to_ia64_cmp [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1434 int cond_to_ia64_cmp_imm [][3] = {
1435 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1436 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1437 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1438 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1439 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1440 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1441 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1442 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1443 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1444 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1448 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1450 /* The condition needs to be reversed */
1451 return cond_to_ia64_cmp_imm [opcode_to_cond (opcode)][opcode_to_type (opcode, cmp_opcode)];
1455 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1459 bb->code = to_insert;
1460 to_insert->next = ins;
1463 to_insert->next = ins->next;
1464 ins->next = to_insert;
1468 #define NEW_INS(cfg,dest,op) do { \
1469 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1470 (dest)->opcode = (op); \
1471 insert_after_ins (bb, last_ins, (dest)); \
1472 last_ins = (dest); \
1476 * mono_arch_lowering_pass:
1478 * Converts complex opcodes into simpler ones so that each IR instruction
1479 * corresponds to one machine instruction.
1482 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1484 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1487 if (bb->max_ireg > cfg->rs->next_vireg)
1488 cfg->rs->next_vireg = bb->max_ireg;
1489 if (bb->max_freg > cfg->rs->next_vfreg)
1490 cfg->rs->next_vfreg = bb->max_freg;
1493 switch (ins->opcode) {
1494 case OP_STOREI1_MEMBASE_IMM:
1495 case OP_STOREI2_MEMBASE_IMM:
1496 case OP_STOREI4_MEMBASE_IMM:
1497 case OP_STOREI8_MEMBASE_IMM:
1498 case OP_STORE_MEMBASE_IMM:
1499 /* There are no store_membase instructions on ia64 */
1500 if (ia64_is_imm14 (ins->inst_offset)) {
1501 NEW_INS (cfg, temp2, OP_ADD_IMM);
1502 temp2->sreg1 = ins->inst_destbasereg;
1503 temp2->inst_imm = ins->inst_offset;
1504 temp2->dreg = mono_regstate_next_int (cfg->rs);
1507 NEW_INS (cfg, temp, OP_I8CONST);
1508 temp->inst_c0 = ins->inst_offset;
1509 temp->dreg = mono_regstate_next_int (cfg->rs);
1510 NEW_INS (cfg, temp2, CEE_ADD);
1511 temp2->sreg1 = ins->inst_destbasereg;
1512 temp2->sreg2 = temp->dreg;
1513 temp2->dreg = mono_regstate_next_int (cfg->rs);
1516 switch (ins->opcode) {
1517 case OP_STOREI1_MEMBASE_IMM:
1518 ins->opcode = OP_STOREI1_MEMBASE_REG;
1520 case OP_STOREI2_MEMBASE_IMM:
1521 ins->opcode = OP_STOREI2_MEMBASE_REG;
1523 case OP_STOREI4_MEMBASE_IMM:
1524 ins->opcode = OP_STOREI4_MEMBASE_REG;
1526 case OP_STOREI8_MEMBASE_IMM:
1527 case OP_STORE_MEMBASE_IMM:
1528 ins->opcode = OP_STOREI8_MEMBASE_REG;
1531 g_assert_not_reached ();
1534 if (ins->inst_imm == 0)
1535 ins->sreg1 = IA64_R0;
1537 NEW_INS (cfg, temp3, OP_I8CONST);
1538 temp3->inst_c0 = ins->inst_imm;
1539 temp3->dreg = mono_regstate_next_int (cfg->rs);
1540 ins->sreg1 = temp3->dreg;
1543 ins->inst_offset = 0;
1544 ins->inst_destbasereg = temp2->dreg;
1546 case OP_STOREI1_MEMBASE_REG:
1547 case OP_STOREI2_MEMBASE_REG:
1548 case OP_STOREI4_MEMBASE_REG:
1549 case OP_STOREI8_MEMBASE_REG:
1550 case OP_STORER4_MEMBASE_REG:
1551 case OP_STORER8_MEMBASE_REG:
1552 case OP_STORE_MEMBASE_REG:
1553 /* There are no store_membase instructions on ia64 */
1554 if (ins->inst_offset == 0) {
1557 else if (ia64_is_imm14 (ins->inst_offset)) {
1558 NEW_INS (cfg, temp2, OP_ADD_IMM);
1559 temp2->sreg1 = ins->inst_destbasereg;
1560 temp2->inst_imm = ins->inst_offset;
1561 temp2->dreg = mono_regstate_next_int (cfg->rs);
1564 NEW_INS (cfg, temp, OP_I8CONST);
1565 temp->inst_c0 = ins->inst_offset;
1566 temp->dreg = mono_regstate_next_int (cfg->rs);
1567 NEW_INS (cfg, temp2, CEE_ADD);
1568 temp2->sreg1 = ins->inst_destbasereg;
1569 temp2->sreg2 = temp->dreg;
1570 temp2->dreg = mono_regstate_next_int (cfg->rs);
1573 ins->inst_offset = 0;
1574 ins->inst_destbasereg = temp2->dreg;
1576 case OP_LOADI1_MEMBASE:
1577 case OP_LOADU1_MEMBASE:
1578 case OP_LOADI2_MEMBASE:
1579 case OP_LOADU2_MEMBASE:
1580 case OP_LOADI4_MEMBASE:
1581 case OP_LOADU4_MEMBASE:
1582 case OP_LOADI8_MEMBASE:
1583 case OP_LOAD_MEMBASE:
1584 case OP_LOADR4_MEMBASE:
1585 case OP_LOADR8_MEMBASE:
1586 /* There are no load_membase instructions on ia64 */
1587 if (ins->inst_offset == 0) {
1590 else if (ia64_is_imm14 (ins->inst_offset)) {
1591 NEW_INS (cfg, temp2, OP_ADD_IMM);
1592 temp2->sreg1 = ins->inst_basereg;
1593 temp2->inst_imm = ins->inst_offset;
1594 temp2->dreg = mono_regstate_next_int (cfg->rs);
1597 NEW_INS (cfg, temp, OP_I8CONST);
1598 temp->inst_c0 = ins->inst_offset;
1599 temp->dreg = mono_regstate_next_int (cfg->rs);
1600 NEW_INS (cfg, temp2, CEE_ADD);
1601 temp2->sreg1 = ins->inst_basereg;
1602 temp2->sreg2 = temp->dreg;
1603 temp2->dreg = mono_regstate_next_int (cfg->rs);
1606 ins->inst_offset = 0;
1607 ins->inst_basereg = temp2->dreg;
1609 case OP_IA64_FETCHADD4_IMM:
1610 case OP_IA64_FETCHADD8_IMM:
1611 case OP_ATOMIC_EXCHANGE_I4:
1612 case OP_ATOMIC_EXCHANGE_I8:
1613 /* There are no membase instructions on ia64 */
1614 if (ia64_is_imm14 (ins->inst_offset)) {
1615 NEW_INS (cfg, temp2, OP_ADD_IMM);
1616 temp2->sreg1 = ins->inst_basereg;
1617 temp2->inst_imm = ins->inst_offset;
1618 temp2->dreg = mono_regstate_next_int (cfg->rs);
1621 NEW_INS (cfg, temp, OP_I8CONST);
1622 temp->inst_c0 = ins->inst_offset;
1623 temp->dreg = mono_regstate_next_int (cfg->rs);
1624 NEW_INS (cfg, temp2, CEE_ADD);
1625 temp2->sreg1 = ins->inst_basereg;
1626 temp2->sreg2 = temp->dreg;
1627 temp2->dreg = mono_regstate_next_int (cfg->rs);
1629 ins->inst_offset = 0;
1630 ins->inst_basereg = temp2->dreg;
1644 case OP_ISHR_UN_IMM:
1645 case OP_LSHR_UN_IMM: {
1646 gboolean is_imm = FALSE;
1647 gboolean switched = FALSE;
1649 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1650 ins->opcode = OP_ZEXT_I1;
1654 switch (ins->opcode) {
1657 is_imm = ia64_is_imm14 (ins->inst_imm);
1661 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1663 /* A = B - IMM -> A = B + (-IMM) */
1664 ins->inst_imm = - ins->inst_imm;
1665 ins->opcode = OP_IADD_IMM;
1673 is_imm = ia64_is_imm8 (ins->inst_imm);
1681 case OP_ISHR_UN_IMM:
1682 case OP_LSHR_UN_IMM:
1683 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1691 ins->sreg2 = ins->sreg1;
1695 switch (ins->opcode) {
1697 ins->opcode = CEE_ADD;
1700 ins->opcode = OP_IADD;
1703 ins->opcode = OP_ISUB;
1706 ins->opcode = OP_IAND;
1709 ins->opcode = OP_IOR;
1712 ins->opcode = OP_IXOR;
1715 ins->opcode = OP_ISHL;
1718 ins->opcode = OP_ISHR;
1720 case OP_ISHR_UN_IMM:
1721 ins->opcode = OP_ISHR_UN;
1724 ins->opcode = CEE_AND;
1727 ins->opcode = OP_LSHL;
1730 ins->opcode = OP_LSHL;
1733 ins->opcode = OP_LSHR;
1735 case OP_LSHR_UN_IMM:
1736 ins->opcode = OP_LSHR_UN;
1739 g_assert_not_reached ();
1742 if (ins->inst_imm == 0)
1743 ins->sreg2 = IA64_R0;
1745 NEW_INS (cfg, temp, OP_I8CONST);
1746 temp->inst_c0 = ins->inst_imm;
1747 temp->dreg = mono_regstate_next_int (cfg->rs);
1748 ins->sreg2 = temp->dreg;
1752 case OP_COMPARE_IMM:
1753 case OP_ICOMPARE_IMM: {
1754 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1758 * The compare_imm instructions have switched up arguments, and
1759 * some of them take an imm between -127 and 128.
1762 switch (next->opcode) {
1765 case OP_COND_EXC_LT:
1768 imm = ia64_is_imm8 (ins->inst_imm - 1);
1774 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1777 imm = ia64_is_imm8 (ins->inst_imm);
1782 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1783 ins->sreg2 = ins->sreg1;
1786 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1788 if (ins->inst_imm == 0)
1789 ins->sreg2 = IA64_R0;
1791 NEW_INS (cfg, temp, OP_I8CONST);
1792 temp->inst_c0 = ins->inst_imm;
1793 temp->dreg = mono_regstate_next_int (cfg->rs);
1794 ins->sreg2 = temp->dreg;
1798 switch (next->opcode) {
1819 next->opcode = OP_IA64_BR_COND;
1820 if (! (next->flags & MONO_INST_BRLABEL))
1821 next->inst_target_bb = next->inst_true_bb;
1823 case OP_COND_EXC_EQ:
1824 case OP_COND_EXC_GT:
1825 case OP_COND_EXC_LT:
1826 case OP_COND_EXC_GT_UN:
1827 case OP_COND_EXC_LE_UN:
1828 case OP_COND_EXC_NE_UN:
1829 case OP_COND_EXC_LT_UN:
1830 next->opcode = OP_IA64_COND_EXC;
1842 next->opcode = OP_IA64_CSET;
1845 printf ("%s\n", mono_inst_name (next->opcode));
1855 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1859 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1860 switch (next->opcode) {
1891 next->opcode = OP_IA64_BR_COND;
1892 if (! (next->flags & MONO_INST_BRLABEL))
1893 next->inst_target_bb = next->inst_true_bb;
1895 case OP_COND_EXC_LT:
1896 case OP_COND_EXC_GT:
1897 case OP_COND_EXC_GT_UN:
1898 case OP_COND_EXC_LE_UN:
1899 next->opcode = OP_IA64_COND_EXC;
1916 next->opcode = OP_IA64_CSET;
1919 printf ("%s\n", mono_inst_name (next->opcode));
1928 gboolean found = FALSE;
1929 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1931 /* First the easy cases */
1932 if (ins->inst_imm == 1) {
1933 ins->opcode = OP_MOVE;
1936 for (i = 1; i < 64; ++i)
1937 if (ins->inst_imm == (((gint64)1) << i)) {
1938 ins->opcode = shl_op;
1944 /* This could be optimized */
1947 for (i = 0; i < 64; ++i) {
1948 if (ins->inst_imm & (((gint64)1) << i)) {
1949 NEW_INS (cfg, temp, shl_op);
1950 temp->dreg = mono_regstate_next_int (cfg->rs);
1951 temp->sreg1 = ins->sreg1;
1955 sum_reg = temp->dreg;
1957 NEW_INS (cfg, temp2, CEE_ADD);
1958 temp2->dreg = mono_regstate_next_int (cfg->rs);
1959 temp2->sreg1 = sum_reg;
1960 temp2->sreg2 = temp->dreg;
1961 sum_reg = temp2->dreg;
1965 ins->opcode = OP_MOVE;
1966 ins->sreg1 = sum_reg;
1970 case CEE_CONV_OVF_U4:
1971 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1972 temp->sreg1 = ins->sreg1;
1973 temp->sreg2 = IA64_R0;
1975 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1976 temp->inst_p1 = (char*)"OverflowException";
1978 ins->opcode = OP_MOVE;
1980 case CEE_CONV_OVF_I4_UN:
1981 NEW_INS (cfg, temp, OP_ICONST);
1982 temp->inst_c0 = 0x7fffffff;
1983 temp->dreg = mono_regstate_next_int (cfg->rs);
1985 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1986 temp2->sreg1 = ins->sreg1;
1987 temp2->sreg2 = temp->dreg;
1989 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1990 temp->inst_p1 = (char*)"OverflowException";
1992 ins->opcode = OP_MOVE;
1994 case OP_FCONV_TO_I4:
1995 case OP_FCONV_TO_I2:
1996 case OP_FCONV_TO_U2:
1997 case OP_FCONV_TO_I1:
1998 case OP_FCONV_TO_U1:
1999 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
2000 temp->sreg1 = ins->sreg1;
2001 temp->dreg = ins->dreg;
2003 switch (ins->opcode) {
2004 case OP_FCONV_TO_I4:
2005 ins->opcode = OP_SEXT_I4;
2007 case OP_FCONV_TO_I2:
2008 ins->opcode = OP_SEXT_I2;
2010 case OP_FCONV_TO_U2:
2011 ins->opcode = OP_ZEXT_I4;
2013 case OP_FCONV_TO_I1:
2014 ins->opcode = OP_SEXT_I1;
2016 case OP_FCONV_TO_U1:
2017 ins->opcode = OP_ZEXT_I1;
2020 g_assert_not_reached ();
2022 ins->sreg1 = ins->dreg;
2030 bb->last_ins = last_ins;
2032 bb->max_ireg = cfg->rs->next_vireg;
2033 bb->max_freg = cfg->rs->next_vfreg;
2037 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
2042 mono_arch_lowering_pass (cfg, bb);
2044 mono_local_regalloc (cfg, bb);
2048 * emit_load_volatile_arguments:
2050 * Load volatile arguments from the stack to the original input registers.
2051 * Required before a tail call.
2053 static Ia64CodegenState
2054 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
2056 MonoMethod *method = cfg->method;
2057 MonoMethodSignature *sig;
2062 /* FIXME: Generate intermediate code instead */
2064 sig = mono_method_signature (method);
2066 cinfo = get_call_info (sig, FALSE);
2068 /* This is the opposite of the code in emit_prolog */
2069 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2070 ArgInfo *ainfo = cinfo->args + i;
2071 gint32 stack_offset;
2073 ins = cfg->varinfo [i];
2075 if (sig->hasthis && (i == 0))
2076 arg_type = &mono_defaults.object_class->byval_arg;
2078 arg_type = sig->params [i - sig->hasthis];
2080 arg_type = mono_type_get_underlying_type (arg_type);
2082 stack_offset = ainfo->offset + ARGS_OFFSET;
2084 /* Save volatile arguments to the stack */
2085 if (ins->opcode != OP_REGVAR) {
2086 switch (ainfo->storage) {
2089 /* FIXME: big offsets */
2090 g_assert (ins->opcode == OP_REGOFFSET);
2091 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2092 if (arg_type->byref)
2093 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2095 switch (arg_type->type) {
2097 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
2100 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
2103 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
2115 if (ins->opcode == OP_REGVAR) {
2116 /* Argument allocated to (non-volatile) register */
2117 switch (ainfo->storage) {
2119 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
2120 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
2123 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
2124 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2137 static Ia64CodegenState
2138 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2143 /* Move return value to the target register */
2144 switch (ins->opcode) {
2146 case OP_VOIDCALL_REG:
2147 case OP_VOIDCALL_MEMBASE:
2151 case OP_CALL_MEMBASE:
2154 case OP_LCALL_MEMBASE:
2155 g_assert (ins->dreg == IA64_R8);
2159 case OP_FCALL_MEMBASE:
2160 g_assert (ins->dreg == 8);
2164 case OP_VCALL_MEMBASE: {
2167 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
2168 storage = cinfo->ret.storage;
2170 if (storage == ArgAggregate) {
2171 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2173 /* Load address of stack space allocated for the return value */
2174 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2175 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2176 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2178 for (i = 0; i < cinfo->ret.nregs; ++i) {
2179 switch (cinfo->ret.atype) {
2180 case AggregateNormal:
2181 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2183 case AggregateSingleHFA:
2184 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2186 case AggregateDoubleHFA:
2187 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2190 g_assert_not_reached ();
2198 g_assert_not_reached ();
2204 #define add_patch_info(cfg,code,patch_type,data) do { \
2205 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2208 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2209 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2211 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2213 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2214 ia64_br_cond_pred (code, (predicate), 0); \
2217 static Ia64CodegenState
2218 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2220 add_patch_info (cfg, code, patch_type, data);
2222 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2224 /* mono_arch_nullify_class_init_trampoline will patch this */
2225 ia64_movl (code, GP_SCRATCH_REG, 0);
2226 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2227 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2228 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2229 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2232 /* Can't use a direct call since the displacement might be too small */
2233 /* mono_arch_patch_callsite will patch this */
2234 ia64_movl (code, GP_SCRATCH_REG, 0);
2235 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2236 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2242 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2245 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2250 Ia64CodegenState code;
2251 guint8 *code_start = cfg->native_code + cfg->code_len;
2252 MonoInst *last_ins = NULL;
2253 guint last_offset = 0;
2256 if (cfg->opt & MONO_OPT_PEEPHOLE)
2257 peephole_pass (cfg, bb);
2259 if (cfg->opt & MONO_OPT_LOOP) {
2263 if (cfg->verbose_level > 2)
2264 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2266 cpos = bb->max_offset;
2268 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2272 offset = code_start - cfg->native_code;
2274 ia64_codegen_init (code, code_start);
2277 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2283 offset = code.buf - cfg->native_code;
2285 max_len = ((int)(((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN])) + 128;
2287 while (offset + max_len + 16 > cfg->code_size) {
2288 ia64_codegen_close (code);
2290 offset = code.buf - cfg->native_code;
2292 cfg->code_size *= 2;
2293 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2294 code_start = cfg->native_code + offset;
2295 mono_jit_stats.code_reallocs++;
2297 ia64_codegen_init (code, code_start);
2300 mono_debug_record_line_number (cfg, ins, offset);
2302 switch (ins->opcode) {
2305 if (ia64_is_imm14 (ins->inst_c0))
2306 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2308 ia64_movl (code, ins->dreg, ins->inst_c0);
2311 ia64_mov (code, ins->dreg, ins->sreg1);
2314 case OP_IA64_BR_COND: {
2316 if (ins->opcode == OP_IA64_BR_COND)
2318 if (ins->flags & MONO_INST_BRLABEL) {
2319 if (ins->inst_i0->inst_c0) {
2322 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2323 ia64_br_cond_pred (code, pred, 0);
2326 if (ins->inst_target_bb->native_offset) {
2327 guint8 *pos = code.buf + code.nins;
2329 ia64_br_cond_pred (code, pred, 0);
2330 ia64_begin_bundle (code);
2331 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2333 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2334 ia64_br_cond_pred (code, pred, 0);
2340 ia64_begin_bundle (code);
2341 ins->inst_c0 = code.buf - cfg->native_code;
2346 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2347 ia64_br_cond_reg (code, IA64_B6);
2351 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2355 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2359 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2363 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2367 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2371 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2374 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2378 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2381 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2382 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2386 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2389 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2393 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2396 /* p6 and p7 is set if there is signed/unsigned overflow */
2398 /* Set p8-p9 == (sreg2 > 0) */
2399 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2401 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2403 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2404 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2405 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2406 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2408 /* res <u sreg1 => unsigned overflow */
2409 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2411 /* FIXME: Predicate this since this is a side effect */
2412 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2415 /* p6 and p7 is set if there is signed/unsigned overflow */
2417 /* Set p8-p9 == (sreg2 > 0) */
2418 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2420 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2422 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2423 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2424 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2425 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2427 /* sreg1 <u sreg2 => unsigned overflow */
2428 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2430 /* FIXME: Predicate this since this is a side effect */
2431 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2434 /* Same as OP_IADDCC */
2435 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2437 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2439 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2440 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2442 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2444 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2447 /* Same as OP_ISUBCC */
2449 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2451 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2453 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2454 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2456 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2458 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2462 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2466 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2469 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2472 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2477 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2480 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2483 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2485 case OP_ISHR_UN_IMM:
2486 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2487 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2489 case OP_LSHR_UN_IMM:
2490 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2493 case OP_STOREI1_MEMBASE_REG:
2494 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2496 case OP_STOREI2_MEMBASE_REG:
2497 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2499 case OP_STOREI4_MEMBASE_REG:
2500 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2502 case OP_STOREI8_MEMBASE_REG:
2503 case OP_STORE_MEMBASE_REG:
2504 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2507 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2508 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2510 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2511 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2513 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2514 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2516 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2517 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2520 case OP_LOADU1_MEMBASE:
2521 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2523 case OP_LOADU2_MEMBASE:
2524 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2526 case OP_LOADU4_MEMBASE:
2527 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2529 case OP_LOADI1_MEMBASE:
2530 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2531 ia64_sxt1 (code, ins->dreg, ins->dreg);
2533 case OP_LOADI2_MEMBASE:
2534 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2535 ia64_sxt2 (code, ins->dreg, ins->dreg);
2537 case OP_LOADI4_MEMBASE:
2538 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2539 ia64_sxt4 (code, ins->dreg, ins->dreg);
2541 case OP_LOAD_MEMBASE:
2542 case OP_LOADI8_MEMBASE:
2543 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2546 case OP_IA64_LOADU1_MEMBASE_INC:
2547 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2549 case OP_IA64_LOADU2_MEMBASE_INC:
2550 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2552 case OP_IA64_LOADU4_MEMBASE_INC:
2553 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2555 case OP_IA64_LOADI8_MEMBASE_INC:
2556 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2560 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2563 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2566 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2569 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2572 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2575 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2578 /* Compare opcodes */
2579 case OP_IA64_CMP4_EQ:
2580 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2582 case OP_IA64_CMP4_NE:
2583 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2585 case OP_IA64_CMP4_LE:
2586 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2588 case OP_IA64_CMP4_LT:
2589 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2591 case OP_IA64_CMP4_GE:
2592 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2594 case OP_IA64_CMP4_GT:
2595 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2597 case OP_IA64_CMP4_LT_UN:
2598 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2600 case OP_IA64_CMP4_LE_UN:
2601 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2603 case OP_IA64_CMP4_GT_UN:
2604 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2606 case OP_IA64_CMP4_GE_UN:
2607 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2609 case OP_IA64_CMP_EQ:
2610 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2612 case OP_IA64_CMP_NE:
2613 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2615 case OP_IA64_CMP_LE:
2616 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2618 case OP_IA64_CMP_LT:
2619 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2621 case OP_IA64_CMP_GE:
2622 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2624 case OP_IA64_CMP_GT:
2625 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2627 case OP_IA64_CMP_GT_UN:
2628 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2630 case OP_IA64_CMP_LT_UN:
2631 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2633 case OP_IA64_CMP_GE_UN:
2634 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2636 case OP_IA64_CMP_LE_UN:
2637 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2639 case OP_IA64_CMP4_EQ_IMM:
2640 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2642 case OP_IA64_CMP4_NE_IMM:
2643 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2645 case OP_IA64_CMP4_LE_IMM:
2646 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2648 case OP_IA64_CMP4_LT_IMM:
2649 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2651 case OP_IA64_CMP4_GE_IMM:
2652 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2654 case OP_IA64_CMP4_GT_IMM:
2655 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2657 case OP_IA64_CMP4_LT_UN_IMM:
2658 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2660 case OP_IA64_CMP4_LE_UN_IMM:
2661 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2663 case OP_IA64_CMP4_GT_UN_IMM:
2664 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2666 case OP_IA64_CMP4_GE_UN_IMM:
2667 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2669 case OP_IA64_CMP_EQ_IMM:
2670 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2672 case OP_IA64_CMP_NE_IMM:
2673 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2675 case OP_IA64_CMP_LE_IMM:
2676 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2678 case OP_IA64_CMP_LT_IMM:
2679 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2681 case OP_IA64_CMP_GE_IMM:
2682 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2684 case OP_IA64_CMP_GT_IMM:
2685 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2687 case OP_IA64_CMP_GT_UN_IMM:
2688 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2690 case OP_IA64_CMP_LT_UN_IMM:
2691 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2693 case OP_IA64_CMP_GE_UN_IMM:
2694 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2696 case OP_IA64_CMP_LE_UN_IMM:
2697 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2699 case OP_IA64_FCMP_EQ:
2700 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2702 case OP_IA64_FCMP_NE:
2703 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2705 case OP_IA64_FCMP_LT:
2706 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2708 case OP_IA64_FCMP_GT:
2709 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2711 case OP_IA64_FCMP_LE:
2712 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2714 case OP_IA64_FCMP_GE:
2715 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2717 case OP_IA64_FCMP_GT_UN:
2718 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2719 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2721 case OP_IA64_FCMP_LT_UN:
2722 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2723 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2725 case OP_IA64_FCMP_GE_UN:
2726 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2727 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2729 case OP_IA64_FCMP_LE_UN:
2730 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2731 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2734 case OP_COND_EXC_IOV:
2735 case OP_COND_EXC_OV:
2736 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2738 case OP_COND_EXC_IC:
2740 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2742 case OP_IA64_COND_EXC:
2743 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2746 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2747 ia64_no_stop (code);
2748 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2751 /* FIXME: Is this needed ? */
2752 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2755 /* FIXME: Is this needed ? */
2756 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2759 /* FIXME: Is this needed ? */
2760 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2763 /* FIXME: Is this needed */
2764 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2767 /* FIXME: Is this needed */
2768 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2771 /* FIXME: Is this needed */
2772 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2776 /* FIXME: Sign extend ? */
2777 ia64_mov (code, ins->dreg, ins->sreg1);
2781 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2788 double d = *(double *)ins->inst_p0;
2790 if ((d == 0.0) && (mono_signbit (d) == 0))
2791 ia64_fmov (code, ins->dreg, 0);
2793 ia64_fmov (code, ins->dreg, 1);
2795 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2796 ia64_movl (code, GP_SCRATCH_REG, 0);
2797 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2802 float f = *(float *)ins->inst_p0;
2804 if ((f == 0.0) && (mono_signbit (f) == 0))
2805 ia64_fmov (code, ins->dreg, 0);
2807 ia64_fmov (code, ins->dreg, 1);
2809 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2810 ia64_movl (code, GP_SCRATCH_REG, 0);
2811 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2816 ia64_fmov (code, ins->dreg, ins->sreg1);
2818 case OP_STORER8_MEMBASE_REG:
2819 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2821 case OP_STORER4_MEMBASE_REG:
2822 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2823 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2825 case OP_LOADR8_MEMBASE:
2826 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2828 case OP_LOADR4_MEMBASE:
2829 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2830 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2833 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2834 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2835 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2838 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2839 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2840 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2842 case OP_LCONV_TO_R8:
2843 /* FIXME: Difference with CEE_CONV_R8 ? */
2844 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2845 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2846 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2848 case OP_LCONV_TO_R4:
2849 /* FIXME: Difference with CEE_CONV_R4 ? */
2850 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2851 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2852 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2854 case OP_FCONV_TO_R4:
2855 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2857 case OP_FCONV_TO_I8:
2858 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2859 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2862 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2865 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2868 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2871 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2875 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2876 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2878 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2879 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2880 /* Positive infinity */
2881 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2882 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2883 /* Negative infinity */
2884 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2885 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2890 /* ensure ins->sreg1 is not NULL */
2891 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2894 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2895 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2902 call = (MonoCallInst*)ins;
2904 if (ins->flags & MONO_INST_HAS_METHOD)
2905 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2907 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2909 code = emit_move_return_value (cfg, ins, code);
2916 case OP_VOIDCALL_REG:
2917 call = (MonoCallInst*)ins;
2921 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2924 ia64_mov (code, IA64_R8, ins->sreg1);
2925 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2926 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2927 ia64_ld8 (code, IA64_GP, IA64_R8);
2928 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2930 code = emit_move_return_value (cfg, ins, code);
2933 case OP_FCALL_MEMBASE:
2934 case OP_LCALL_MEMBASE:
2935 case OP_VCALL_MEMBASE:
2936 case OP_VOIDCALL_MEMBASE:
2937 case OP_CALL_MEMBASE:
2939 * There are no membase instructions on ia64, but we can't
2940 * lower this since get_vcall_slot_addr () needs to decode it.
2943 /* Keep this in synch with get_vcall_slot_addr */
2944 if (ia64_is_imm14 (ins->inst_offset))
2945 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2947 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2948 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2951 ia64_begin_bundle (code);
2952 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2954 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2956 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2959 * This nop will tell get_vcall_slot_addr that this is a virtual
2962 ia64_nop_i (code, 0x12345);
2964 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2966 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2968 code = emit_move_return_value (cfg, ins, code);
2972 * Keep in sync with the code in emit_epilog.
2975 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2978 g_assert (!cfg->method->save_lmf);
2980 /* Load arguments into their original registers */
2981 code = emit_load_volatile_arguments (cfg, code);
2983 if (cfg->arch.stack_alloc_size) {
2984 if (cfg->arch.omit_fp) {
2985 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2986 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2988 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2989 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2993 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2995 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2996 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2998 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2999 ia64_movl (code, GP_SCRATCH_REG, 0);
3000 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3001 ia64_br_cond_reg (code, IA64_B6);
3006 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
3012 /* FIXME: Sigaltstack support */
3014 /* keep alignment */
3015 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->sreg1);
3016 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_FRAME_ALIGNMENT - 1));
3017 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3019 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
3021 ia64_mov (code, ins->dreg, IA64_SP);
3023 /* An area at sp is reserved by the ABI for parameter passing */
3024 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
3025 if (ia64_is_adds_imm (abi_offset))
3026 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
3028 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
3029 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
3032 if (ins->flags & MONO_INST_INIT) {
3034 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
3036 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3039 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
3040 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
3041 ia64_br_cond_pred (code, 8, -2);
3043 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3045 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3051 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
3052 ia64_ld8 (code, ins->dreg, ins->dreg);
3055 /* Synchronization */
3056 case OP_MEMORY_BARRIER:
3059 case OP_IA64_FETCHADD4_IMM:
3060 g_assert (ins->inst_offset == 0);
3061 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3062 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3064 case OP_IA64_FETCHADD8_IMM:
3065 g_assert (ins->inst_offset == 0);
3066 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
3067 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
3069 case OP_ATOMIC_EXCHANGE_I4:
3070 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3071 ia64_sxt4 (code, ins->dreg, ins->dreg);
3073 case OP_ATOMIC_EXCHANGE_I8:
3074 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
3077 /* Exception handling */
3078 case OP_CALL_HANDLER:
3080 * Using a call instruction would mess up the register stack, so
3081 * save the return address to a register and use a
3084 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3085 ia64_mov (code, IA64_R15, IA64_R0);
3086 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3087 /* Add the length of OP_CALL_HANDLER */
3088 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3089 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3090 ia64_movl (code, GP_SCRATCH_REG2, 0);
3091 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3092 ia64_br_cond_reg (code, IA64_B6);
3093 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3095 case OP_START_HANDLER: {
3097 * We receive the return address in GP_SCRATCH_REG.
3099 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3102 * R15 determines our caller. It is used since it is writable using
3104 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3105 * R15 != 0 means we are called by call_filter ().
3107 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3108 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3110 ia64_br_cond_pred (code, 6, 6);
3113 * Called by call_filter:
3114 * Allocate a new stack frame, and set the fp register from the
3115 * value passed in by the caller.
3116 * We allocate a similar frame as is done by the prolog, so
3117 * if an exception is thrown while executing the filter, the
3118 * unwinder can unwind through the filter frame using the unwind
3119 * info for the prolog.
3121 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);
3122 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3123 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3124 ia64_mov (code, cfg->frame_reg, IA64_R15);
3125 /* Signal to endfilter that we are called by call_filter */
3126 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3128 /* Save the return address */
3129 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3130 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3131 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3135 case CEE_ENDFINALLY:
3136 case OP_ENDFILTER: {
3137 /* FIXME: Return the value in ENDFILTER */
3138 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3140 /* Load the return address */
3141 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3142 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3145 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3146 ia64_br_cond_pred (code, 7, 4);
3148 /* Called by call_filter */
3150 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3151 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3152 ia64_br_ret_reg (code, IA64_B0);
3154 /* Called by CALL_HANDLER */
3155 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3156 ia64_br_cond_reg (code, IA64_B6);
3160 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3161 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3162 (gpointer)"mono_arch_throw_exception");
3165 * This might be the last instruction in the method, so add a dummy
3166 * instruction so the unwinder will work.
3168 ia64_break_i (code, 0);
3171 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3172 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3173 (gpointer)"mono_arch_rethrow_exception");
3175 ia64_break_i (code, 0);
3179 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3180 g_assert_not_reached ();
3183 if ((code.buf - cfg->native_code - offset) > max_len) {
3184 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3185 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3186 g_assert_not_reached ();
3192 last_offset = offset;
3197 ia64_codegen_close (code);
3199 cfg->code_len = code.buf - cfg->native_code;
3203 mono_arch_register_lowlevel_calls (void)
3205 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3208 static Ia64InsType ins_types_in_template [32][3] = {
3209 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3210 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3211 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3212 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3213 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3214 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3217 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3218 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3219 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3220 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3221 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3222 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3223 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3224 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3225 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3226 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3227 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3228 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3231 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3232 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3233 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3234 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3237 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3238 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3243 static gboolean stops_in_template [32][3] = {
3244 { FALSE, FALSE, FALSE },
3245 { FALSE, FALSE, TRUE },
3246 { FALSE, TRUE, FALSE },
3247 { FALSE, TRUE, TRUE },
3248 { FALSE, FALSE, FALSE },
3249 { FALSE, FALSE, TRUE },
3250 { FALSE, FALSE, FALSE },
3251 { FALSE, FALSE, FALSE },
3253 { FALSE, FALSE, FALSE },
3254 { FALSE, FALSE, TRUE },
3255 { TRUE, FALSE, FALSE },
3256 { TRUE, FALSE, TRUE },
3257 { FALSE, FALSE, FALSE },
3258 { FALSE, FALSE, TRUE },
3259 { FALSE, FALSE, FALSE },
3260 { FALSE, FALSE, TRUE },
3262 { FALSE, FALSE, FALSE },
3263 { FALSE, FALSE, TRUE },
3264 { FALSE, FALSE, FALSE },
3265 { FALSE, FALSE, TRUE },
3266 { FALSE, FALSE, FALSE },
3267 { FALSE, FALSE, FALSE },
3268 { FALSE, FALSE, FALSE },
3269 { FALSE, FALSE, TRUE },
3271 { FALSE, FALSE, FALSE },
3272 { FALSE, FALSE, TRUE },
3273 { FALSE, FALSE, FALSE },
3274 { FALSE, FALSE, FALSE },
3275 { FALSE, FALSE, FALSE },
3276 { FALSE, FALSE, TRUE },
3277 { FALSE, FALSE, FALSE },
3278 { FALSE, FALSE, FALSE }
3281 static int last_stop_in_template [32] = {
3282 -1, 2, 1, 2, -1, 2, -1, -1,
3283 -1, 2, 0, 2, -1, 2, -1, 2,
3284 -1, 2, -1, 2, -1, -1, -1, 2,
3285 -1, 2, -1, -1, -1, 2, -1, -1
3288 static guint64 nops_for_ins_types [6] = {
3297 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3304 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3306 #define DEBUG_INS_SCHED(a)
3310 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3312 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3313 guint8 *deps = code->dep_info;
3314 gboolean need_stop, no_stop;
3316 for (i = 0; i < code->nins; ++i)
3320 current_deps_start = 0;
3321 current_ins_start = 0;
3322 deps_start [ins_index] = current_ins_start;
3325 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3326 while (pos < code->dep_info_pos) {
3328 switch (deps [pos]) {
3329 case IA64_END_OF_INS:
3331 current_ins_start = pos + 2;
3332 deps_start [ins_index] = current_ins_start;
3334 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3339 reg = deps [pos + 1];
3341 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3342 for (i = current_deps_start; i < current_ins_start; i += 2)
3343 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3347 reg = code->dep_info [pos + 1];
3349 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3350 for (i = current_deps_start; i < current_ins_start; i += 2)
3351 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3355 reg = deps [pos + 1];
3357 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3358 for (i = current_deps_start; i < current_ins_start; i += 2)
3359 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3362 case IA64_READ_PR_BRANCH:
3363 reg = deps [pos + 1];
3365 /* Writes to prs by non-float instructions are visible to branches */
3366 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3367 for (i = current_deps_start; i < current_ins_start; i += 2)
3368 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3372 reg = code->dep_info [pos + 1];
3374 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3375 for (i = current_deps_start; i < current_ins_start; i += 2)
3376 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3379 case IA64_WRITE_PR_FLOAT:
3380 reg = code->dep_info [pos + 1];
3382 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3383 for (i = current_deps_start; i < current_ins_start; i += 2)
3384 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3388 reg = deps [pos + 1];
3390 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3391 for (i = current_deps_start; i < current_ins_start; i += 2)
3392 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3396 reg = code->dep_info [pos + 1];
3398 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3399 for (i = current_deps_start; i < current_ins_start; i += 2)
3400 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3403 case IA64_READ_BR_BRANCH:
3404 reg = deps [pos + 1];
3406 /* Writes to brs are visible to branches */
3407 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3410 reg = deps [pos + 1];
3412 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3413 for (i = current_deps_start; i < current_ins_start; i += 2)
3414 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3418 reg = code->dep_info [pos + 1];
3420 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3421 for (i = current_deps_start; i < current_ins_start; i += 2)
3422 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3426 reg = deps [pos + 1];
3428 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3429 for (i = current_deps_start; i < current_ins_start; i += 2)
3430 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3434 reg = code->dep_info [pos + 1];
3436 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3437 for (i = current_deps_start; i < current_ins_start; i += 2)
3438 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3443 * Explicitly indicate that a stop is not required. Useful for
3444 * example when two predicated instructions with negated predicates
3445 * write the same registers.
3450 g_assert_not_reached ();
3454 if (need_stop && !no_stop) {
3455 g_assert (ins_index > 0);
3456 stops [ins_index - 1] = 1;
3458 DEBUG_INS_SCHED (printf ("STOP\n"));
3459 current_deps_start = current_ins_start;
3461 /* Skip remaining deps for this instruction */
3462 while (deps [pos] != IA64_END_OF_INS)
3467 if (code->nins > 0) {
3468 /* No dependency info for the last instruction */
3469 stops [code->nins - 1] = 1;
3472 deps_start [code->nins] = code->dep_info_pos;
3476 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3478 int stop_pos, i, deps_to_shift, dep_shift;
3480 g_assert (n <= code->nins);
3482 // if (n > 1) printf ("FOUND: %ld.\n", template);
3484 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3486 stop_pos = last_stop_in_template [template] + 1;
3490 /* Compute the number of 'real' instructions before the stop */
3491 deps_to_shift = stop_pos;
3492 if (stop_pos >= 3 && (nops & (1 << 2)))
3494 if (stop_pos >= 2 && (nops & (1 << 1)))
3496 if (stop_pos >= 1 && (nops & (1 << 0)))
3500 * We have to keep some dependencies whose instructions have been shifted
3501 * out of the buffer. So nullify the end_of_ins markers in the dependency
3504 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3505 if (code->dep_info [i] == IA64_END_OF_INS)
3506 code->dep_info [i] = IA64_NONE;
3508 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3509 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3510 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3512 dep_shift = deps_start [deps_to_shift];
3513 for (i = 0; i < code->nins + 1 - n; ++i)
3514 deps_start [i] = deps_start [n + i] - dep_shift;
3516 /* Determine the exact positions of instructions with unwind ops */
3517 if (code->unw_op_count) {
3519 int curr_ins, curr_ins_pos;
3522 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3523 for (i = 0; i < 3; ++i) {
3524 if (! (nops & (1 << i))) {
3525 ins_pos [curr_ins] = curr_ins_pos + i;
3530 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3531 if (code->unw_ops_pos [i] < n) {
3532 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3533 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3536 if (code->unw_op_pos < code->unw_op_count)
3537 code->unw_op_pos += n;
3540 if (n == code->nins) {
3545 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3546 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3547 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3553 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3555 int i, ins_type, template, nins_to_emit;
3556 int deps_start [16];
3561 * We implement a simple scheduler which tries to put three instructions
3562 * per bundle, then two, then one.
3564 ia64_analyze_deps (code, deps_start, stops);
3566 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3567 /* Find a suitable template */
3568 for (template = 0; template < 32; ++template) {
3569 if (stops_in_template [template][0] != stops [0] ||
3570 stops_in_template [template][1] != stops [1] ||
3571 stops_in_template [template][2] != stops [2])
3575 for (i = 0; i < 3; ++i) {
3576 ins_type = ins_types_in_template [template][i];
3577 switch (code->itypes [i]) {
3578 case IA64_INS_TYPE_A:
3579 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3582 found &= (ins_type == code->itypes [i]);
3588 found = debug_ins_sched ();
3591 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3597 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3598 /* Wait for more instructions */
3601 /* If it didn't work out, try putting two instructions into one bundle */
3602 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3603 /* Try a nop at the end */
3604 for (template = 0; template < 32; ++template) {
3605 if (stops_in_template [template][0] != stops [0] ||
3606 ((stops_in_template [template][1] != stops [1]) &&
3607 (stops_in_template [template][2] != stops [1])))
3611 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3612 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3615 if (!debug_ins_sched ())
3618 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);
3623 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3624 /* Wait for more instructions */
3627 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3628 /* Try a nop in the middle */
3629 for (template = 0; template < 32; ++template) {
3630 if (((stops_in_template [template][0] != stops [0]) &&
3631 (stops_in_template [template][1] != stops [0])) ||
3632 stops_in_template [template][2] != stops [1])
3635 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3636 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3639 if (!debug_ins_sched ())
3642 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);
3647 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3648 /* Try a nop at the beginning */
3649 for (template = 0; template < 32; ++template) {
3650 if ((stops_in_template [template][1] != stops [0]) ||
3651 (stops_in_template [template][2] != stops [1]))
3654 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3655 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3658 if (!debug_ins_sched ())
3661 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);
3666 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3667 /* Wait for more instructions */
3671 nins_to_emit = code->nins;
3675 while (nins_to_emit > 0) {
3676 if (!debug_ins_sched ())
3678 switch (code->itypes [0]) {
3679 case IA64_INS_TYPE_A:
3681 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3683 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3685 case IA64_INS_TYPE_I:
3687 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3689 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3691 case IA64_INS_TYPE_M:
3693 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3695 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3697 case IA64_INS_TYPE_B:
3699 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3701 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3703 case IA64_INS_TYPE_F:
3705 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3707 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3709 case IA64_INS_TYPE_LX:
3710 if (stops [0] || stops [1])
3711 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3713 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3717 g_assert_not_reached ();
3723 unw_dyn_region_info_t*
3724 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3726 unw_dyn_region_info_t *r;
3728 g_assert (code->nins == 0);
3729 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3730 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3731 r->op_count = code->unw_op_count;
3732 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3733 code->unw_op_count = 0;
3734 code->unw_op_pos = 0;
3735 code->region_start = code->buf;
3741 ia64_patch (unsigned char* code, gpointer target)
3744 guint64 instructions [3];
3745 guint8 gen_buf [16];
3746 Ia64CodegenState gen;
3751 * code encodes both the position inside the buffer and code.nins when
3752 * the instruction was emitted.
3754 ins_to_skip = (guint64)code % 16;
3755 code = (unsigned char*)((guint64)code & ~15);
3758 * Search for the first instruction which is 'patchable', skipping
3759 * ins_to_skip instructions.
3764 template = ia64_bundle_template (code);
3765 instructions [0] = ia64_bundle_ins1 (code);
3766 instructions [1] = ia64_bundle_ins2 (code);
3767 instructions [2] = ia64_bundle_ins3 (code);
3769 ia64_codegen_init (gen, gen_buf);
3772 for (i = 0; i < 3; ++i) {
3773 guint64 ins = instructions [i];
3774 int opcode = ia64_ins_opcode (ins);
3776 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3784 switch (ins_types_in_template [template][i]) {
3785 case IA64_INS_TYPE_A:
3786 case IA64_INS_TYPE_M:
3787 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3789 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3790 instructions [i] = gen.instructions [0];
3796 case IA64_INS_TYPE_B:
3797 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3799 gint64 disp = ((guint8*)target - code) >> 4;
3802 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3804 instructions [i] = gen.instructions [0];
3807 else if (opcode == 5) {
3809 gint64 disp = ((guint8*)target - code) >> 4;
3812 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3813 instructions [i] = gen.instructions [0];
3819 case IA64_INS_TYPE_LX:
3823 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3825 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3826 instructions [1] = gen.instructions [0];
3827 instructions [2] = gen.instructions [1];
3840 ia64_codegen_init (gen, code);
3841 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3851 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3853 MonoJumpInfo *patch_info;
3855 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3856 unsigned char *ip = patch_info->ip.i + code;
3857 const unsigned char *target;
3859 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3861 if (patch_info->type == MONO_PATCH_INFO_NONE)
3863 if (mono_compile_aot) {
3867 ia64_patch (ip, (gpointer)target);
3872 mono_arch_emit_prolog (MonoCompile *cfg)
3874 MonoMethod *method = cfg->method;
3875 MonoMethodSignature *sig;
3877 int alloc_size, pos, i;
3878 Ia64CodegenState code;
3881 sig = mono_method_signature (method);
3884 cinfo = get_call_info (sig, FALSE);
3886 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3888 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3889 cfg->code_size += 1024;
3890 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3891 cfg->code_size += 1024;
3893 cfg->native_code = g_malloc (cfg->code_size);
3895 ia64_codegen_init (code, cfg->native_code);
3897 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3898 if (cfg->param_area)
3899 alloc_size += cfg->param_area;
3903 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3905 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3906 /* Force sp to be saved/restored */
3907 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3909 cfg->arch.stack_alloc_size = alloc_size;
3913 if (method->save_lmf) {
3914 /* No LMF on IA64 */
3919 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3920 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);
3921 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3922 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3924 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3925 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3926 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3927 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3928 ia64_mov (code, cfg->frame_reg, IA64_SP);
3932 int pagesize = getpagesize ();
3934 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3935 if (alloc_size >= pagesize) {
3936 gint32 remaining_size = alloc_size;
3938 /* Generate stack touching code */
3939 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3940 while (remaining_size >= pagesize) {
3941 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3942 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3943 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3944 remaining_size -= pagesize;
3948 if (ia64_is_imm14 (-alloc_size)) {
3949 if (cfg->arch.omit_fp)
3950 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3951 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3954 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3955 if (cfg->arch.omit_fp)
3956 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3957 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3961 ia64_begin_bundle (code);
3963 /* Initialize unwind info */
3964 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3966 if (sig->ret->type != MONO_TYPE_VOID) {
3967 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3968 /* Save volatile arguments to the stack */
3973 /* Keep this in sync with emit_load_volatile_arguments */
3974 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3975 ArgInfo *ainfo = cinfo->args + i;
3976 gint32 stack_offset;
3978 inst = cfg->varinfo [i];
3980 if (sig->hasthis && (i == 0))
3981 arg_type = &mono_defaults.object_class->byval_arg;
3983 arg_type = sig->params [i - sig->hasthis];
3985 arg_type = mono_type_get_underlying_type (arg_type);
3987 stack_offset = ainfo->offset + ARGS_OFFSET;
3989 /* Save volatile arguments to the stack */
3990 if (inst->opcode != OP_REGVAR) {
3991 switch (ainfo->storage) {
3994 /* FIXME: big offsets */
3995 g_assert (inst->opcode == OP_REGOFFSET);
3996 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3997 if (arg_type->byref)
3998 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4000 switch (arg_type->type) {
4002 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4005 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
4008 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
4016 if (ainfo->nslots != ainfo->nregs)
4019 g_assert (inst->opcode == OP_REGOFFSET);
4020 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
4021 for (i = 0; i < ainfo->nregs; ++i) {
4022 switch (ainfo->atype) {
4023 case AggregateNormal:
4024 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
4026 case AggregateSingleHFA:
4027 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
4029 case AggregateDoubleHFA:
4030 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4038 g_assert_not_reached ();
4042 if (inst->opcode == OP_REGVAR) {
4043 /* Argument allocated to (non-volatile) register */
4044 switch (ainfo->storage) {
4046 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4047 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4050 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4051 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4059 if (method->save_lmf) {
4060 /* No LMF on IA64 */
4063 if (strstr (cfg->method->name, "end_invoke_int_IAsyncResult"))
4064 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
4066 ia64_codegen_close (code);
4070 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4071 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4073 cfg->code_len = code.buf - cfg->native_code;
4075 g_assert (cfg->code_len < cfg->code_size);
4077 cfg->arch.prolog_end_offset = cfg->code_len;
4083 mono_arch_emit_epilog (MonoCompile *cfg)
4085 MonoMethod *method = cfg->method;
4087 int max_epilog_size = 16 * 4;
4088 Ia64CodegenState code;
4093 if (mono_jit_trace_calls != NULL)
4094 max_epilog_size += 1024;
4096 cfg->arch.epilog_begin_offset = cfg->code_len;
4098 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4099 cfg->code_size *= 2;
4100 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4101 mono_jit_stats.code_reallocs++;
4104 /* FIXME: Emit unwind info */
4106 buf = cfg->native_code + cfg->code_len;
4108 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4109 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4111 ia64_codegen_init (code, buf);
4113 /* the code restoring the registers must be kept in sync with CEE_JMP */
4116 if (method->save_lmf) {
4117 /* No LMF on IA64 */
4120 /* Load returned vtypes into registers if needed */
4121 cinfo = get_call_info (mono_method_signature (method), FALSE);
4122 ainfo = &cinfo->ret;
4123 switch (ainfo->storage) {
4125 if (ainfo->nslots != ainfo->nregs)
4128 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4129 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4130 for (i = 0; i < ainfo->nregs; ++i) {
4131 switch (ainfo->atype) {
4132 case AggregateNormal:
4133 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4135 case AggregateSingleHFA:
4136 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4138 case AggregateDoubleHFA:
4139 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4142 g_assert_not_reached ();
4151 ia64_begin_bundle (code);
4153 code.region_start = cfg->native_code;
4155 /* Label the unwind state at the start of the exception throwing region */
4156 //ia64_unw_label_state (code, 1234);
4158 if (cfg->arch.stack_alloc_size) {
4159 if (cfg->arch.omit_fp) {
4160 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4161 ia64_unw_pop_frames (code, 1);
4162 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4164 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4165 ia64_unw_pop_frames (code, 1);
4166 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4170 ia64_unw_pop_frames (code, 1);
4171 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4174 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4175 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4176 ia64_br_ret_reg (code, IA64_B0);
4178 ia64_codegen_close (code);
4180 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4181 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4183 cfg->code_len = code.buf - cfg->native_code;
4185 g_assert (cfg->code_len < cfg->code_size);
4189 mono_arch_emit_exceptions (MonoCompile *cfg)
4191 MonoJumpInfo *patch_info;
4193 Ia64CodegenState code;
4194 gboolean empty = TRUE;
4195 //unw_dyn_region_info_t *r_exceptions;
4196 MonoClass *exc_classes [16];
4197 guint8 *exc_throw_start [16], *exc_throw_end [16];
4198 guint32 code_size = 0;
4200 /* Compute needed space */
4201 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4202 if (patch_info->type == MONO_PATCH_INFO_EXC)
4204 if (patch_info->type == MONO_PATCH_INFO_R8)
4205 code_size += 8 + 7; /* sizeof (double) + alignment */
4206 if (patch_info->type == MONO_PATCH_INFO_R4)
4207 code_size += 4 + 7; /* sizeof (float) + alignment */
4213 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4214 cfg->code_size *= 2;
4215 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4216 mono_jit_stats.code_reallocs++;
4219 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4221 /* The unwind state here is the same as before the epilog */
4222 //ia64_unw_copy_state (code, 1234);
4224 /* add code to raise exceptions */
4225 /* FIXME: Optimize this */
4227 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4228 switch (patch_info->type) {
4229 case MONO_PATCH_INFO_EXC: {
4230 MonoClass *exc_class;
4233 guint64 exc_token_index;
4235 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4236 g_assert (exc_class);
4237 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4238 throw_ip = cfg->native_code + patch_info->ip.i;
4240 ia64_begin_bundle (code);
4242 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4244 /* Find a throw sequence for the same exception class */
4245 for (i = 0; i < nthrows; ++i)
4246 if (exc_classes [i] == exc_class)
4250 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4252 if (ia64_is_adds_imm (offset))
4253 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4255 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4257 buf = code.buf + code.nins;
4258 ia64_br_cond_pred (code, 0, 0);
4259 ia64_begin_bundle (code);
4260 ia64_patch (buf, exc_throw_start [i]);
4262 patch_info->type = MONO_PATCH_INFO_NONE;
4267 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4269 ia64_begin_bundle (code);
4272 exc_classes [nthrows] = exc_class;
4273 exc_throw_start [nthrows] = code.buf;
4277 if (ia64_is_adds_imm (exc_token_index))
4278 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4280 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4282 patch_info->data.name = "mono_arch_throw_corlib_exception";
4283 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4284 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4287 ia64_movl (code, GP_SCRATCH_REG, 0);
4288 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4289 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4290 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4292 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4294 /* Patch up the throw offset */
4295 ia64_begin_bundle (code);
4297 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4300 exc_throw_end [nthrows] = code.buf;
4314 /* The unwinder needs this to work */
4315 ia64_break_i (code, 0);
4317 ia64_codegen_close (code);
4320 //r_exceptions = mono_ia64_create_unwind_region (&code);
4321 //cfg->arch.r_epilog = r_exceptions;
4323 cfg->code_len = code.buf - cfg->native_code;
4325 g_assert (cfg->code_len < cfg->code_size);
4329 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4331 Ia64CodegenState code;
4332 CallInfo *cinfo = NULL;
4333 MonoMethodSignature *sig;
4335 int i, n, stack_area = 0;
4337 ia64_codegen_init (code, p);
4339 /* Keep this in sync with mono_arch_get_argument_info */
4341 if (enable_arguments) {
4342 /* Allocate a new area on the stack and save arguments there */
4343 sig = mono_method_signature (cfg->method);
4345 cinfo = get_call_info (sig, FALSE);
4347 n = sig->param_count + sig->hasthis;
4349 stack_area = ALIGN_TO (n * 8, 16);
4352 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4354 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4356 /* FIXME: Allocate out registers */
4358 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4360 /* Required by the ABI */
4361 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4363 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4364 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4366 /* Save arguments to the stack */
4367 for (i = 0; i < n; ++i) {
4368 ins = cfg->varinfo [i];
4370 if (ins->opcode == OP_REGVAR) {
4371 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4372 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4373 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4376 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4377 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4378 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4379 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4380 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4381 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4386 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4389 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4391 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4392 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4394 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4396 if (enable_arguments && stack_area) {
4397 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4399 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4401 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4406 ia64_codegen_close (code);
4412 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4414 Ia64CodegenState code;
4415 CallInfo *cinfo = NULL;
4416 MonoMethod *method = cfg->method;
4417 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4419 ia64_codegen_init (code, p);
4421 cinfo = get_call_info (sig, FALSE);
4423 /* Save return value + pass it to func */
4424 switch (cinfo->ret.storage) {
4428 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4429 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4432 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4433 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4434 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4435 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4437 case ArgValuetypeAddrInIReg:
4438 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4449 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4450 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4451 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4453 /* Restore return value */
4454 switch (cinfo->ret.storage) {
4458 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4461 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4462 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4464 case ArgValuetypeAddrInIReg:
4472 ia64_codegen_close (code);
4478 mono_arch_save_unwind_info (MonoCompile *cfg)
4482 /* FIXME: Unregister this for dynamic methods */
4484 di = g_malloc0 (sizeof (unw_dyn_info_t));
4485 di->start_ip = (unw_word_t) cfg->native_code;
4486 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4488 di->format = UNW_INFO_FORMAT_DYNAMIC;
4489 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4490 di->u.pi.regions = cfg->arch.r_pro;
4492 _U_dyn_register (di);
4496 unw_dyn_region_info_t *region = di->u.pi.regions;
4498 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4500 printf (" [Region: %d]\n", region->insn_count);
4501 region = region->next;
4508 mono_arch_flush_icache (guint8 *code, gint size)
4510 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4511 guint8* end = (guint8*)((guint64)code + size);
4513 #ifdef __INTEL_COMPILER
4514 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4521 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4522 /* FIXME: This could be increased to 128 on some cpus */
4529 mono_arch_flush_register_windows (void)
4531 /* Not needed because of libunwind */
4535 mono_arch_is_inst_imm (gint64 imm)
4537 /* The lowering pass will take care of it */
4543 * Determine whenever the trap whose info is in SIGINFO is caused by
4547 mono_arch_is_int_overflow (void *sigctx, void *info)
4549 /* Division is emulated with explicit overflow checks */
4554 mono_arch_get_patch_offset (guint8 *code)
4562 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4564 guint8 *bundle2 = code - 48;
4565 guint8 *bundle3 = code - 32;
4566 guint8 *bundle4 = code - 16;
4567 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4568 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4569 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4570 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4571 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4572 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4573 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4574 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4575 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4579 * Virtual calls are made with:
4581 * [MII] ld8 r31=[r8]
4585 * mov.sptk b6=r31,0x2000000000f32a80
4592 * br.call.sptk.few b0=b6;;
4595 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4596 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4597 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4598 (ins31 == IA64_NOP_M) &&
4599 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4600 (ins33 == IA64_NOP_I) &&
4601 (ins41 == IA64_NOP_M) &&
4602 (ins42 == IA64_NOP_I) &&
4603 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4604 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4605 g_assert (ins21 == IA64_NOP_M);
4606 g_assert (ins23 == IA64_NOP_I);
4607 g_assert (ia64_ins_opcode (ins22) == 0);
4608 g_assert (ia64_ins_x3 (ins22) == 7);
4609 g_assert (ia64_ins_x (ins22) == 0);
4610 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4615 * Must be a scratch register, since only those are saved by the trampoline
4617 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4619 g_assert (regs [reg]);
4628 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4635 static gboolean tls_offset_inited = FALSE;
4638 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4640 if (!tls_offset_inited) {
4641 tls_offset_inited = TRUE;
4643 appdomain_tls_offset = mono_domain_get_tls_offset ();
4644 thread_tls_offset = mono_thread_get_tls_offset ();
4649 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4654 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4656 MonoCallInst *call = (MonoCallInst*)inst;
4657 int out_reg = cfg->arch.reg_out0;
4660 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4663 if (cinfo->ret.storage == ArgAggregate) {
4664 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4667 * The valuetype is in registers after the call, need to be copied
4668 * to the stack. Save the address to a local here, so the call
4669 * instruction can access it.
4671 g_assert (local->opcode == OP_REGOFFSET);
4672 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4675 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4676 vtarg->sreg1 = vt_reg;
4677 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4678 mono_bblock_add_inst (cfg->cbb, vtarg);
4680 mono_call_inst_add_outarg_reg (call, vtarg->dreg, out_reg, FALSE);
4688 /* add the this argument */
4689 if (this_reg != -1) {
4691 MONO_INST_NEW (cfg, this, OP_MOVE);
4692 this->type = this_type;
4693 this->sreg1 = this_reg;
4694 this->dreg = mono_regstate_next_int (cfg->rs);
4695 mono_bblock_add_inst (cfg->cbb, this);
4697 mono_call_inst_add_outarg_reg (call, this->dreg, out_reg, FALSE);
4702 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4704 MonoInst *ins = NULL;
4706 if (cmethod->klass == mono_defaults.thread_class &&
4707 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4708 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4709 } else if(cmethod->klass->image == mono_defaults.corlib &&
4710 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4711 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4713 if (strcmp (cmethod->name, "Increment") == 0) {
4714 MonoInst *ins_iconst;
4717 if (fsig->params [0]->type == MONO_TYPE_I4)
4718 opcode = OP_ATOMIC_ADD_NEW_I4;
4719 else if (fsig->params [0]->type == MONO_TYPE_I8)
4720 opcode = OP_ATOMIC_ADD_NEW_I8;
4722 g_assert_not_reached ();
4723 MONO_INST_NEW (cfg, ins, opcode);
4724 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4725 ins_iconst->inst_imm = 1;
4727 ins->inst_i0 = args [0];
4728 ins->inst_i1 = ins_iconst;
4729 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4730 MonoInst *ins_iconst;
4733 if (fsig->params [0]->type == MONO_TYPE_I4)
4734 opcode = OP_ATOMIC_ADD_NEW_I4;
4735 else if (fsig->params [0]->type == MONO_TYPE_I8)
4736 opcode = OP_ATOMIC_ADD_NEW_I8;
4738 g_assert_not_reached ();
4739 MONO_INST_NEW (cfg, ins, opcode);
4740 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4741 ins_iconst->inst_imm = -1;
4743 ins->inst_i0 = args [0];
4744 ins->inst_i1 = ins_iconst;
4746 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4749 if (fsig->params [0]->type == MONO_TYPE_I4)
4750 opcode = OP_ATOMIC_EXCHANGE_I4;
4751 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4752 (fsig->params [0]->type == MONO_TYPE_I) ||
4753 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4754 opcode = OP_ATOMIC_EXCHANGE_I8;
4758 MONO_INST_NEW (cfg, ins, opcode);
4760 ins->inst_i0 = args [0];
4761 ins->inst_i1 = args [1];
4762 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4763 /* 64 bit reads are already atomic */
4764 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4765 ins->inst_i0 = args [0];
4773 mono_arch_print_tree (MonoInst *tree, int arity)
4778 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4782 if (appdomain_tls_offset == -1)
4785 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4786 ins->inst_offset = appdomain_tls_offset;
4790 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4794 if (thread_tls_offset == -1)
4797 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4798 ins->inst_offset = thread_tls_offset;