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 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
35 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
38 * IA64 register usage:
39 * - local registers are used for global register allocation
40 * - r8..r11, r14..r30 is used for local register allocation
41 * - r31 is a scratch register used within opcode implementations
42 * - FIXME: Use out registers as well
43 * - the first three locals are used for saving ar.pfst, b0, and sp
44 * - compare instructions allways set p6 and p7
48 * There are a lot of places where generated code is disassembled/patched.
49 * The automatic bundling of instructions done by the code generation macros
50 * could complicate things, so it is best to call
51 * ia64_codegen_set_one_ins_per_bundle () at those places.
54 #define ARGS_OFFSET 16
56 #define GP_SCRATCH_REG 31
57 #define GP_SCRATCH_REG2 30
58 #define FP_SCRATCH_REG 32
59 #define FP_SCRATCH_REG2 33
61 #define LOOP_ALIGNMENT 8
62 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
64 #define NOT_IMPLEMENTED g_assert_not_reached ()
66 static const char* gregs [] = {
67 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
68 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
69 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
70 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
71 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
72 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
73 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
74 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
75 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
76 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
77 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
78 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
79 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
83 mono_arch_regname (int reg)
91 static const char* fregs [] = {
92 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
93 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
94 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
95 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
96 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
97 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
98 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
99 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
100 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
101 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
102 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
103 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
104 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
108 mono_arch_fregname (int reg)
116 G_GNUC_UNUSED static void
121 G_GNUC_UNUSED static gboolean
124 static int count = 0;
127 if (count == atoi (getenv ("COUNT"))) {
131 if (count > atoi (getenv ("COUNT"))) {
139 debug_ins_sched (void)
142 return debug_count ();
152 return debug_count ();
159 ia64_patch (unsigned char* code, gpointer target);
165 ArgValuetypeAddrInIReg,
183 /* Only if storage == ArgAggregate */
193 gboolean need_stack_align;
199 #define DEBUG(a) if (cfg->verbose_level > 1) a
201 #define NEW_ICONST(cfg,dest,val) do { \
202 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
203 (dest)->opcode = OP_ICONST; \
204 (dest)->inst_c0 = (val); \
205 (dest)->type = STACK_I4; \
211 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
213 ainfo->offset = *stack_size;
215 if (*gr >= PARAM_REGS) {
216 ainfo->storage = ArgOnStack;
217 (*stack_size) += sizeof (gpointer);
220 ainfo->storage = ArgInIReg;
226 #define FLOAT_PARAM_REGS 8
229 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
231 ainfo->offset = *stack_size;
233 if (*gr >= PARAM_REGS) {
234 ainfo->storage = ArgOnStack;
235 (*stack_size) += sizeof (gpointer);
238 ainfo->storage = ArgInFloatReg;
239 ainfo->reg = 8 + *fr;
246 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
248 guint32 *gr, guint32 *fr, guint32 *stack_size)
252 MonoMarshalType *info;
253 gboolean is_hfa = TRUE;
254 guint32 hfa_type = 0;
256 klass = mono_class_from_mono_type (type);
257 if (type->type == MONO_TYPE_TYPEDBYREF)
258 size = 3 * sizeof (gpointer);
259 else if (sig->pinvoke)
260 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
262 size = mono_type_stack_size (&klass->byval_arg, NULL);
264 if (!sig->pinvoke || (size == 0)) {
265 /* Allways pass in memory */
266 ainfo->offset = *stack_size;
267 *stack_size += ALIGN_TO (size, 8);
268 ainfo->storage = ArgOnStack;
273 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
274 info = mono_marshal_load_type_info (klass);
276 for (i = 0; i < info->num_fields; ++i) {
277 guint32 ftype = info->fields [i].field->type->type;
278 if (!(info->fields [i].field->type->byref) &&
279 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
282 else if (hfa_type != ftype)
291 ainfo->storage = ArgAggregate;
292 ainfo->atype = AggregateNormal;
295 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
297 if (info->num_fields <= 8) {
299 ainfo->nregs = info->num_fields;
300 ainfo->nslots = ainfo->nregs;
306 if ((*fr) + info->num_fields > 8)
309 ainfo->reg = 8 + (*fr);
310 ainfo->nregs = info->num_fields;
311 ainfo->nslots = ainfo->nregs;
312 (*fr) += info->num_fields;
317 /* This also handles returning of TypedByRef used by some icalls */
320 ainfo->reg = IA64_R8;
321 ainfo->nregs = (size + 7) / 8;
322 ainfo->nslots = ainfo->nregs;
329 ainfo->offset = *stack_size;
330 ainfo->nslots = (size + 7) / 8;
332 if (((*gr) + ainfo->nslots) <= 8) {
333 /* Fits entirely in registers */
334 ainfo->nregs = ainfo->nslots;
335 (*gr) += ainfo->nregs;
339 ainfo->nregs = 8 - (*gr);
341 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
347 * Obtain information about a call according to the calling convention.
348 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
349 * Gude" document for more information.
352 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
356 int n = sig->hasthis + sig->param_count;
357 guint32 stack_size = 0;
360 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
367 ret_type = mono_type_get_underlying_type (sig->ret);
368 switch (ret_type->type) {
369 case MONO_TYPE_BOOLEAN:
380 case MONO_TYPE_FNPTR:
381 case MONO_TYPE_CLASS:
382 case MONO_TYPE_OBJECT:
383 case MONO_TYPE_SZARRAY:
384 case MONO_TYPE_ARRAY:
385 case MONO_TYPE_STRING:
386 cinfo->ret.storage = ArgInIReg;
387 cinfo->ret.reg = IA64_R8;
391 cinfo->ret.storage = ArgInIReg;
392 cinfo->ret.reg = IA64_R8;
396 cinfo->ret.storage = ArgInFloatReg;
399 case MONO_TYPE_GENERICINST:
400 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
401 cinfo->ret.storage = ArgInIReg;
402 cinfo->ret.reg = IA64_R8;
406 case MONO_TYPE_VALUETYPE:
407 case MONO_TYPE_TYPEDBYREF: {
408 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
410 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
411 if (cinfo->ret.storage == ArgOnStack)
412 /* The caller passes the address where the value is stored */
413 add_general (&gr, &stack_size, &cinfo->ret);
414 if (cinfo->ret.storage == ArgInIReg)
415 cinfo->ret.storage = ArgValuetypeAddrInIReg;
419 cinfo->ret.storage = ArgNone;
422 g_error ("Can't handle as return value 0x%x", sig->ret->type);
428 add_general (&gr, &stack_size, cinfo->args + 0);
430 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
432 fr = FLOAT_PARAM_REGS;
434 /* Emit the signature cookie just before the implicit arguments */
435 add_general (&gr, &stack_size, &cinfo->sig_cookie);
438 for (i = 0; i < sig->param_count; ++i) {
439 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
442 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
443 /* We allways pass the sig cookie on the stack for simplicity */
445 * Prevent implicit arguments + the sig cookie from being passed
449 fr = FLOAT_PARAM_REGS;
451 /* Emit the signature cookie just before the implicit arguments */
452 add_general (&gr, &stack_size, &cinfo->sig_cookie);
455 if (sig->params [i]->byref) {
456 add_general (&gr, &stack_size, ainfo);
459 ptype = mono_type_get_underlying_type (sig->params [i]);
460 switch (ptype->type) {
461 case MONO_TYPE_BOOLEAN:
464 add_general (&gr, &stack_size, ainfo);
469 add_general (&gr, &stack_size, ainfo);
473 add_general (&gr, &stack_size, ainfo);
478 case MONO_TYPE_FNPTR:
479 case MONO_TYPE_CLASS:
480 case MONO_TYPE_OBJECT:
481 case MONO_TYPE_STRING:
482 case MONO_TYPE_SZARRAY:
483 case MONO_TYPE_ARRAY:
484 add_general (&gr, &stack_size, ainfo);
486 case MONO_TYPE_GENERICINST:
487 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
488 add_general (&gr, &stack_size, ainfo);
492 case MONO_TYPE_VALUETYPE:
493 case MONO_TYPE_TYPEDBYREF:
495 /* We allways pass valuetypes on the stack */
496 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
500 add_general (&gr, &stack_size, ainfo);
503 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
506 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
509 g_assert_not_reached ();
513 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
515 fr = FLOAT_PARAM_REGS;
517 /* Emit the signature cookie just before the implicit arguments */
518 add_general (&gr, &stack_size, &cinfo->sig_cookie);
521 cinfo->stack_usage = stack_size;
522 cinfo->reg_usage = gr;
523 cinfo->freg_usage = fr;
528 * mono_arch_get_argument_info:
529 * @csig: a method signature
530 * @param_count: the number of parameters to consider
531 * @arg_info: an array to store the result infos
533 * Gathers information on parameters such as size, alignment and
534 * padding. arg_info should be large enought to hold param_count + 1 entries.
536 * Returns the size of the argument area on the stack.
539 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
542 CallInfo *cinfo = get_call_info (csig, FALSE);
543 guint32 args_size = cinfo->stack_usage;
545 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
547 arg_info [0].offset = 0;
550 for (k = 0; k < param_count; k++) {
551 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
553 arg_info [k + 1].size = 0;
562 * Initialize the cpu to execute managed code.
565 mono_arch_cpu_init (void)
570 * This function returns the optimizations supported on this cpu.
573 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
581 mono_arch_break (void)
586 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
590 MonoMethodSignature *sig;
591 MonoMethodHeader *header;
594 header = mono_method_get_header (cfg->method);
596 sig = mono_method_signature (cfg->method);
598 cinfo = get_call_info (sig, FALSE);
600 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
601 MonoInst *ins = cfg->args [i];
603 ArgInfo *ainfo = &cinfo->args [i];
605 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
608 if (ainfo->storage == ArgInIReg) {
609 /* The input registers are non-volatile */
610 ins->opcode = OP_REGVAR;
611 ins->dreg = 32 + ainfo->reg;
615 for (i = 0; i < cfg->num_varinfo; i++) {
616 MonoInst *ins = cfg->varinfo [i];
617 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
620 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
623 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
624 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
627 if (mono_is_regsize_var (ins->inst_vtype)) {
628 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
629 g_assert (i == vmv->idx);
630 vars = g_list_prepend (vars, vmv);
634 vars = mono_varlist_sort (cfg, vars, 0);
640 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
643 guint32 reserved_regs;
644 MonoMethodHeader *header;
646 if (cfg->arch.reg_local0 > 0)
650 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
652 header = mono_method_get_header (cfg->method);
654 /* Some registers are reserved for use by the prolog/epilog */
655 reserved_regs = header->num_clauses ? 4 : 3;
657 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
658 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
659 /* One registers is needed by instrument_epilog to save the return value */
661 if (cinfo->reg_usage < 2)
662 /* Number of arguments passed to function call in instrument_prolog */
663 cinfo->reg_usage = 2;
666 cfg->arch.reg_in0 = 32;
667 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
668 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
670 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
671 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
672 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
675 * Frames without handlers save sp to fp, frames with handlers save it into
676 * a dedicated register.
678 if (header->num_clauses)
679 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
681 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
683 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
684 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
685 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
689 * Need to allocate at least 2 out register for use by OP_THROW / the system
690 * exception throwing code.
692 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
698 mono_arch_get_global_int_regs (MonoCompile *cfg)
703 mono_ia64_alloc_stacked_registers (cfg);
705 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
708 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
715 * mono_arch_regalloc_cost:
717 * Return the cost, in number of memory references, of the action of
718 * allocating the variable VMV into a register during global register
722 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
724 /* FIXME: Increase costs linearly to avoid using all local registers */
730 mono_arch_allocate_vars (MonoCompile *cfg)
732 MonoMethodSignature *sig;
733 MonoMethodHeader *header;
736 guint32 locals_stack_size, locals_stack_align;
740 header = mono_method_get_header (cfg->method);
742 sig = mono_method_signature (cfg->method);
744 cinfo = get_call_info (sig, FALSE);
747 * Determine whenever the frame pointer can be eliminated.
748 * FIXME: Remove some of the restrictions.
750 cfg->arch.omit_fp = TRUE;
752 if (!debug_omit_fp ())
753 cfg->arch.omit_fp = FALSE;
755 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
756 cfg->arch.omit_fp = FALSE;
757 if (header->num_clauses)
758 cfg->arch.omit_fp = FALSE;
760 cfg->arch.omit_fp = FALSE;
761 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
762 ArgInfo *ainfo = &cinfo->args [i];
764 if (ainfo->storage == ArgOnStack) {
766 * The stack offset can only be determined when the frame
769 cfg->arch.omit_fp = FALSE;
773 mono_ia64_alloc_stacked_registers (cfg);
776 * We use the ABI calling conventions for managed code as well.
777 * Exception: valuetypes are never passed or returned in registers.
780 if (cfg->arch.omit_fp) {
781 cfg->frame_reg = IA64_SP;
782 offset = ARGS_OFFSET;
785 /* Locals are allocated backwards from %fp */
786 cfg->frame_reg = cfg->arch.reg_fp;
790 if (cfg->method->save_lmf) {
794 if (sig->ret->type != MONO_TYPE_VOID) {
795 switch (cinfo->ret.storage) {
797 cfg->ret->opcode = OP_REGVAR;
798 cfg->ret->inst_c0 = cinfo->ret.reg;
801 cfg->ret->opcode = OP_REGVAR;
802 cfg->ret->inst_c0 = cinfo->ret.reg;
804 case ArgValuetypeAddrInIReg:
805 cfg->ret->opcode = OP_REGVAR;
806 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
809 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
810 if (cfg->arch.omit_fp)
811 g_assert_not_reached ();
812 offset = ALIGN_TO (offset, 8);
813 offset += cinfo->ret.nslots * 8;
814 cfg->ret->opcode = OP_REGOFFSET;
815 cfg->ret->inst_basereg = cfg->frame_reg;
816 cfg->ret->inst_offset = - offset;
819 g_assert_not_reached ();
821 cfg->ret->dreg = cfg->ret->inst_c0;
824 /* Allocate locals */
825 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
826 if (locals_stack_align) {
827 offset = ALIGN_TO (offset, locals_stack_align);
829 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
830 if (offsets [i] != -1) {
831 MonoInst *inst = cfg->varinfo [i];
832 inst->opcode = OP_REGOFFSET;
833 inst->inst_basereg = cfg->frame_reg;
834 if (cfg->arch.omit_fp)
835 inst->inst_offset = (offset + offsets [i]);
837 inst->inst_offset = - (offset + offsets [i]);
838 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
841 offset += locals_stack_size;
843 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
844 if (cfg->arch.omit_fp)
845 g_assert_not_reached ();
846 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
847 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
850 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
851 inst = cfg->args [i];
852 if (inst->opcode != OP_REGVAR) {
853 ArgInfo *ainfo = &cinfo->args [i];
854 gboolean inreg = TRUE;
857 if (sig->hasthis && (i == 0))
858 arg_type = &mono_defaults.object_class->byval_arg;
860 arg_type = sig->params [i - sig->hasthis];
862 /* FIXME: VOLATILE is only set if the liveness pass runs */
863 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
866 inst->opcode = OP_REGOFFSET;
868 switch (ainfo->storage) {
870 inst->opcode = OP_REGVAR;
871 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
875 * Since float regs are volatile, we save the arguments to
876 * the stack in the prolog.
881 if (cfg->arch.omit_fp)
882 g_assert_not_reached ();
883 inst->opcode = OP_REGOFFSET;
884 inst->inst_basereg = cfg->frame_reg;
885 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
894 if (!inreg && (ainfo->storage != ArgOnStack)) {
895 inst->opcode = OP_REGOFFSET;
896 inst->inst_basereg = cfg->frame_reg;
897 /* These arguments are saved to the stack in the prolog */
898 switch (ainfo->storage) {
900 if (ainfo->atype == AggregateSingleHFA)
901 offset += ainfo->nslots * 4;
903 offset += ainfo->nslots * 8;
906 offset += sizeof (gpointer);
909 offset = ALIGN_TO (offset, sizeof (gpointer));
910 if (cfg->arch.omit_fp)
911 inst->inst_offset = offset;
913 inst->inst_offset = - offset;
918 if (cfg->arch.omit_fp && offset == 16)
921 cfg->stack_offset = offset;
927 mono_arch_create_vars (MonoCompile *cfg)
929 MonoMethodSignature *sig;
932 sig = mono_method_signature (cfg->method);
934 cinfo = get_call_info (sig, FALSE);
936 if (cinfo->ret.storage == ArgAggregate)
937 cfg->ret_var_is_local = TRUE;
943 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
947 arg->opcode = OP_OUTARG_REG;
948 arg->inst_left = tree;
949 arg->inst_right = (MonoInst*)call;
950 arg->backend.reg3 = reg;
951 call->used_iregs |= 1 << reg;
954 arg->opcode = OP_OUTARG_FREG;
955 arg->inst_left = tree;
956 arg->inst_right = (MonoInst*)call;
957 arg->backend.reg3 = reg;
958 call->used_fregs |= 1 << reg;
961 g_assert_not_reached ();
966 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
969 MonoMethodSignature *tmp_sig;
972 /* FIXME: Add support for signature tokens to AOT */
973 cfg->disable_aot = TRUE;
975 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
978 * mono_ArgIterator_Setup assumes the signature cookie is
979 * passed first and all the arguments which were before it are
980 * passed on the stack after the signature. So compensate by
981 * passing a different signature.
983 tmp_sig = mono_metadata_signature_dup (call->signature);
984 tmp_sig->param_count -= call->signature->sentinelpos;
985 tmp_sig->sentinelpos = 0;
986 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
988 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
989 sig_arg->inst_p0 = tmp_sig;
991 MONO_INST_NEW (cfg, arg, OP_OUTARG);
992 arg->inst_left = sig_arg;
993 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
994 arg->type = STACK_PTR;
996 /* prepend, so they get reversed */
997 arg->next = call->out_args;
998 call->out_args = arg;
1002 * take the arguments and generate the arch-specific
1003 * instructions to properly call the function in call.
1004 * This includes pushing, moving arguments to the right register
1008 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1011 MonoMethodSignature *sig;
1012 int i, n, stack_size;
1018 mono_ia64_alloc_stacked_registers (cfg);
1020 sig = call->signature;
1021 n = sig->param_count + sig->hasthis;
1023 cinfo = get_call_info (sig, sig->pinvoke);
1025 if (cinfo->ret.storage == ArgAggregate) {
1026 /* The code in emit_this_vret_arg needs a local */
1027 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1028 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1031 for (i = 0; i < n; ++i) {
1032 ainfo = cinfo->args + i;
1034 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1035 /* Emit the signature cookie just before the implicit arguments */
1036 emit_sig_cookie (cfg, call, cinfo);
1039 if (is_virtual && i == 0) {
1040 /* the argument will be attached to the call instruction */
1041 in = call->args [i];
1045 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1046 in = call->args [i];
1047 arg->cil_code = in->cil_code;
1048 arg->inst_left = in;
1049 arg->type = in->type;
1050 /* prepend, so they get reversed */
1051 arg->next = call->out_args;
1052 call->out_args = arg;
1054 if (sig->hasthis && (i == 0))
1055 arg_type = &mono_defaults.object_class->byval_arg;
1057 arg_type = sig->params [i - sig->hasthis];
1059 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1060 MonoInst *stack_addr;
1064 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1065 size = sizeof (MonoTypedRef);
1066 align = sizeof (gpointer);
1070 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1073 * Other backends use mono_type_stack_size (), but that
1074 * aligns the size to 8, which is larger than the size of
1075 * the source, leading to reads of invalid memory if the
1076 * source is at the end of address space.
1078 size = mono_class_value_size (in->klass, &align);
1081 if (ainfo->storage == ArgAggregate) {
1082 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1085 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1088 * Part of the structure is passed in registers.
1090 for (j = 0; j < ainfo->nregs; ++j) {
1091 int offset, load_op, dest_reg, arg_storage;
1093 slot = ainfo->reg + j;
1095 if (ainfo->atype == AggregateSingleHFA) {
1096 load_op = CEE_LDIND_R4;
1098 dest_reg = ainfo->reg + j;
1099 arg_storage = ArgInFloatReg;
1100 } else if (ainfo->atype == AggregateDoubleHFA) {
1101 load_op = CEE_LDIND_R8;
1103 dest_reg = ainfo->reg + j;
1104 arg_storage = ArgInFloatReg;
1106 load_op = CEE_LDIND_I;
1108 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1109 arg_storage = ArgInIReg;
1112 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1113 load->ssa_op = MONO_SSA_LOAD;
1114 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1116 NEW_ICONST (cfg, offset_ins, offset);
1117 MONO_INST_NEW (cfg, load2, CEE_ADD);
1118 load2->inst_left = load;
1119 load2->inst_right = offset_ins;
1121 MONO_INST_NEW (cfg, load, load_op);
1122 load->inst_left = load2;
1127 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1128 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1129 if (set_reg != call->out_args) {
1130 set_reg->next = call->out_args;
1131 call->out_args = set_reg;
1136 * Part of the structure is passed on the stack.
1138 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1141 slot = ainfo->reg + j;
1143 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1144 load->ssa_op = MONO_SSA_LOAD;
1145 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1147 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1148 MONO_INST_NEW (cfg, load2, CEE_ADD);
1149 load2->inst_left = load;
1150 load2->inst_right = offset_ins;
1152 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1153 load->inst_left = load2;
1158 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1159 outarg->inst_left = load;
1160 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1162 if (outarg != call->out_args) {
1163 outarg->next = call->out_args;
1164 call->out_args = outarg;
1168 /* Trees can't be shared so make a copy */
1169 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1170 arg->cil_code = in->cil_code;
1171 arg->ssa_op = MONO_SSA_STORE;
1172 arg->inst_left = vtaddr;
1173 arg->inst_right = in;
1174 arg->type = in->type;
1176 /* prepend, so they get reversed */
1177 arg->next = call->out_args;
1178 call->out_args = arg;
1181 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1182 stack_addr->inst_basereg = IA64_SP;
1183 stack_addr->inst_offset = 16 + ainfo->offset;
1184 stack_addr->inst_imm = size;
1186 arg->opcode = OP_OUTARG_VT;
1187 arg->inst_right = stack_addr;
1191 switch (ainfo->storage) {
1193 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1196 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1199 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1200 arg->opcode = OP_OUTARG_R4;
1203 arg->opcode = OP_OUTARG;
1204 arg->inst_imm = 16 + ainfo->offset;
1207 g_assert_not_reached ();
1213 /* Handle the case where there are no implicit arguments */
1214 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1215 emit_sig_cookie (cfg, call, cinfo);
1218 call->stack_usage = cinfo->stack_usage;
1219 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1220 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1221 cfg->flags |= MONO_CFG_HAS_CALLS;
1229 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1231 MonoInst *ins, *last_ins = NULL;
1235 switch (ins->opcode) {
1243 if (ins->dreg == ins->sreg1) {
1245 last_ins->next = ins->next;
1252 * OP_MOVE sreg, dreg
1253 * OP_MOVE dreg, sreg
1255 if (last_ins && last_ins->opcode == OP_MOVE &&
1256 ins->sreg1 == last_ins->dreg &&
1257 ins->dreg == last_ins->sreg1) {
1258 last_ins->next = ins->next;
1265 /* remove unnecessary multiplication with 1 */
1266 if (ins->inst_imm == 1) {
1267 if (ins->dreg != ins->sreg1) {
1268 ins->opcode = OP_MOVE;
1270 last_ins->next = ins->next;
1281 bb->last_ins = last_ins;
1284 int cond_to_ia64_cmp [][3] = {
1285 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1286 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1287 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1288 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1289 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1290 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1291 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1292 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1293 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1294 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1298 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1300 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1303 int cond_to_ia64_cmp_imm [][3] = {
1304 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1305 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1306 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1307 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1308 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1309 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1310 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1311 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1312 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1313 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1317 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1319 /* The condition needs to be reversed */
1320 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1324 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1328 bb->code = to_insert;
1329 to_insert->next = ins;
1332 to_insert->next = ins->next;
1333 ins->next = to_insert;
1337 #define NEW_INS(cfg,dest,op) do { \
1338 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1339 (dest)->opcode = (op); \
1340 insert_after_ins (bb, last_ins, (dest)); \
1341 last_ins = (dest); \
1345 * mono_arch_lowering_pass:
1347 * Converts complex opcodes into simpler ones so that each IR instruction
1348 * corresponds to one machine instruction.
1351 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1353 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1356 if (bb->max_vreg > cfg->rs->next_vreg)
1357 cfg->rs->next_vreg = bb->max_vreg;
1360 switch (ins->opcode) {
1361 case OP_STOREI1_MEMBASE_IMM:
1362 case OP_STOREI2_MEMBASE_IMM:
1363 case OP_STOREI4_MEMBASE_IMM:
1364 case OP_STOREI8_MEMBASE_IMM:
1365 case OP_STORE_MEMBASE_IMM:
1366 /* There are no store_membase instructions on ia64 */
1367 if (ins->inst_offset == 0) {
1369 } else if (ia64_is_imm14 (ins->inst_offset)) {
1370 NEW_INS (cfg, temp2, OP_ADD_IMM);
1371 temp2->sreg1 = ins->inst_destbasereg;
1372 temp2->inst_imm = ins->inst_offset;
1373 temp2->dreg = mono_regstate_next_int (cfg->rs);
1376 NEW_INS (cfg, temp, OP_I8CONST);
1377 temp->inst_c0 = ins->inst_offset;
1378 temp->dreg = mono_regstate_next_int (cfg->rs);
1379 NEW_INS (cfg, temp2, CEE_ADD);
1380 temp2->sreg1 = ins->inst_destbasereg;
1381 temp2->sreg2 = temp->dreg;
1382 temp2->dreg = mono_regstate_next_int (cfg->rs);
1385 switch (ins->opcode) {
1386 case OP_STOREI1_MEMBASE_IMM:
1387 ins->opcode = OP_STOREI1_MEMBASE_REG;
1389 case OP_STOREI2_MEMBASE_IMM:
1390 ins->opcode = OP_STOREI2_MEMBASE_REG;
1392 case OP_STOREI4_MEMBASE_IMM:
1393 ins->opcode = OP_STOREI4_MEMBASE_REG;
1395 case OP_STOREI8_MEMBASE_IMM:
1396 case OP_STORE_MEMBASE_IMM:
1397 ins->opcode = OP_STOREI8_MEMBASE_REG;
1400 g_assert_not_reached ();
1403 if (ins->inst_imm == 0)
1404 ins->sreg1 = IA64_R0;
1406 NEW_INS (cfg, temp3, OP_I8CONST);
1407 temp3->inst_c0 = ins->inst_imm;
1408 temp3->dreg = mono_regstate_next_int (cfg->rs);
1409 ins->sreg1 = temp3->dreg;
1412 ins->inst_offset = 0;
1414 ins->inst_destbasereg = temp2->dreg;
1416 case OP_STOREI1_MEMBASE_REG:
1417 case OP_STOREI2_MEMBASE_REG:
1418 case OP_STOREI4_MEMBASE_REG:
1419 case OP_STOREI8_MEMBASE_REG:
1420 case OP_STORER4_MEMBASE_REG:
1421 case OP_STORER8_MEMBASE_REG:
1422 case OP_STORE_MEMBASE_REG:
1423 /* There are no store_membase instructions on ia64 */
1424 if (ins->inst_offset == 0) {
1427 else if (ia64_is_imm14 (ins->inst_offset)) {
1428 NEW_INS (cfg, temp2, OP_ADD_IMM);
1429 temp2->sreg1 = ins->inst_destbasereg;
1430 temp2->inst_imm = ins->inst_offset;
1431 temp2->dreg = mono_regstate_next_int (cfg->rs);
1434 NEW_INS (cfg, temp, OP_I8CONST);
1435 temp->inst_c0 = ins->inst_offset;
1436 temp->dreg = mono_regstate_next_int (cfg->rs);
1437 NEW_INS (cfg, temp2, CEE_ADD);
1438 temp2->sreg1 = ins->inst_destbasereg;
1439 temp2->sreg2 = temp->dreg;
1440 temp2->dreg = mono_regstate_next_int (cfg->rs);
1443 ins->inst_offset = 0;
1444 ins->inst_destbasereg = temp2->dreg;
1446 case OP_LOADI1_MEMBASE:
1447 case OP_LOADU1_MEMBASE:
1448 case OP_LOADI2_MEMBASE:
1449 case OP_LOADU2_MEMBASE:
1450 case OP_LOADI4_MEMBASE:
1451 case OP_LOADU4_MEMBASE:
1452 case OP_LOADI8_MEMBASE:
1453 case OP_LOAD_MEMBASE:
1454 case OP_LOADR4_MEMBASE:
1455 case OP_LOADR8_MEMBASE:
1456 case OP_ATOMIC_EXCHANGE_I4:
1457 case OP_ATOMIC_EXCHANGE_I8:
1458 case OP_ATOMIC_ADD_NEW_I4:
1459 case OP_ATOMIC_ADD_NEW_I8:
1460 case OP_ATOMIC_ADD_IMM_NEW_I4:
1461 case OP_ATOMIC_ADD_IMM_NEW_I8:
1462 /* There are no membase instructions on ia64 */
1463 if (ins->inst_offset == 0) {
1466 else if (ia64_is_imm14 (ins->inst_offset)) {
1467 NEW_INS (cfg, temp2, OP_ADD_IMM);
1468 temp2->sreg1 = ins->inst_basereg;
1469 temp2->inst_imm = ins->inst_offset;
1470 temp2->dreg = mono_regstate_next_int (cfg->rs);
1473 NEW_INS (cfg, temp, OP_I8CONST);
1474 temp->inst_c0 = ins->inst_offset;
1475 temp->dreg = mono_regstate_next_int (cfg->rs);
1476 NEW_INS (cfg, temp2, CEE_ADD);
1477 temp2->sreg1 = ins->inst_basereg;
1478 temp2->sreg2 = temp->dreg;
1479 temp2->dreg = mono_regstate_next_int (cfg->rs);
1482 ins->inst_offset = 0;
1483 ins->inst_basereg = temp2->dreg;
1497 case OP_ISHR_UN_IMM:
1498 case OP_LSHR_UN_IMM: {
1499 gboolean is_imm = FALSE;
1500 gboolean switched = FALSE;
1502 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1503 ins->opcode = OP_ZEXT_I1;
1507 switch (ins->opcode) {
1510 is_imm = ia64_is_imm14 (ins->inst_imm);
1514 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1516 /* A = B - IMM -> A = B + (-IMM) */
1517 ins->inst_imm = - ins->inst_imm;
1518 ins->opcode = OP_IADD_IMM;
1526 is_imm = ia64_is_imm8 (ins->inst_imm);
1534 case OP_ISHR_UN_IMM:
1535 case OP_LSHR_UN_IMM:
1536 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1544 ins->sreg2 = ins->sreg1;
1548 switch (ins->opcode) {
1550 ins->opcode = CEE_ADD;
1553 ins->opcode = OP_IADD;
1556 ins->opcode = OP_ISUB;
1559 ins->opcode = OP_IAND;
1562 ins->opcode = OP_IOR;
1565 ins->opcode = OP_IXOR;
1568 ins->opcode = OP_ISHL;
1571 ins->opcode = OP_ISHR;
1573 case OP_ISHR_UN_IMM:
1574 ins->opcode = OP_ISHR_UN;
1577 ins->opcode = CEE_AND;
1580 ins->opcode = OP_LSHL;
1583 ins->opcode = OP_LSHL;
1586 ins->opcode = OP_LSHR;
1588 case OP_LSHR_UN_IMM:
1589 ins->opcode = OP_LSHR_UN;
1592 g_assert_not_reached ();
1595 if (ins->inst_imm == 0)
1596 ins->sreg2 = IA64_R0;
1598 NEW_INS (cfg, temp, OP_I8CONST);
1599 temp->inst_c0 = ins->inst_imm;
1600 temp->dreg = mono_regstate_next_int (cfg->rs);
1601 ins->sreg2 = temp->dreg;
1605 case OP_COMPARE_IMM:
1606 case OP_ICOMPARE_IMM: {
1607 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1611 * The compare_imm instructions have switched up arguments, and
1612 * some of them take an imm between -127 and 128.
1615 switch (next->opcode) {
1618 case OP_COND_EXC_LT:
1621 imm = ia64_is_imm8 (ins->inst_imm - 1);
1627 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1630 imm = ia64_is_imm8 (ins->inst_imm);
1635 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1636 ins->sreg2 = ins->sreg1;
1639 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1641 if (ins->inst_imm == 0)
1642 ins->sreg2 = IA64_R0;
1644 NEW_INS (cfg, temp, OP_I8CONST);
1645 temp->inst_c0 = ins->inst_imm;
1646 temp->dreg = mono_regstate_next_int (cfg->rs);
1647 ins->sreg2 = temp->dreg;
1651 switch (next->opcode) {
1672 next->opcode = OP_IA64_BR_COND;
1673 if (! (next->flags & MONO_INST_BRLABEL))
1674 next->inst_target_bb = next->inst_true_bb;
1676 case OP_COND_EXC_EQ:
1677 case OP_COND_EXC_GT:
1678 case OP_COND_EXC_LT:
1679 case OP_COND_EXC_GT_UN:
1680 case OP_COND_EXC_LE_UN:
1681 case OP_COND_EXC_NE_UN:
1682 case OP_COND_EXC_LT_UN:
1683 next->opcode = OP_IA64_COND_EXC;
1695 next->opcode = OP_IA64_CSET;
1698 printf ("%s\n", mono_inst_name (next->opcode));
1708 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1712 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1713 switch (next->opcode) {
1744 next->opcode = OP_IA64_BR_COND;
1745 if (! (next->flags & MONO_INST_BRLABEL))
1746 next->inst_target_bb = next->inst_true_bb;
1748 case OP_COND_EXC_LT:
1749 case OP_COND_EXC_GT:
1750 case OP_COND_EXC_GT_UN:
1751 case OP_COND_EXC_LE_UN:
1752 next->opcode = OP_IA64_COND_EXC;
1769 next->opcode = OP_IA64_CSET;
1772 printf ("%s\n", mono_inst_name (next->opcode));
1781 gboolean found = FALSE;
1782 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1784 /* First the easy cases */
1785 if (ins->inst_imm == 1) {
1786 ins->opcode = OP_MOVE;
1789 for (i = 1; i < 64; ++i)
1790 if (ins->inst_imm == (((gint64)1) << i)) {
1791 ins->opcode = shl_op;
1797 /* This could be optimized */
1800 for (i = 0; i < 64; ++i) {
1801 if (ins->inst_imm & (((gint64)1) << i)) {
1802 NEW_INS (cfg, temp, shl_op);
1803 temp->dreg = mono_regstate_next_int (cfg->rs);
1804 temp->sreg1 = ins->sreg1;
1808 sum_reg = temp->dreg;
1810 NEW_INS (cfg, temp2, CEE_ADD);
1811 temp2->dreg = mono_regstate_next_int (cfg->rs);
1812 temp2->sreg1 = sum_reg;
1813 temp2->sreg2 = temp->dreg;
1814 sum_reg = temp2->dreg;
1818 ins->opcode = OP_MOVE;
1819 ins->sreg1 = sum_reg;
1823 case CEE_CONV_OVF_U4:
1824 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1825 temp->sreg1 = ins->sreg1;
1826 temp->sreg2 = IA64_R0;
1828 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1829 temp->inst_p1 = (char*)"OverflowException";
1831 ins->opcode = OP_MOVE;
1833 case CEE_CONV_OVF_I4_UN:
1834 NEW_INS (cfg, temp, OP_ICONST);
1835 temp->inst_c0 = 0x7fffffff;
1836 temp->dreg = mono_regstate_next_int (cfg->rs);
1838 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1839 temp2->sreg1 = ins->sreg1;
1840 temp2->sreg2 = temp->dreg;
1842 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1843 temp->inst_p1 = (char*)"OverflowException";
1845 ins->opcode = OP_MOVE;
1847 case OP_FCONV_TO_I4:
1848 case OP_FCONV_TO_I2:
1849 case OP_FCONV_TO_U2:
1850 case OP_FCONV_TO_I1:
1851 case OP_FCONV_TO_U1:
1852 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1853 temp->sreg1 = ins->sreg1;
1854 temp->dreg = ins->dreg;
1856 switch (ins->opcode) {
1857 case OP_FCONV_TO_I4:
1858 ins->opcode = OP_SEXT_I4;
1860 case OP_FCONV_TO_I2:
1861 ins->opcode = OP_SEXT_I2;
1863 case OP_FCONV_TO_U2:
1864 ins->opcode = OP_ZEXT_I4;
1866 case OP_FCONV_TO_I1:
1867 ins->opcode = OP_SEXT_I1;
1869 case OP_FCONV_TO_U1:
1870 ins->opcode = OP_ZEXT_I1;
1873 g_assert_not_reached ();
1875 ins->sreg1 = ins->dreg;
1883 bb->last_ins = last_ins;
1885 bb->max_vreg = cfg->rs->next_vreg;
1889 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1894 mono_arch_lowering_pass (cfg, bb);
1896 mono_local_regalloc (cfg, bb);
1900 * emit_load_volatile_arguments:
1902 * Load volatile arguments from the stack to the original input registers.
1903 * Required before a tail call.
1905 static Ia64CodegenState
1906 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1908 MonoMethod *method = cfg->method;
1909 MonoMethodSignature *sig;
1914 /* FIXME: Generate intermediate code instead */
1916 sig = mono_method_signature (method);
1918 cinfo = get_call_info (sig, FALSE);
1920 /* This is the opposite of the code in emit_prolog */
1921 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1922 ArgInfo *ainfo = cinfo->args + i;
1923 gint32 stack_offset;
1925 ins = cfg->args [i];
1927 if (sig->hasthis && (i == 0))
1928 arg_type = &mono_defaults.object_class->byval_arg;
1930 arg_type = sig->params [i - sig->hasthis];
1932 arg_type = mono_type_get_underlying_type (arg_type);
1934 stack_offset = ainfo->offset + ARGS_OFFSET;
1936 /* Save volatile arguments to the stack */
1937 if (ins->opcode != OP_REGVAR) {
1938 switch (ainfo->storage) {
1941 /* FIXME: big offsets */
1942 g_assert (ins->opcode == OP_REGOFFSET);
1943 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1944 if (arg_type->byref)
1945 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1947 switch (arg_type->type) {
1949 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1952 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1955 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1967 if (ins->opcode == OP_REGVAR) {
1968 /* Argument allocated to (non-volatile) register */
1969 switch (ainfo->storage) {
1971 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1972 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1975 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1976 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1989 static Ia64CodegenState
1990 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1995 /* Move return value to the target register */
1996 switch (ins->opcode) {
1998 case OP_VOIDCALL_REG:
1999 case OP_VOIDCALL_MEMBASE:
2003 case OP_CALL_MEMBASE:
2006 case OP_LCALL_MEMBASE:
2007 g_assert (ins->dreg == IA64_R8);
2011 case OP_FCALL_MEMBASE:
2012 g_assert (ins->dreg == 8);
2016 case OP_VCALL_MEMBASE: {
2019 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
2020 storage = cinfo->ret.storage;
2022 if (storage == ArgAggregate) {
2023 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2025 /* Load address of stack space allocated for the return value */
2026 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2027 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2028 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2030 for (i = 0; i < cinfo->ret.nregs; ++i) {
2031 switch (cinfo->ret.atype) {
2032 case AggregateNormal:
2033 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2035 case AggregateSingleHFA:
2036 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2038 case AggregateDoubleHFA:
2039 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2042 g_assert_not_reached ();
2050 g_assert_not_reached ();
2056 #define add_patch_info(cfg,code,patch_type,data) do { \
2057 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2060 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2061 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2063 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2065 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2066 ia64_br_cond_pred (code, (predicate), 0); \
2069 static Ia64CodegenState
2070 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2072 add_patch_info (cfg, code, patch_type, data);
2074 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2076 /* mono_arch_patch_callsite will patch this */
2077 /* mono_arch_nullify_class_init_trampoline will patch this */
2078 ia64_movl (code, GP_SCRATCH_REG, 0);
2079 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2080 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2081 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2082 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2085 /* Can't use a direct call since the displacement might be too small */
2086 /* mono_arch_patch_callsite will patch this */
2087 ia64_movl (code, GP_SCRATCH_REG, 0);
2088 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2089 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2095 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2098 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2103 Ia64CodegenState code;
2104 guint8 *code_start = cfg->native_code + cfg->code_len;
2105 MonoInst *last_ins = NULL;
2106 guint last_offset = 0;
2109 if (cfg->opt & MONO_OPT_PEEPHOLE)
2110 peephole_pass (cfg, bb);
2112 if (cfg->opt & MONO_OPT_LOOP) {
2116 if (cfg->verbose_level > 2)
2117 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2119 cpos = bb->max_offset;
2121 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2125 offset = code_start - cfg->native_code;
2127 ia64_codegen_init (code, code_start);
2130 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2136 offset = code.buf - cfg->native_code;
2138 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2140 while (offset + max_len + 16 > cfg->code_size) {
2141 ia64_codegen_close (code);
2143 offset = code.buf - cfg->native_code;
2145 cfg->code_size *= 2;
2146 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2147 code_start = cfg->native_code + offset;
2148 mono_jit_stats.code_reallocs++;
2150 ia64_codegen_init (code, code_start);
2153 mono_debug_record_line_number (cfg, ins, offset);
2155 switch (ins->opcode) {
2158 if (ia64_is_imm14 (ins->inst_c0))
2159 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2161 ia64_movl (code, ins->dreg, ins->inst_c0);
2164 ia64_mov (code, ins->dreg, ins->sreg1);
2167 case OP_IA64_BR_COND: {
2169 if (ins->opcode == OP_IA64_BR_COND)
2171 if (ins->flags & MONO_INST_BRLABEL) {
2172 if (ins->inst_i0->inst_c0) {
2175 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2176 ia64_br_cond_pred (code, pred, 0);
2179 if (ins->inst_target_bb->native_offset) {
2180 guint8 *pos = code.buf + code.nins;
2182 ia64_br_cond_pred (code, pred, 0);
2183 ia64_begin_bundle (code);
2184 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2186 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2187 ia64_br_cond_pred (code, pred, 0);
2193 ia64_begin_bundle (code);
2194 ins->inst_c0 = code.buf - cfg->native_code;
2199 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2200 ia64_br_cond_reg (code, IA64_B6);
2204 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2208 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2212 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2216 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2220 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2224 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2227 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2231 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2234 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2235 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2239 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2242 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2246 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2249 /* p6 and p7 is set if there is signed/unsigned overflow */
2251 /* Set p8-p9 == (sreg2 > 0) */
2252 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2254 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2256 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2257 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2258 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2259 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2261 /* res <u sreg1 => unsigned overflow */
2262 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2264 /* FIXME: Predicate this since this is a side effect */
2265 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2268 /* p6 and p7 is set if there is signed/unsigned overflow */
2270 /* Set p8-p9 == (sreg2 > 0) */
2271 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2273 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2275 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2276 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2277 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2278 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2280 /* sreg1 <u sreg2 => unsigned overflow */
2281 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2283 /* FIXME: Predicate this since this is a side effect */
2284 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2287 /* Same as OP_IADDCC */
2288 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2290 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2292 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2293 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2295 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2297 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2300 /* Same as OP_ISUBCC */
2302 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2304 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2306 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2307 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2309 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2311 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2315 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2319 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2322 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2325 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2330 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2333 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2336 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2338 case OP_ISHR_UN_IMM:
2339 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2340 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2342 case OP_LSHR_UN_IMM:
2343 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2346 /* Based on gcc code */
2347 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2348 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2349 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2350 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2353 case OP_STOREI1_MEMBASE_REG:
2354 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2356 case OP_STOREI2_MEMBASE_REG:
2357 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2359 case OP_STOREI4_MEMBASE_REG:
2360 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2362 case OP_STOREI8_MEMBASE_REG:
2363 case OP_STORE_MEMBASE_REG:
2364 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2367 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2368 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2370 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2371 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2373 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2374 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2376 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2377 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2380 case OP_LOADU1_MEMBASE:
2381 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2383 case OP_LOADU2_MEMBASE:
2384 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2386 case OP_LOADU4_MEMBASE:
2387 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2389 case OP_LOADI1_MEMBASE:
2390 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2391 ia64_sxt1 (code, ins->dreg, ins->dreg);
2393 case OP_LOADI2_MEMBASE:
2394 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2395 ia64_sxt2 (code, ins->dreg, ins->dreg);
2397 case OP_LOADI4_MEMBASE:
2398 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2399 ia64_sxt4 (code, ins->dreg, ins->dreg);
2401 case OP_LOAD_MEMBASE:
2402 case OP_LOADI8_MEMBASE:
2403 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2406 case OP_IA64_LOADU1_MEMBASE_INC:
2407 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2409 case OP_IA64_LOADU2_MEMBASE_INC:
2410 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2412 case OP_IA64_LOADU4_MEMBASE_INC:
2413 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2415 case OP_IA64_LOADI8_MEMBASE_INC:
2416 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2420 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2423 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2426 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2429 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2432 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2435 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2438 /* Compare opcodes */
2439 case OP_IA64_CMP4_EQ:
2440 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2442 case OP_IA64_CMP4_NE:
2443 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2445 case OP_IA64_CMP4_LE:
2446 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2448 case OP_IA64_CMP4_LT:
2449 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2451 case OP_IA64_CMP4_GE:
2452 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2454 case OP_IA64_CMP4_GT:
2455 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2457 case OP_IA64_CMP4_LT_UN:
2458 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2460 case OP_IA64_CMP4_LE_UN:
2461 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2463 case OP_IA64_CMP4_GT_UN:
2464 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2466 case OP_IA64_CMP4_GE_UN:
2467 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2469 case OP_IA64_CMP_EQ:
2470 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2472 case OP_IA64_CMP_NE:
2473 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2475 case OP_IA64_CMP_LE:
2476 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2478 case OP_IA64_CMP_LT:
2479 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2481 case OP_IA64_CMP_GE:
2482 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2484 case OP_IA64_CMP_GT:
2485 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2487 case OP_IA64_CMP_GT_UN:
2488 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2490 case OP_IA64_CMP_LT_UN:
2491 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2493 case OP_IA64_CMP_GE_UN:
2494 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2496 case OP_IA64_CMP_LE_UN:
2497 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2499 case OP_IA64_CMP4_EQ_IMM:
2500 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2502 case OP_IA64_CMP4_NE_IMM:
2503 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2505 case OP_IA64_CMP4_LE_IMM:
2506 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2508 case OP_IA64_CMP4_LT_IMM:
2509 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2511 case OP_IA64_CMP4_GE_IMM:
2512 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2514 case OP_IA64_CMP4_GT_IMM:
2515 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2517 case OP_IA64_CMP4_LT_UN_IMM:
2518 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2520 case OP_IA64_CMP4_LE_UN_IMM:
2521 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2523 case OP_IA64_CMP4_GT_UN_IMM:
2524 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2526 case OP_IA64_CMP4_GE_UN_IMM:
2527 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2529 case OP_IA64_CMP_EQ_IMM:
2530 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2532 case OP_IA64_CMP_NE_IMM:
2533 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2535 case OP_IA64_CMP_LE_IMM:
2536 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2538 case OP_IA64_CMP_LT_IMM:
2539 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2541 case OP_IA64_CMP_GE_IMM:
2542 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2544 case OP_IA64_CMP_GT_IMM:
2545 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2547 case OP_IA64_CMP_GT_UN_IMM:
2548 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2550 case OP_IA64_CMP_LT_UN_IMM:
2551 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2553 case OP_IA64_CMP_GE_UN_IMM:
2554 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2556 case OP_IA64_CMP_LE_UN_IMM:
2557 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2559 case OP_IA64_FCMP_EQ:
2560 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2562 case OP_IA64_FCMP_NE:
2563 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2565 case OP_IA64_FCMP_LT:
2566 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2568 case OP_IA64_FCMP_GT:
2569 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2571 case OP_IA64_FCMP_LE:
2572 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2574 case OP_IA64_FCMP_GE:
2575 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2577 case OP_IA64_FCMP_GT_UN:
2578 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2579 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2581 case OP_IA64_FCMP_LT_UN:
2582 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2583 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2585 case OP_IA64_FCMP_GE_UN:
2586 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2587 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2589 case OP_IA64_FCMP_LE_UN:
2590 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2591 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2594 case OP_COND_EXC_IOV:
2595 case OP_COND_EXC_OV:
2596 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2598 case OP_COND_EXC_IC:
2600 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2602 case OP_IA64_COND_EXC:
2603 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2606 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2607 ia64_no_stop (code);
2608 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2611 /* FIXME: Is this needed ? */
2612 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2615 /* FIXME: Is this needed ? */
2616 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2619 /* FIXME: Is this needed ? */
2620 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2623 /* FIXME: Is this needed */
2624 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2627 /* FIXME: Is this needed */
2628 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2631 /* FIXME: Is this needed */
2632 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2636 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2640 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2647 double d = *(double *)ins->inst_p0;
2649 if ((d == 0.0) && (mono_signbit (d) == 0))
2650 ia64_fmov (code, ins->dreg, 0);
2652 ia64_fmov (code, ins->dreg, 1);
2654 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2655 ia64_movl (code, GP_SCRATCH_REG, 0);
2656 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2661 float f = *(float *)ins->inst_p0;
2663 if ((f == 0.0) && (mono_signbit (f) == 0))
2664 ia64_fmov (code, ins->dreg, 0);
2666 ia64_fmov (code, ins->dreg, 1);
2668 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2669 ia64_movl (code, GP_SCRATCH_REG, 0);
2670 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2675 ia64_fmov (code, ins->dreg, ins->sreg1);
2677 case OP_STORER8_MEMBASE_REG:
2678 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2680 case OP_STORER4_MEMBASE_REG:
2681 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2682 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2684 case OP_LOADR8_MEMBASE:
2685 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2687 case OP_LOADR4_MEMBASE:
2688 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2689 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2692 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2693 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2694 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2697 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2698 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2699 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2701 case OP_LCONV_TO_R8:
2702 /* FIXME: Difference with CEE_CONV_R8 ? */
2703 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2704 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2705 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2707 case OP_LCONV_TO_R4:
2708 /* FIXME: Difference with CEE_CONV_R4 ? */
2709 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2710 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2711 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2713 case OP_FCONV_TO_R4:
2714 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2716 case OP_FCONV_TO_I8:
2717 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2718 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2721 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2724 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2727 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2730 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2734 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2735 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2737 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2738 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2739 /* Positive infinity */
2740 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2741 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2742 /* Negative infinity */
2743 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2744 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2749 /* ensure ins->sreg1 is not NULL */
2750 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2753 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2754 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2761 call = (MonoCallInst*)ins;
2763 if (ins->flags & MONO_INST_HAS_METHOD)
2764 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2766 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2768 code = emit_move_return_value (cfg, ins, code);
2775 case OP_VOIDCALL_REG:
2776 call = (MonoCallInst*)ins;
2780 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2783 ia64_mov (code, IA64_R8, ins->sreg1);
2784 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2785 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2786 ia64_ld8 (code, IA64_GP, IA64_R8);
2787 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2789 code = emit_move_return_value (cfg, ins, code);
2792 case OP_FCALL_MEMBASE:
2793 case OP_LCALL_MEMBASE:
2794 case OP_VCALL_MEMBASE:
2795 case OP_VOIDCALL_MEMBASE:
2796 case OP_CALL_MEMBASE:
2798 * There are no membase instructions on ia64, but we can't
2799 * lower this since get_vcall_slot_addr () needs to decode it.
2802 /* Keep this in synch with get_vcall_slot_addr */
2803 if (ia64_is_imm14 (ins->inst_offset))
2804 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2806 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2807 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2810 ia64_begin_bundle (code);
2811 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2813 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2815 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2818 * This nop will tell get_vcall_slot_addr that this is a virtual
2821 ia64_nop_i (code, 0x12345);
2823 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2825 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2827 code = emit_move_return_value (cfg, ins, code);
2831 * Keep in sync with the code in emit_epilog.
2834 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2837 g_assert (!cfg->method->save_lmf);
2839 /* Load arguments into their original registers */
2840 code = emit_load_volatile_arguments (cfg, code);
2842 if (cfg->arch.stack_alloc_size) {
2843 if (cfg->arch.omit_fp) {
2844 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2845 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2847 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2848 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2852 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2854 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2855 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2857 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2858 ia64_movl (code, GP_SCRATCH_REG, 0);
2859 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2860 ia64_br_cond_reg (code, IA64_B6);
2865 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2871 /* FIXME: Sigaltstack support */
2873 /* keep alignment */
2874 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2875 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2876 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2878 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2880 ia64_mov (code, ins->dreg, IA64_SP);
2882 /* An area at sp is reserved by the ABI for parameter passing */
2883 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2884 if (ia64_is_adds_imm (abi_offset))
2885 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2887 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2888 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2891 if (ins->flags & MONO_INST_INIT) {
2893 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2895 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2898 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2899 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2900 ia64_br_cond_pred (code, 8, -2);
2902 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2904 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2910 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2911 ia64_ld8 (code, ins->dreg, ins->dreg);
2914 /* Synchronization */
2915 case OP_MEMORY_BARRIER:
2918 case OP_ATOMIC_ADD_IMM_NEW_I4:
2919 g_assert (ins->inst_offset == 0);
2920 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2921 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2923 case OP_ATOMIC_ADD_IMM_NEW_I8:
2924 g_assert (ins->inst_offset == 0);
2925 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2926 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2928 case OP_ATOMIC_EXCHANGE_I4:
2929 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2930 ia64_sxt4 (code, ins->dreg, ins->dreg);
2932 case OP_ATOMIC_EXCHANGE_I8:
2933 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2935 case OP_ATOMIC_ADD_NEW_I4: {
2936 guint8 *label, *buf;
2938 /* From libatomic_ops */
2941 ia64_begin_bundle (code);
2942 label = code.buf + code.nins;
2943 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2944 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2945 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2946 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2947 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2948 buf = code.buf + code.nins;
2949 ia64_br_cond_pred (code, 7, 0);
2950 ia64_begin_bundle (code);
2951 ia64_patch (buf, label);
2952 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2955 case OP_ATOMIC_ADD_NEW_I8: {
2956 guint8 *label, *buf;
2958 /* From libatomic_ops */
2961 ia64_begin_bundle (code);
2962 label = code.buf + code.nins;
2963 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2964 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2965 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2966 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2967 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2968 buf = code.buf + code.nins;
2969 ia64_br_cond_pred (code, 7, 0);
2970 ia64_begin_bundle (code);
2971 ia64_patch (buf, label);
2972 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2976 /* Exception handling */
2977 case OP_CALL_HANDLER:
2979 * Using a call instruction would mess up the register stack, so
2980 * save the return address to a register and use a
2983 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2984 ia64_mov (code, IA64_R15, IA64_R0);
2985 ia64_mov_from_ip (code, GP_SCRATCH_REG);
2986 /* Add the length of OP_CALL_HANDLER */
2987 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
2988 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2989 ia64_movl (code, GP_SCRATCH_REG2, 0);
2990 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2991 ia64_br_cond_reg (code, IA64_B6);
2992 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2994 case OP_START_HANDLER: {
2996 * We receive the return address in GP_SCRATCH_REG.
2998 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3001 * R15 determines our caller. It is used since it is writable using
3003 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3004 * R15 != 0 means we are called by call_filter ().
3006 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3007 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3009 ia64_br_cond_pred (code, 6, 6);
3012 * Called by call_filter:
3013 * Allocate a new stack frame, and set the fp register from the
3014 * value passed in by the caller.
3015 * We allocate a similar frame as is done by the prolog, so
3016 * if an exception is thrown while executing the filter, the
3017 * unwinder can unwind through the filter frame using the unwind
3018 * info for the prolog.
3020 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);
3021 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3022 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3023 ia64_mov (code, cfg->frame_reg, IA64_R15);
3024 /* Signal to endfilter that we are called by call_filter */
3025 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3027 /* Save the return address */
3028 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3029 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3030 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3035 case OP_ENDFILTER: {
3036 /* FIXME: Return the value in ENDFILTER */
3037 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3039 /* Load the return address */
3040 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3041 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3044 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3045 ia64_br_cond_pred (code, 7, 4);
3047 /* Called by call_filter */
3049 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3050 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3051 ia64_br_ret_reg (code, IA64_B0);
3053 /* Called by CALL_HANDLER */
3054 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3055 ia64_br_cond_reg (code, IA64_B6);
3059 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3060 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3061 (gpointer)"mono_arch_throw_exception");
3064 * This might be the last instruction in the method, so add a dummy
3065 * instruction so the unwinder will work.
3067 ia64_break_i (code, 0);
3070 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3071 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3072 (gpointer)"mono_arch_rethrow_exception");
3074 ia64_break_i (code, 0);
3078 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3079 g_assert_not_reached ();
3082 if ((code.buf - cfg->native_code - offset) > max_len) {
3083 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3084 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3085 g_assert_not_reached ();
3091 last_offset = offset;
3096 ia64_codegen_close (code);
3098 cfg->code_len = code.buf - cfg->native_code;
3102 mono_arch_register_lowlevel_calls (void)
3104 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3107 static Ia64InsType ins_types_in_template [32][3] = {
3108 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3109 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3110 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3111 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3112 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3113 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3116 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3117 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3118 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3119 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3120 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3121 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3122 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3123 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3124 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3125 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3126 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3127 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3130 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3131 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3132 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3133 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3136 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3137 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3142 static gboolean stops_in_template [32][3] = {
3143 { FALSE, FALSE, FALSE },
3144 { FALSE, FALSE, TRUE },
3145 { FALSE, TRUE, FALSE },
3146 { FALSE, TRUE, TRUE },
3147 { FALSE, FALSE, FALSE },
3148 { FALSE, FALSE, TRUE },
3149 { FALSE, FALSE, FALSE },
3150 { FALSE, FALSE, FALSE },
3152 { FALSE, FALSE, FALSE },
3153 { FALSE, FALSE, TRUE },
3154 { TRUE, FALSE, FALSE },
3155 { TRUE, FALSE, TRUE },
3156 { FALSE, FALSE, FALSE },
3157 { FALSE, FALSE, TRUE },
3158 { FALSE, FALSE, FALSE },
3159 { FALSE, FALSE, TRUE },
3161 { FALSE, FALSE, FALSE },
3162 { FALSE, FALSE, TRUE },
3163 { FALSE, FALSE, FALSE },
3164 { FALSE, FALSE, TRUE },
3165 { FALSE, FALSE, FALSE },
3166 { FALSE, FALSE, FALSE },
3167 { FALSE, FALSE, FALSE },
3168 { FALSE, FALSE, TRUE },
3170 { FALSE, FALSE, FALSE },
3171 { FALSE, FALSE, TRUE },
3172 { FALSE, FALSE, FALSE },
3173 { FALSE, FALSE, FALSE },
3174 { FALSE, FALSE, FALSE },
3175 { FALSE, FALSE, TRUE },
3176 { FALSE, FALSE, FALSE },
3177 { FALSE, FALSE, FALSE }
3180 static int last_stop_in_template [32] = {
3181 -1, 2, 1, 2, -1, 2, -1, -1,
3182 -1, 2, 0, 2, -1, 2, -1, 2,
3183 -1, 2, -1, 2, -1, -1, -1, 2,
3184 -1, 2, -1, -1, -1, 2, -1, -1
3187 static guint64 nops_for_ins_types [6] = {
3196 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3203 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3205 #define DEBUG_INS_SCHED(a)
3209 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3211 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3212 guint8 *deps = code->dep_info;
3213 gboolean need_stop, no_stop;
3215 for (i = 0; i < code->nins; ++i)
3219 current_deps_start = 0;
3220 current_ins_start = 0;
3221 deps_start [ins_index] = current_ins_start;
3224 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3225 while (pos < code->dep_info_pos) {
3227 switch (deps [pos]) {
3228 case IA64_END_OF_INS:
3230 current_ins_start = pos + 2;
3231 deps_start [ins_index] = current_ins_start;
3233 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3238 reg = deps [pos + 1];
3240 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3241 for (i = current_deps_start; i < current_ins_start; i += 2)
3242 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3246 reg = code->dep_info [pos + 1];
3248 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3249 for (i = current_deps_start; i < current_ins_start; i += 2)
3250 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3254 reg = deps [pos + 1];
3256 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3257 for (i = current_deps_start; i < current_ins_start; i += 2)
3258 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3261 case IA64_READ_PR_BRANCH:
3262 reg = deps [pos + 1];
3264 /* Writes to prs by non-float instructions are visible to branches */
3265 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3266 for (i = current_deps_start; i < current_ins_start; i += 2)
3267 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3271 reg = code->dep_info [pos + 1];
3273 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3274 for (i = current_deps_start; i < current_ins_start; i += 2)
3275 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3278 case IA64_WRITE_PR_FLOAT:
3279 reg = code->dep_info [pos + 1];
3281 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3282 for (i = current_deps_start; i < current_ins_start; i += 2)
3283 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3287 reg = deps [pos + 1];
3289 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3290 for (i = current_deps_start; i < current_ins_start; i += 2)
3291 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3295 reg = code->dep_info [pos + 1];
3297 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3298 for (i = current_deps_start; i < current_ins_start; i += 2)
3299 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3302 case IA64_READ_BR_BRANCH:
3303 reg = deps [pos + 1];
3305 /* Writes to brs are visible to branches */
3306 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3309 reg = deps [pos + 1];
3311 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3312 for (i = current_deps_start; i < current_ins_start; i += 2)
3313 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3317 reg = code->dep_info [pos + 1];
3319 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3320 for (i = current_deps_start; i < current_ins_start; i += 2)
3321 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3325 reg = deps [pos + 1];
3327 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3328 for (i = current_deps_start; i < current_ins_start; i += 2)
3329 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3333 reg = code->dep_info [pos + 1];
3335 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3336 for (i = current_deps_start; i < current_ins_start; i += 2)
3337 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3342 * Explicitly indicate that a stop is not required. Useful for
3343 * example when two predicated instructions with negated predicates
3344 * write the same registers.
3349 g_assert_not_reached ();
3353 if (need_stop && !no_stop) {
3354 g_assert (ins_index > 0);
3355 stops [ins_index - 1] = 1;
3357 DEBUG_INS_SCHED (printf ("STOP\n"));
3358 current_deps_start = current_ins_start;
3360 /* Skip remaining deps for this instruction */
3361 while (deps [pos] != IA64_END_OF_INS)
3366 if (code->nins > 0) {
3367 /* No dependency info for the last instruction */
3368 stops [code->nins - 1] = 1;
3371 deps_start [code->nins] = code->dep_info_pos;
3375 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3377 int stop_pos, i, deps_to_shift, dep_shift;
3379 g_assert (n <= code->nins);
3381 // if (n > 1) printf ("FOUND: %ld.\n", template);
3383 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3385 stop_pos = last_stop_in_template [template] + 1;
3389 /* Compute the number of 'real' instructions before the stop */
3390 deps_to_shift = stop_pos;
3391 if (stop_pos >= 3 && (nops & (1 << 2)))
3393 if (stop_pos >= 2 && (nops & (1 << 1)))
3395 if (stop_pos >= 1 && (nops & (1 << 0)))
3399 * We have to keep some dependencies whose instructions have been shifted
3400 * out of the buffer. So nullify the end_of_ins markers in the dependency
3403 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3404 if (code->dep_info [i] == IA64_END_OF_INS)
3405 code->dep_info [i] = IA64_NONE;
3407 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3408 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3409 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3411 dep_shift = deps_start [deps_to_shift];
3412 for (i = 0; i < code->nins + 1 - n; ++i)
3413 deps_start [i] = deps_start [n + i] - dep_shift;
3415 /* Determine the exact positions of instructions with unwind ops */
3416 if (code->unw_op_count) {
3418 int curr_ins, curr_ins_pos;
3421 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3422 for (i = 0; i < 3; ++i) {
3423 if (! (nops & (1 << i))) {
3424 ins_pos [curr_ins] = curr_ins_pos + i;
3429 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3430 if (code->unw_ops_pos [i] < n) {
3431 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3432 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3435 if (code->unw_op_pos < code->unw_op_count)
3436 code->unw_op_pos += n;
3439 if (n == code->nins) {
3444 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3445 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3446 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3452 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3454 int i, ins_type, template, nins_to_emit;
3455 int deps_start [16];
3460 * We implement a simple scheduler which tries to put three instructions
3461 * per bundle, then two, then one.
3463 ia64_analyze_deps (code, deps_start, stops);
3465 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3466 /* Find a suitable template */
3467 for (template = 0; template < 32; ++template) {
3468 if (stops_in_template [template][0] != stops [0] ||
3469 stops_in_template [template][1] != stops [1] ||
3470 stops_in_template [template][2] != stops [2])
3474 for (i = 0; i < 3; ++i) {
3475 ins_type = ins_types_in_template [template][i];
3476 switch (code->itypes [i]) {
3477 case IA64_INS_TYPE_A:
3478 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3481 found &= (ins_type == code->itypes [i]);
3487 found = debug_ins_sched ();
3490 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3496 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3497 /* Wait for more instructions */
3500 /* If it didn't work out, try putting two instructions into one bundle */
3501 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3502 /* Try a nop at the end */
3503 for (template = 0; template < 32; ++template) {
3504 if (stops_in_template [template][0] != stops [0] ||
3505 ((stops_in_template [template][1] != stops [1]) &&
3506 (stops_in_template [template][2] != stops [1])))
3510 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3511 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3514 if (!debug_ins_sched ())
3517 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);
3522 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3523 /* Wait for more instructions */
3526 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3527 /* Try a nop in the middle */
3528 for (template = 0; template < 32; ++template) {
3529 if (((stops_in_template [template][0] != stops [0]) &&
3530 (stops_in_template [template][1] != stops [0])) ||
3531 stops_in_template [template][2] != stops [1])
3534 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3535 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3538 if (!debug_ins_sched ())
3541 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);
3546 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3547 /* Try a nop at the beginning */
3548 for (template = 0; template < 32; ++template) {
3549 if ((stops_in_template [template][1] != stops [0]) ||
3550 (stops_in_template [template][2] != stops [1]))
3553 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3554 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3557 if (!debug_ins_sched ())
3560 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);
3565 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3566 /* Wait for more instructions */
3570 nins_to_emit = code->nins;
3574 while (nins_to_emit > 0) {
3575 if (!debug_ins_sched ())
3577 switch (code->itypes [0]) {
3578 case IA64_INS_TYPE_A:
3580 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3582 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3584 case IA64_INS_TYPE_I:
3586 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3588 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3590 case IA64_INS_TYPE_M:
3592 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3594 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3596 case IA64_INS_TYPE_B:
3598 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3600 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3602 case IA64_INS_TYPE_F:
3604 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3606 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3608 case IA64_INS_TYPE_LX:
3609 if (stops [0] || stops [1])
3610 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3612 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3616 g_assert_not_reached ();
3622 unw_dyn_region_info_t*
3623 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3625 unw_dyn_region_info_t *r;
3627 g_assert (code->nins == 0);
3628 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3629 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3630 r->op_count = code->unw_op_count;
3631 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3632 code->unw_op_count = 0;
3633 code->unw_op_pos = 0;
3634 code->region_start = code->buf;
3640 ia64_patch (unsigned char* code, gpointer target)
3643 guint64 instructions [3];
3644 guint8 gen_buf [16];
3645 Ia64CodegenState gen;
3650 * code encodes both the position inside the buffer and code.nins when
3651 * the instruction was emitted.
3653 ins_to_skip = (guint64)code % 16;
3654 code = (unsigned char*)((guint64)code & ~15);
3657 * Search for the first instruction which is 'patchable', skipping
3658 * ins_to_skip instructions.
3663 template = ia64_bundle_template (code);
3664 instructions [0] = ia64_bundle_ins1 (code);
3665 instructions [1] = ia64_bundle_ins2 (code);
3666 instructions [2] = ia64_bundle_ins3 (code);
3668 ia64_codegen_init (gen, gen_buf);
3671 for (i = 0; i < 3; ++i) {
3672 guint64 ins = instructions [i];
3673 int opcode = ia64_ins_opcode (ins);
3675 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3683 switch (ins_types_in_template [template][i]) {
3684 case IA64_INS_TYPE_A:
3685 case IA64_INS_TYPE_M:
3686 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3688 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3689 instructions [i] = gen.instructions [0];
3695 case IA64_INS_TYPE_B:
3696 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3698 gint64 disp = ((guint8*)target - code) >> 4;
3701 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3703 instructions [i] = gen.instructions [0];
3706 else if (opcode == 5) {
3708 gint64 disp = ((guint8*)target - code) >> 4;
3711 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3712 instructions [i] = gen.instructions [0];
3718 case IA64_INS_TYPE_LX:
3722 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3724 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3725 instructions [1] = gen.instructions [0];
3726 instructions [2] = gen.instructions [1];
3739 ia64_codegen_init (gen, code);
3740 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3750 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3752 MonoJumpInfo *patch_info;
3754 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3755 unsigned char *ip = patch_info->ip.i + code;
3756 const unsigned char *target;
3758 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3760 if (patch_info->type == MONO_PATCH_INFO_NONE)
3762 if (mono_compile_aot) {
3766 ia64_patch (ip, (gpointer)target);
3771 mono_arch_emit_prolog (MonoCompile *cfg)
3773 MonoMethod *method = cfg->method;
3774 MonoMethodSignature *sig;
3776 int alloc_size, pos, i;
3777 Ia64CodegenState code;
3780 sig = mono_method_signature (method);
3783 cinfo = get_call_info (sig, FALSE);
3785 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3787 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3788 cfg->code_size += 1024;
3789 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3790 cfg->code_size += 1024;
3792 cfg->native_code = g_malloc (cfg->code_size);
3794 ia64_codegen_init (code, cfg->native_code);
3796 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3797 if (cfg->param_area)
3798 alloc_size += cfg->param_area;
3802 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3804 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3805 /* Force sp to be saved/restored */
3806 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3808 cfg->arch.stack_alloc_size = alloc_size;
3812 if (method->save_lmf) {
3813 /* No LMF on IA64 */
3818 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3819 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);
3820 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3821 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3823 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3824 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3825 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3826 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3827 ia64_mov (code, cfg->frame_reg, IA64_SP);
3831 int pagesize = getpagesize ();
3833 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3834 if (alloc_size >= pagesize) {
3835 gint32 remaining_size = alloc_size;
3837 /* Generate stack touching code */
3838 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3839 while (remaining_size >= pagesize) {
3840 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3841 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3842 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3843 remaining_size -= pagesize;
3847 if (ia64_is_imm14 (-alloc_size)) {
3848 if (cfg->arch.omit_fp)
3849 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3850 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3853 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3854 if (cfg->arch.omit_fp)
3855 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3856 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3860 ia64_begin_bundle (code);
3862 /* Initialize unwind info */
3863 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3865 if (sig->ret->type != MONO_TYPE_VOID) {
3866 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3867 /* Save volatile arguments to the stack */
3872 /* Keep this in sync with emit_load_volatile_arguments */
3873 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3874 ArgInfo *ainfo = cinfo->args + i;
3875 gint32 stack_offset;
3877 inst = cfg->args [i];
3879 if (sig->hasthis && (i == 0))
3880 arg_type = &mono_defaults.object_class->byval_arg;
3882 arg_type = sig->params [i - sig->hasthis];
3884 arg_type = mono_type_get_underlying_type (arg_type);
3886 stack_offset = ainfo->offset + ARGS_OFFSET;
3888 /* Save volatile arguments to the stack */
3889 if (inst->opcode != OP_REGVAR) {
3890 switch (ainfo->storage) {
3893 g_assert (inst->opcode == OP_REGOFFSET);
3894 if (ia64_is_adds_imm (inst->inst_offset))
3895 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3897 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3898 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3900 if (arg_type->byref)
3901 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3903 switch (arg_type->type) {
3905 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3908 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3911 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3919 if (ainfo->nslots != ainfo->nregs)
3922 g_assert (inst->opcode == OP_REGOFFSET);
3923 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3924 for (i = 0; i < ainfo->nregs; ++i) {
3925 switch (ainfo->atype) {
3926 case AggregateNormal:
3927 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3929 case AggregateSingleHFA:
3930 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3932 case AggregateDoubleHFA:
3933 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3941 g_assert_not_reached ();
3945 if (inst->opcode == OP_REGVAR) {
3946 /* Argument allocated to (non-volatile) register */
3947 switch (ainfo->storage) {
3949 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3950 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3953 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3954 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3962 if (method->save_lmf) {
3963 /* No LMF on IA64 */
3966 ia64_codegen_close (code);
3970 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3971 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
3973 cfg->code_len = code.buf - cfg->native_code;
3975 g_assert (cfg->code_len < cfg->code_size);
3977 cfg->arch.prolog_end_offset = cfg->code_len;
3983 mono_arch_emit_epilog (MonoCompile *cfg)
3985 MonoMethod *method = cfg->method;
3987 int max_epilog_size = 16 * 4;
3988 Ia64CodegenState code;
3993 if (mono_jit_trace_calls != NULL)
3994 max_epilog_size += 1024;
3996 cfg->arch.epilog_begin_offset = cfg->code_len;
3998 while (cfg->code_len + max_epilog_size > cfg->code_size) {
3999 cfg->code_size *= 2;
4000 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4001 mono_jit_stats.code_reallocs++;
4004 /* FIXME: Emit unwind info */
4006 buf = cfg->native_code + cfg->code_len;
4008 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4009 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4011 ia64_codegen_init (code, buf);
4013 /* the code restoring the registers must be kept in sync with OP_JMP */
4016 if (method->save_lmf) {
4017 /* No LMF on IA64 */
4020 /* Load returned vtypes into registers if needed */
4021 cinfo = get_call_info (mono_method_signature (method), FALSE);
4022 ainfo = &cinfo->ret;
4023 switch (ainfo->storage) {
4025 if (ainfo->nslots != ainfo->nregs)
4028 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4029 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4030 for (i = 0; i < ainfo->nregs; ++i) {
4031 switch (ainfo->atype) {
4032 case AggregateNormal:
4033 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4035 case AggregateSingleHFA:
4036 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4038 case AggregateDoubleHFA:
4039 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4042 g_assert_not_reached ();
4051 ia64_begin_bundle (code);
4053 code.region_start = cfg->native_code;
4055 /* Label the unwind state at the start of the exception throwing region */
4056 //ia64_unw_label_state (code, 1234);
4058 if (cfg->arch.stack_alloc_size) {
4059 if (cfg->arch.omit_fp) {
4060 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4061 ia64_unw_pop_frames (code, 1);
4062 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4064 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4065 ia64_unw_pop_frames (code, 1);
4066 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4070 ia64_unw_pop_frames (code, 1);
4071 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4074 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4075 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4076 ia64_br_ret_reg (code, IA64_B0);
4078 ia64_codegen_close (code);
4080 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4081 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4083 cfg->code_len = code.buf - cfg->native_code;
4085 g_assert (cfg->code_len < cfg->code_size);
4089 mono_arch_emit_exceptions (MonoCompile *cfg)
4091 MonoJumpInfo *patch_info;
4093 Ia64CodegenState code;
4094 gboolean empty = TRUE;
4095 //unw_dyn_region_info_t *r_exceptions;
4096 MonoClass *exc_classes [16];
4097 guint8 *exc_throw_start [16], *exc_throw_end [16];
4098 guint32 code_size = 0;
4100 /* Compute needed space */
4101 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4102 if (patch_info->type == MONO_PATCH_INFO_EXC)
4104 if (patch_info->type == MONO_PATCH_INFO_R8)
4105 code_size += 8 + 7; /* sizeof (double) + alignment */
4106 if (patch_info->type == MONO_PATCH_INFO_R4)
4107 code_size += 4 + 7; /* sizeof (float) + alignment */
4113 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4114 cfg->code_size *= 2;
4115 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4116 mono_jit_stats.code_reallocs++;
4119 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4121 /* The unwind state here is the same as before the epilog */
4122 //ia64_unw_copy_state (code, 1234);
4124 /* add code to raise exceptions */
4125 /* FIXME: Optimize this */
4127 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4128 switch (patch_info->type) {
4129 case MONO_PATCH_INFO_EXC: {
4130 MonoClass *exc_class;
4133 guint64 exc_token_index;
4135 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4136 g_assert (exc_class);
4137 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4138 throw_ip = cfg->native_code + patch_info->ip.i;
4140 ia64_begin_bundle (code);
4142 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4144 /* Find a throw sequence for the same exception class */
4145 for (i = 0; i < nthrows; ++i)
4146 if (exc_classes [i] == exc_class)
4150 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4152 if (ia64_is_adds_imm (offset))
4153 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4155 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4157 buf = code.buf + code.nins;
4158 ia64_br_cond_pred (code, 0, 0);
4159 ia64_begin_bundle (code);
4160 ia64_patch (buf, exc_throw_start [i]);
4162 patch_info->type = MONO_PATCH_INFO_NONE;
4167 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4169 ia64_begin_bundle (code);
4172 exc_classes [nthrows] = exc_class;
4173 exc_throw_start [nthrows] = code.buf;
4177 if (ia64_is_adds_imm (exc_token_index))
4178 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4180 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4182 patch_info->data.name = "mono_arch_throw_corlib_exception";
4183 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4184 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4187 ia64_movl (code, GP_SCRATCH_REG, 0);
4188 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4189 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4190 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4192 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4194 /* Patch up the throw offset */
4195 ia64_begin_bundle (code);
4197 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4200 exc_throw_end [nthrows] = code.buf;
4214 /* The unwinder needs this to work */
4215 ia64_break_i (code, 0);
4217 ia64_codegen_close (code);
4220 //r_exceptions = mono_ia64_create_unwind_region (&code);
4221 //cfg->arch.r_epilog = r_exceptions;
4223 cfg->code_len = code.buf - cfg->native_code;
4225 g_assert (cfg->code_len < cfg->code_size);
4229 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4231 Ia64CodegenState code;
4232 CallInfo *cinfo = NULL;
4233 MonoMethodSignature *sig;
4235 int i, n, stack_area = 0;
4237 ia64_codegen_init (code, p);
4239 /* Keep this in sync with mono_arch_get_argument_info */
4241 if (enable_arguments) {
4242 /* Allocate a new area on the stack and save arguments there */
4243 sig = mono_method_signature (cfg->method);
4245 cinfo = get_call_info (sig, FALSE);
4247 n = sig->param_count + sig->hasthis;
4249 stack_area = ALIGN_TO (n * 8, 16);
4252 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4254 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4256 /* FIXME: Allocate out registers */
4258 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4260 /* Required by the ABI */
4261 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4263 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4264 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4266 /* Save arguments to the stack */
4267 for (i = 0; i < n; ++i) {
4268 ins = cfg->args [i];
4270 if (ins->opcode == OP_REGVAR) {
4271 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4272 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4273 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4276 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4277 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4278 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4279 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4280 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4281 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4286 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4289 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4291 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4292 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4294 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4296 if (enable_arguments && stack_area) {
4297 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4299 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4301 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4306 ia64_codegen_close (code);
4312 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4314 Ia64CodegenState code;
4315 CallInfo *cinfo = NULL;
4316 MonoMethod *method = cfg->method;
4317 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4319 ia64_codegen_init (code, p);
4321 cinfo = get_call_info (sig, FALSE);
4323 /* Save return value + pass it to func */
4324 switch (cinfo->ret.storage) {
4328 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4329 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4332 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4333 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4334 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4335 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4337 case ArgValuetypeAddrInIReg:
4338 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4349 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4350 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4351 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4353 /* Restore return value */
4354 switch (cinfo->ret.storage) {
4358 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4361 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4362 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4364 case ArgValuetypeAddrInIReg:
4372 ia64_codegen_close (code);
4378 mono_arch_save_unwind_info (MonoCompile *cfg)
4382 /* FIXME: Unregister this for dynamic methods */
4384 di = g_malloc0 (sizeof (unw_dyn_info_t));
4385 di->start_ip = (unw_word_t) cfg->native_code;
4386 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4388 di->format = UNW_INFO_FORMAT_DYNAMIC;
4389 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4390 di->u.pi.regions = cfg->arch.r_pro;
4392 _U_dyn_register (di);
4396 unw_dyn_region_info_t *region = di->u.pi.regions;
4398 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4400 printf (" [Region: %d]\n", region->insn_count);
4401 region = region->next;
4408 mono_arch_flush_icache (guint8 *code, gint size)
4410 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4411 guint8* end = (guint8*)((guint64)code + size);
4413 #ifdef __INTEL_COMPILER
4414 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4421 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4422 /* FIXME: This could be increased to 128 on some cpus */
4429 mono_arch_flush_register_windows (void)
4431 /* Not needed because of libunwind */
4435 mono_arch_is_inst_imm (gint64 imm)
4437 /* The lowering pass will take care of it */
4443 * Determine whenever the trap whose info is in SIGINFO is caused by
4447 mono_arch_is_int_overflow (void *sigctx, void *info)
4449 /* Division is emulated with explicit overflow checks */
4454 mono_arch_get_patch_offset (guint8 *code)
4462 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4464 guint8 *bundle2 = code - 48;
4465 guint8 *bundle3 = code - 32;
4466 guint8 *bundle4 = code - 16;
4467 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4468 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4469 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4470 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4471 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4472 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4473 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4474 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4475 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4479 * Virtual calls are made with:
4481 * [MII] ld8 r31=[r8]
4485 * mov.sptk b6=r31,0x2000000000f32a80
4492 * br.call.sptk.few b0=b6;;
4495 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4496 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4497 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4498 (ins31 == IA64_NOP_M) &&
4499 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4500 (ins33 == IA64_NOP_I) &&
4501 (ins41 == IA64_NOP_M) &&
4502 (ins42 == IA64_NOP_I) &&
4503 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4504 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4505 g_assert (ins21 == IA64_NOP_M);
4506 g_assert (ins23 == IA64_NOP_I);
4507 g_assert (ia64_ins_opcode (ins22) == 0);
4508 g_assert (ia64_ins_x3 (ins22) == 7);
4509 g_assert (ia64_ins_x (ins22) == 0);
4510 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4515 * Must be a scratch register, since only those are saved by the trampoline
4517 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4519 g_assert (regs [reg]);
4528 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4535 static gboolean tls_offset_inited = FALSE;
4538 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4540 if (!tls_offset_inited) {
4541 tls_offset_inited = TRUE;
4543 appdomain_tls_offset = mono_domain_get_tls_offset ();
4544 thread_tls_offset = mono_thread_get_tls_offset ();
4549 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4554 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4556 MonoCallInst *call = (MonoCallInst*)inst;
4557 int out_reg = cfg->arch.reg_out0;
4560 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4563 if (cinfo->ret.storage == ArgAggregate) {
4564 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4567 * The valuetype is in registers after the call, need to be copied
4568 * to the stack. Save the address to a local here, so the call
4569 * instruction can access it.
4571 g_assert (local->opcode == OP_REGOFFSET);
4572 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4575 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4576 vtarg->sreg1 = vt_reg;
4577 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4578 mono_bblock_add_inst (cfg->cbb, vtarg);
4580 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4588 /* add the this argument */
4589 if (this_reg != -1) {
4591 MONO_INST_NEW (cfg, this, OP_MOVE);
4592 this->type = this_type;
4593 this->sreg1 = this_reg;
4594 this->dreg = mono_regstate_next_int (cfg->rs);
4595 mono_bblock_add_inst (cfg->cbb, this);
4597 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4602 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4604 MonoInst *ins = NULL;
4606 if (cmethod->klass == mono_defaults.thread_class &&
4607 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4608 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4609 } else if(cmethod->klass->image == mono_defaults.corlib &&
4610 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4611 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4613 if (strcmp (cmethod->name, "Increment") == 0) {
4616 if (fsig->params [0]->type == MONO_TYPE_I4)
4617 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4618 else if (fsig->params [0]->type == MONO_TYPE_I8)
4619 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4621 g_assert_not_reached ();
4622 MONO_INST_NEW (cfg, ins, opcode);
4624 ins->inst_i0 = args [0];
4625 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4628 if (fsig->params [0]->type == MONO_TYPE_I4)
4629 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4630 else if (fsig->params [0]->type == MONO_TYPE_I8)
4631 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4633 g_assert_not_reached ();
4634 MONO_INST_NEW (cfg, ins, opcode);
4636 ins->inst_i0 = args [0];
4637 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4640 if (fsig->params [0]->type == MONO_TYPE_I4)
4641 opcode = OP_ATOMIC_EXCHANGE_I4;
4642 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4643 (fsig->params [0]->type == MONO_TYPE_I) ||
4644 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4645 opcode = OP_ATOMIC_EXCHANGE_I8;
4649 MONO_INST_NEW (cfg, ins, opcode);
4651 ins->inst_i0 = args [0];
4652 ins->inst_i1 = args [1];
4653 } else if (strcmp (cmethod->name, "Add") == 0) {
4656 if (fsig->params [0]->type == MONO_TYPE_I4)
4657 opcode = OP_ATOMIC_ADD_NEW_I4;
4658 else if (fsig->params [0]->type == MONO_TYPE_I8)
4659 opcode = OP_ATOMIC_ADD_NEW_I8;
4661 g_assert_not_reached ();
4663 MONO_INST_NEW (cfg, ins, opcode);
4665 ins->inst_i0 = args [0];
4666 ins->inst_i1 = args [1];
4667 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4668 /* 64 bit reads are already atomic */
4669 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4670 ins->inst_i0 = args [0];
4678 mono_arch_print_tree (MonoInst *tree, int arity)
4683 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4687 if (appdomain_tls_offset == -1)
4690 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4691 ins->inst_offset = appdomain_tls_offset;
4695 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4699 if (thread_tls_offset == -1)
4702 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4703 ins->inst_offset = thread_tls_offset;