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 * Initialize architecture specific code.
573 mono_arch_init (void)
578 * Cleanup architecture specific code.
581 mono_arch_cleanup (void)
586 * This function returns the optimizations supported on this cpu.
589 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
597 mono_arch_break (void)
602 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
606 MonoMethodSignature *sig;
607 MonoMethodHeader *header;
610 header = mono_method_get_header (cfg->method);
612 sig = mono_method_signature (cfg->method);
614 cinfo = get_call_info (sig, FALSE);
616 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
617 MonoInst *ins = cfg->args [i];
619 ArgInfo *ainfo = &cinfo->args [i];
621 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
624 if (ainfo->storage == ArgInIReg) {
625 /* The input registers are non-volatile */
626 ins->opcode = OP_REGVAR;
627 ins->dreg = 32 + ainfo->reg;
631 for (i = 0; i < cfg->num_varinfo; i++) {
632 MonoInst *ins = cfg->varinfo [i];
633 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
636 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
639 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
640 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
643 if (mono_is_regsize_var (ins->inst_vtype)) {
644 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
645 g_assert (i == vmv->idx);
646 vars = g_list_prepend (vars, vmv);
650 vars = mono_varlist_sort (cfg, vars, 0);
656 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
659 guint32 reserved_regs;
660 MonoMethodHeader *header;
662 if (cfg->arch.reg_local0 > 0)
666 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
668 header = mono_method_get_header (cfg->method);
670 /* Some registers are reserved for use by the prolog/epilog */
671 reserved_regs = header->num_clauses ? 4 : 3;
673 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
674 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
675 /* One registers is needed by instrument_epilog to save the return value */
677 if (cinfo->reg_usage < 2)
678 /* Number of arguments passed to function call in instrument_prolog */
679 cinfo->reg_usage = 2;
682 cfg->arch.reg_in0 = 32;
683 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
684 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
686 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
687 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
688 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
691 * Frames without handlers save sp to fp, frames with handlers save it into
692 * a dedicated register.
694 if (header->num_clauses)
695 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
697 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
699 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
700 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
701 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
705 * Need to allocate at least 2 out register for use by OP_THROW / the system
706 * exception throwing code.
708 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
714 mono_arch_get_global_int_regs (MonoCompile *cfg)
719 mono_ia64_alloc_stacked_registers (cfg);
721 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
724 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
731 * mono_arch_regalloc_cost:
733 * Return the cost, in number of memory references, of the action of
734 * allocating the variable VMV into a register during global register
738 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
740 /* FIXME: Increase costs linearly to avoid using all local registers */
746 mono_arch_allocate_vars (MonoCompile *cfg)
748 MonoMethodSignature *sig;
749 MonoMethodHeader *header;
752 guint32 locals_stack_size, locals_stack_align;
756 header = mono_method_get_header (cfg->method);
758 sig = mono_method_signature (cfg->method);
760 cinfo = get_call_info (sig, FALSE);
763 * Determine whenever the frame pointer can be eliminated.
764 * FIXME: Remove some of the restrictions.
766 cfg->arch.omit_fp = TRUE;
768 if (!debug_omit_fp ())
769 cfg->arch.omit_fp = FALSE;
771 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
772 cfg->arch.omit_fp = FALSE;
773 if (header->num_clauses)
774 cfg->arch.omit_fp = FALSE;
776 cfg->arch.omit_fp = FALSE;
777 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
778 ArgInfo *ainfo = &cinfo->args [i];
780 if (ainfo->storage == ArgOnStack) {
782 * The stack offset can only be determined when the frame
785 cfg->arch.omit_fp = FALSE;
789 mono_ia64_alloc_stacked_registers (cfg);
792 * We use the ABI calling conventions for managed code as well.
793 * Exception: valuetypes are never passed or returned in registers.
796 if (cfg->arch.omit_fp) {
797 cfg->frame_reg = IA64_SP;
798 offset = ARGS_OFFSET;
801 /* Locals are allocated backwards from %fp */
802 cfg->frame_reg = cfg->arch.reg_fp;
806 if (cfg->method->save_lmf) {
810 if (sig->ret->type != MONO_TYPE_VOID) {
811 switch (cinfo->ret.storage) {
813 cfg->ret->opcode = OP_REGVAR;
814 cfg->ret->inst_c0 = cinfo->ret.reg;
817 cfg->ret->opcode = OP_REGVAR;
818 cfg->ret->inst_c0 = cinfo->ret.reg;
820 case ArgValuetypeAddrInIReg:
821 cfg->ret->opcode = OP_REGVAR;
822 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
825 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
826 if (cfg->arch.omit_fp)
827 g_assert_not_reached ();
828 offset = ALIGN_TO (offset, 8);
829 offset += cinfo->ret.nslots * 8;
830 cfg->ret->opcode = OP_REGOFFSET;
831 cfg->ret->inst_basereg = cfg->frame_reg;
832 cfg->ret->inst_offset = - offset;
835 g_assert_not_reached ();
837 cfg->ret->dreg = cfg->ret->inst_c0;
840 /* Allocate locals */
841 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
842 if (locals_stack_align) {
843 offset = ALIGN_TO (offset, locals_stack_align);
845 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
846 if (offsets [i] != -1) {
847 MonoInst *inst = cfg->varinfo [i];
848 inst->opcode = OP_REGOFFSET;
849 inst->inst_basereg = cfg->frame_reg;
850 if (cfg->arch.omit_fp)
851 inst->inst_offset = (offset + offsets [i]);
853 inst->inst_offset = - (offset + offsets [i]);
854 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
857 offset += locals_stack_size;
859 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
860 if (cfg->arch.omit_fp)
861 g_assert_not_reached ();
862 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
863 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
866 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
867 inst = cfg->args [i];
868 if (inst->opcode != OP_REGVAR) {
869 ArgInfo *ainfo = &cinfo->args [i];
870 gboolean inreg = TRUE;
873 if (sig->hasthis && (i == 0))
874 arg_type = &mono_defaults.object_class->byval_arg;
876 arg_type = sig->params [i - sig->hasthis];
878 /* FIXME: VOLATILE is only set if the liveness pass runs */
879 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
882 inst->opcode = OP_REGOFFSET;
884 switch (ainfo->storage) {
886 inst->opcode = OP_REGVAR;
887 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
891 * Since float regs are volatile, we save the arguments to
892 * the stack in the prolog.
897 if (cfg->arch.omit_fp)
898 g_assert_not_reached ();
899 inst->opcode = OP_REGOFFSET;
900 inst->inst_basereg = cfg->frame_reg;
901 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
910 if (!inreg && (ainfo->storage != ArgOnStack)) {
911 inst->opcode = OP_REGOFFSET;
912 inst->inst_basereg = cfg->frame_reg;
913 /* These arguments are saved to the stack in the prolog */
914 switch (ainfo->storage) {
916 if (ainfo->atype == AggregateSingleHFA)
917 offset += ainfo->nslots * 4;
919 offset += ainfo->nslots * 8;
922 offset += sizeof (gpointer);
925 offset = ALIGN_TO (offset, sizeof (gpointer));
926 if (cfg->arch.omit_fp)
927 inst->inst_offset = offset;
929 inst->inst_offset = - offset;
934 if (cfg->arch.omit_fp && offset == 16)
937 cfg->stack_offset = offset;
943 mono_arch_create_vars (MonoCompile *cfg)
945 MonoMethodSignature *sig;
948 sig = mono_method_signature (cfg->method);
950 cinfo = get_call_info (sig, FALSE);
952 if (cinfo->ret.storage == ArgAggregate)
953 cfg->ret_var_is_local = TRUE;
959 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
963 arg->opcode = OP_OUTARG_REG;
964 arg->inst_left = tree;
965 arg->inst_right = (MonoInst*)call;
966 arg->backend.reg3 = reg;
967 call->used_iregs |= 1 << reg;
970 arg->opcode = OP_OUTARG_FREG;
971 arg->inst_left = tree;
972 arg->inst_right = (MonoInst*)call;
973 arg->backend.reg3 = reg;
974 call->used_fregs |= 1 << reg;
977 g_assert_not_reached ();
982 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
985 MonoMethodSignature *tmp_sig;
988 /* FIXME: Add support for signature tokens to AOT */
989 cfg->disable_aot = TRUE;
991 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
994 * mono_ArgIterator_Setup assumes the signature cookie is
995 * passed first and all the arguments which were before it are
996 * passed on the stack after the signature. So compensate by
997 * passing a different signature.
999 tmp_sig = mono_metadata_signature_dup (call->signature);
1000 tmp_sig->param_count -= call->signature->sentinelpos;
1001 tmp_sig->sentinelpos = 0;
1002 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1004 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1005 sig_arg->inst_p0 = tmp_sig;
1007 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1008 arg->inst_left = sig_arg;
1009 arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1010 arg->type = STACK_PTR;
1012 /* prepend, so they get reversed */
1013 arg->next = call->out_args;
1014 call->out_args = arg;
1018 * take the arguments and generate the arch-specific
1019 * instructions to properly call the function in call.
1020 * This includes pushing, moving arguments to the right register
1024 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1027 MonoMethodSignature *sig;
1028 int i, n, stack_size;
1034 mono_ia64_alloc_stacked_registers (cfg);
1036 sig = call->signature;
1037 n = sig->param_count + sig->hasthis;
1039 cinfo = get_call_info (sig, sig->pinvoke);
1041 if (cinfo->ret.storage == ArgAggregate) {
1042 /* The code in emit_this_vret_arg needs a local */
1043 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1044 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1047 for (i = 0; i < n; ++i) {
1048 ainfo = cinfo->args + i;
1050 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1051 /* Emit the signature cookie just before the implicit arguments */
1052 emit_sig_cookie (cfg, call, cinfo);
1055 if (is_virtual && i == 0) {
1056 /* the argument will be attached to the call instruction */
1057 in = call->args [i];
1061 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1062 in = call->args [i];
1063 arg->cil_code = in->cil_code;
1064 arg->inst_left = in;
1065 arg->type = in->type;
1066 /* prepend, so they get reversed */
1067 arg->next = call->out_args;
1068 call->out_args = arg;
1070 if (sig->hasthis && (i == 0))
1071 arg_type = &mono_defaults.object_class->byval_arg;
1073 arg_type = sig->params [i - sig->hasthis];
1075 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1076 MonoInst *stack_addr;
1080 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1081 size = sizeof (MonoTypedRef);
1082 align = sizeof (gpointer);
1086 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1089 * Other backends use mono_type_stack_size (), but that
1090 * aligns the size to 8, which is larger than the size of
1091 * the source, leading to reads of invalid memory if the
1092 * source is at the end of address space.
1094 size = mono_class_value_size (in->klass, &align);
1097 if (ainfo->storage == ArgAggregate) {
1098 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1101 vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1104 * Part of the structure is passed in registers.
1106 for (j = 0; j < ainfo->nregs; ++j) {
1107 int offset, load_op, dest_reg, arg_storage;
1109 slot = ainfo->reg + j;
1111 if (ainfo->atype == AggregateSingleHFA) {
1112 load_op = CEE_LDIND_R4;
1114 dest_reg = ainfo->reg + j;
1115 arg_storage = ArgInFloatReg;
1116 } else if (ainfo->atype == AggregateDoubleHFA) {
1117 load_op = CEE_LDIND_R8;
1119 dest_reg = ainfo->reg + j;
1120 arg_storage = ArgInFloatReg;
1122 load_op = CEE_LDIND_I;
1124 dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1125 arg_storage = ArgInIReg;
1128 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1129 load->ssa_op = MONO_SSA_LOAD;
1130 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1132 NEW_ICONST (cfg, offset_ins, offset);
1133 MONO_INST_NEW (cfg, load2, CEE_ADD);
1134 load2->inst_left = load;
1135 load2->inst_right = offset_ins;
1137 MONO_INST_NEW (cfg, load, load_op);
1138 load->inst_left = load2;
1143 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1144 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1145 if (set_reg != call->out_args) {
1146 set_reg->next = call->out_args;
1147 call->out_args = set_reg;
1152 * Part of the structure is passed on the stack.
1154 for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1157 slot = ainfo->reg + j;
1159 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1160 load->ssa_op = MONO_SSA_LOAD;
1161 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1163 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1164 MONO_INST_NEW (cfg, load2, CEE_ADD);
1165 load2->inst_left = load;
1166 load2->inst_right = offset_ins;
1168 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1169 load->inst_left = load2;
1174 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1175 outarg->inst_left = load;
1176 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1178 if (outarg != call->out_args) {
1179 outarg->next = call->out_args;
1180 call->out_args = outarg;
1184 /* Trees can't be shared so make a copy */
1185 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1186 arg->cil_code = in->cil_code;
1187 arg->ssa_op = MONO_SSA_STORE;
1188 arg->inst_left = vtaddr;
1189 arg->inst_right = in;
1190 arg->type = in->type;
1192 /* prepend, so they get reversed */
1193 arg->next = call->out_args;
1194 call->out_args = arg;
1197 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1198 stack_addr->inst_basereg = IA64_SP;
1199 stack_addr->inst_offset = 16 + ainfo->offset;
1200 stack_addr->inst_imm = size;
1202 arg->opcode = OP_OUTARG_VT;
1203 arg->inst_right = stack_addr;
1207 switch (ainfo->storage) {
1209 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1212 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1215 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1216 arg->opcode = OP_OUTARG_R4;
1219 arg->opcode = OP_OUTARG;
1220 arg->inst_imm = 16 + ainfo->offset;
1223 g_assert_not_reached ();
1229 /* Handle the case where there are no implicit arguments */
1230 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1231 emit_sig_cookie (cfg, call, cinfo);
1234 call->stack_usage = cinfo->stack_usage;
1235 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1236 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1237 cfg->flags |= MONO_CFG_HAS_CALLS;
1245 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1247 MonoInst *ins, *last_ins = NULL;
1251 switch (ins->opcode) {
1259 if (ins->dreg == ins->sreg1) {
1261 last_ins->next = ins->next;
1268 * OP_MOVE sreg, dreg
1269 * OP_MOVE dreg, sreg
1271 if (last_ins && last_ins->opcode == OP_MOVE &&
1272 ins->sreg1 == last_ins->dreg &&
1273 ins->dreg == last_ins->sreg1) {
1274 last_ins->next = ins->next;
1281 /* remove unnecessary multiplication with 1 */
1282 if (ins->inst_imm == 1) {
1283 if (ins->dreg != ins->sreg1) {
1284 ins->opcode = OP_MOVE;
1286 last_ins->next = ins->next;
1297 bb->last_ins = last_ins;
1300 int cond_to_ia64_cmp [][3] = {
1301 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1302 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1303 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1304 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1305 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1306 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1307 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1308 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1309 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1310 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1314 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1316 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1319 int cond_to_ia64_cmp_imm [][3] = {
1320 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1321 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1322 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1323 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1324 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1325 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1326 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1327 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1328 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1329 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1333 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1335 /* The condition needs to be reversed */
1336 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1340 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1344 bb->code = to_insert;
1345 to_insert->next = ins;
1348 to_insert->next = ins->next;
1349 ins->next = to_insert;
1353 #define NEW_INS(cfg,dest,op) do { \
1354 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1355 (dest)->opcode = (op); \
1356 insert_after_ins (bb, last_ins, (dest)); \
1357 last_ins = (dest); \
1361 * mono_arch_lowering_pass:
1363 * Converts complex opcodes into simpler ones so that each IR instruction
1364 * corresponds to one machine instruction.
1367 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1369 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1372 if (bb->max_vreg > cfg->rs->next_vreg)
1373 cfg->rs->next_vreg = bb->max_vreg;
1376 switch (ins->opcode) {
1377 case OP_STOREI1_MEMBASE_IMM:
1378 case OP_STOREI2_MEMBASE_IMM:
1379 case OP_STOREI4_MEMBASE_IMM:
1380 case OP_STOREI8_MEMBASE_IMM:
1381 case OP_STORE_MEMBASE_IMM:
1382 /* There are no store_membase instructions on ia64 */
1383 if (ins->inst_offset == 0) {
1385 } else if (ia64_is_imm14 (ins->inst_offset)) {
1386 NEW_INS (cfg, temp2, OP_ADD_IMM);
1387 temp2->sreg1 = ins->inst_destbasereg;
1388 temp2->inst_imm = ins->inst_offset;
1389 temp2->dreg = mono_regstate_next_int (cfg->rs);
1392 NEW_INS (cfg, temp, OP_I8CONST);
1393 temp->inst_c0 = ins->inst_offset;
1394 temp->dreg = mono_regstate_next_int (cfg->rs);
1395 NEW_INS (cfg, temp2, CEE_ADD);
1396 temp2->sreg1 = ins->inst_destbasereg;
1397 temp2->sreg2 = temp->dreg;
1398 temp2->dreg = mono_regstate_next_int (cfg->rs);
1401 switch (ins->opcode) {
1402 case OP_STOREI1_MEMBASE_IMM:
1403 ins->opcode = OP_STOREI1_MEMBASE_REG;
1405 case OP_STOREI2_MEMBASE_IMM:
1406 ins->opcode = OP_STOREI2_MEMBASE_REG;
1408 case OP_STOREI4_MEMBASE_IMM:
1409 ins->opcode = OP_STOREI4_MEMBASE_REG;
1411 case OP_STOREI8_MEMBASE_IMM:
1412 case OP_STORE_MEMBASE_IMM:
1413 ins->opcode = OP_STOREI8_MEMBASE_REG;
1416 g_assert_not_reached ();
1419 if (ins->inst_imm == 0)
1420 ins->sreg1 = IA64_R0;
1422 NEW_INS (cfg, temp3, OP_I8CONST);
1423 temp3->inst_c0 = ins->inst_imm;
1424 temp3->dreg = mono_regstate_next_int (cfg->rs);
1425 ins->sreg1 = temp3->dreg;
1428 ins->inst_offset = 0;
1430 ins->inst_destbasereg = temp2->dreg;
1432 case OP_STOREI1_MEMBASE_REG:
1433 case OP_STOREI2_MEMBASE_REG:
1434 case OP_STOREI4_MEMBASE_REG:
1435 case OP_STOREI8_MEMBASE_REG:
1436 case OP_STORER4_MEMBASE_REG:
1437 case OP_STORER8_MEMBASE_REG:
1438 case OP_STORE_MEMBASE_REG:
1439 /* There are no store_membase instructions on ia64 */
1440 if (ins->inst_offset == 0) {
1443 else if (ia64_is_imm14 (ins->inst_offset)) {
1444 NEW_INS (cfg, temp2, OP_ADD_IMM);
1445 temp2->sreg1 = ins->inst_destbasereg;
1446 temp2->inst_imm = ins->inst_offset;
1447 temp2->dreg = mono_regstate_next_int (cfg->rs);
1450 NEW_INS (cfg, temp, OP_I8CONST);
1451 temp->inst_c0 = ins->inst_offset;
1452 temp->dreg = mono_regstate_next_int (cfg->rs);
1453 NEW_INS (cfg, temp2, CEE_ADD);
1454 temp2->sreg1 = ins->inst_destbasereg;
1455 temp2->sreg2 = temp->dreg;
1456 temp2->dreg = mono_regstate_next_int (cfg->rs);
1459 ins->inst_offset = 0;
1460 ins->inst_destbasereg = temp2->dreg;
1462 case OP_LOADI1_MEMBASE:
1463 case OP_LOADU1_MEMBASE:
1464 case OP_LOADI2_MEMBASE:
1465 case OP_LOADU2_MEMBASE:
1466 case OP_LOADI4_MEMBASE:
1467 case OP_LOADU4_MEMBASE:
1468 case OP_LOADI8_MEMBASE:
1469 case OP_LOAD_MEMBASE:
1470 case OP_LOADR4_MEMBASE:
1471 case OP_LOADR8_MEMBASE:
1472 case OP_ATOMIC_EXCHANGE_I4:
1473 case OP_ATOMIC_EXCHANGE_I8:
1474 case OP_ATOMIC_ADD_NEW_I4:
1475 case OP_ATOMIC_ADD_NEW_I8:
1476 case OP_ATOMIC_ADD_IMM_NEW_I4:
1477 case OP_ATOMIC_ADD_IMM_NEW_I8:
1478 /* There are no membase instructions on ia64 */
1479 if (ins->inst_offset == 0) {
1482 else if (ia64_is_imm14 (ins->inst_offset)) {
1483 NEW_INS (cfg, temp2, OP_ADD_IMM);
1484 temp2->sreg1 = ins->inst_basereg;
1485 temp2->inst_imm = ins->inst_offset;
1486 temp2->dreg = mono_regstate_next_int (cfg->rs);
1489 NEW_INS (cfg, temp, OP_I8CONST);
1490 temp->inst_c0 = ins->inst_offset;
1491 temp->dreg = mono_regstate_next_int (cfg->rs);
1492 NEW_INS (cfg, temp2, CEE_ADD);
1493 temp2->sreg1 = ins->inst_basereg;
1494 temp2->sreg2 = temp->dreg;
1495 temp2->dreg = mono_regstate_next_int (cfg->rs);
1498 ins->inst_offset = 0;
1499 ins->inst_basereg = temp2->dreg;
1514 case OP_ISHR_UN_IMM:
1515 case OP_LSHR_UN_IMM: {
1516 gboolean is_imm = FALSE;
1517 gboolean switched = FALSE;
1519 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1520 ins->opcode = OP_ZEXT_I1;
1524 switch (ins->opcode) {
1527 is_imm = ia64_is_imm14 (ins->inst_imm);
1531 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1533 /* A = B - IMM -> A = B + (-IMM) */
1534 ins->inst_imm = - ins->inst_imm;
1535 ins->opcode = OP_IADD_IMM;
1543 is_imm = ia64_is_imm8 (ins->inst_imm);
1552 case OP_ISHR_UN_IMM:
1553 case OP_LSHR_UN_IMM:
1554 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1562 ins->sreg2 = ins->sreg1;
1566 switch (ins->opcode) {
1568 ins->opcode = CEE_ADD;
1571 ins->opcode = OP_IADD;
1574 ins->opcode = OP_ISUB;
1577 ins->opcode = OP_IAND;
1580 ins->opcode = OP_IOR;
1583 ins->opcode = OP_IXOR;
1586 ins->opcode = OP_ISHL;
1589 ins->opcode = OP_ISHR;
1591 case OP_ISHR_UN_IMM:
1592 ins->opcode = OP_ISHR_UN;
1595 ins->opcode = CEE_AND;
1598 ins->opcode = OP_LSHL;
1601 ins->opcode = OP_LSHR;
1604 ins->opcode = OP_LSHL;
1607 ins->opcode = OP_LSHR;
1609 case OP_LSHR_UN_IMM:
1610 ins->opcode = OP_LSHR_UN;
1613 g_assert_not_reached ();
1616 if (ins->inst_imm == 0)
1617 ins->sreg2 = IA64_R0;
1619 NEW_INS (cfg, temp, OP_I8CONST);
1620 temp->inst_c0 = ins->inst_imm;
1621 temp->dreg = mono_regstate_next_int (cfg->rs);
1622 ins->sreg2 = temp->dreg;
1626 case OP_COMPARE_IMM:
1627 case OP_ICOMPARE_IMM: {
1628 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1633 * The compare_imm instructions have switched up arguments, and
1634 * some of them take an imm between -127 and 128.
1637 cond = mono_opcode_to_cond (next->opcode);
1638 if ((cond == CMP_LT) || (cond == CMP_GE))
1639 imm = ia64_is_imm8 (ins->inst_imm - 1);
1640 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1641 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1643 imm = ia64_is_imm8 (ins->inst_imm);
1646 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1647 ins->sreg2 = ins->sreg1;
1650 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1652 if (ins->inst_imm == 0)
1653 ins->sreg2 = IA64_R0;
1655 NEW_INS (cfg, temp, OP_I8CONST);
1656 temp->inst_c0 = ins->inst_imm;
1657 temp->dreg = mono_regstate_next_int (cfg->rs);
1658 ins->sreg2 = temp->dreg;
1662 switch (next->opcode) {
1683 next->opcode = OP_IA64_BR_COND;
1684 if (! (next->flags & MONO_INST_BRLABEL))
1685 next->inst_target_bb = next->inst_true_bb;
1687 case OP_COND_EXC_EQ:
1688 case OP_COND_EXC_GT:
1689 case OP_COND_EXC_LT:
1690 case OP_COND_EXC_GT_UN:
1691 case OP_COND_EXC_LE_UN:
1692 case OP_COND_EXC_NE_UN:
1693 case OP_COND_EXC_LT_UN:
1694 next->opcode = OP_IA64_COND_EXC;
1706 next->opcode = OP_IA64_CSET;
1709 printf ("%s\n", mono_inst_name (next->opcode));
1719 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1723 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1724 switch (next->opcode) {
1755 next->opcode = OP_IA64_BR_COND;
1756 if (! (next->flags & MONO_INST_BRLABEL))
1757 next->inst_target_bb = next->inst_true_bb;
1759 case OP_COND_EXC_LT:
1760 case OP_COND_EXC_GT:
1761 case OP_COND_EXC_GT_UN:
1762 case OP_COND_EXC_LE_UN:
1763 next->opcode = OP_IA64_COND_EXC;
1780 next->opcode = OP_IA64_CSET;
1783 printf ("%s\n", mono_inst_name (next->opcode));
1792 gboolean found = FALSE;
1793 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1795 /* First the easy cases */
1796 if (ins->inst_imm == 1) {
1797 ins->opcode = OP_MOVE;
1800 for (i = 1; i < 64; ++i)
1801 if (ins->inst_imm == (((gint64)1) << i)) {
1802 ins->opcode = shl_op;
1808 /* This could be optimized */
1811 for (i = 0; i < 64; ++i) {
1812 if (ins->inst_imm & (((gint64)1) << i)) {
1813 NEW_INS (cfg, temp, shl_op);
1814 temp->dreg = mono_regstate_next_int (cfg->rs);
1815 temp->sreg1 = ins->sreg1;
1819 sum_reg = temp->dreg;
1821 NEW_INS (cfg, temp2, CEE_ADD);
1822 temp2->dreg = mono_regstate_next_int (cfg->rs);
1823 temp2->sreg1 = sum_reg;
1824 temp2->sreg2 = temp->dreg;
1825 sum_reg = temp2->dreg;
1829 ins->opcode = OP_MOVE;
1830 ins->sreg1 = sum_reg;
1834 case CEE_CONV_OVF_U4:
1835 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1836 temp->sreg1 = ins->sreg1;
1837 temp->sreg2 = IA64_R0;
1839 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1840 temp->inst_p1 = (char*)"OverflowException";
1842 ins->opcode = OP_MOVE;
1844 case CEE_CONV_OVF_I4_UN:
1845 NEW_INS (cfg, temp, OP_ICONST);
1846 temp->inst_c0 = 0x7fffffff;
1847 temp->dreg = mono_regstate_next_int (cfg->rs);
1849 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1850 temp2->sreg1 = ins->sreg1;
1851 temp2->sreg2 = temp->dreg;
1853 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1854 temp->inst_p1 = (char*)"OverflowException";
1856 ins->opcode = OP_MOVE;
1858 case OP_FCONV_TO_I4:
1859 case OP_FCONV_TO_I2:
1860 case OP_FCONV_TO_U2:
1861 case OP_FCONV_TO_I1:
1862 case OP_FCONV_TO_U1:
1863 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1864 temp->sreg1 = ins->sreg1;
1865 temp->dreg = ins->dreg;
1867 switch (ins->opcode) {
1868 case OP_FCONV_TO_I4:
1869 ins->opcode = OP_SEXT_I4;
1871 case OP_FCONV_TO_I2:
1872 ins->opcode = OP_SEXT_I2;
1874 case OP_FCONV_TO_U2:
1875 ins->opcode = OP_ZEXT_I4;
1877 case OP_FCONV_TO_I1:
1878 ins->opcode = OP_SEXT_I1;
1880 case OP_FCONV_TO_U1:
1881 ins->opcode = OP_ZEXT_I1;
1884 g_assert_not_reached ();
1886 ins->sreg1 = ins->dreg;
1894 bb->last_ins = last_ins;
1896 bb->max_vreg = cfg->rs->next_vreg;
1900 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1905 mono_arch_lowering_pass (cfg, bb);
1907 mono_local_regalloc (cfg, bb);
1911 * emit_load_volatile_arguments:
1913 * Load volatile arguments from the stack to the original input registers.
1914 * Required before a tail call.
1916 static Ia64CodegenState
1917 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1919 MonoMethod *method = cfg->method;
1920 MonoMethodSignature *sig;
1925 /* FIXME: Generate intermediate code instead */
1927 sig = mono_method_signature (method);
1929 cinfo = get_call_info (sig, FALSE);
1931 /* This is the opposite of the code in emit_prolog */
1932 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1933 ArgInfo *ainfo = cinfo->args + i;
1934 gint32 stack_offset;
1936 ins = cfg->args [i];
1938 if (sig->hasthis && (i == 0))
1939 arg_type = &mono_defaults.object_class->byval_arg;
1941 arg_type = sig->params [i - sig->hasthis];
1943 arg_type = mono_type_get_underlying_type (arg_type);
1945 stack_offset = ainfo->offset + ARGS_OFFSET;
1947 /* Save volatile arguments to the stack */
1948 if (ins->opcode != OP_REGVAR) {
1949 switch (ainfo->storage) {
1952 /* FIXME: big offsets */
1953 g_assert (ins->opcode == OP_REGOFFSET);
1954 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1955 if (arg_type->byref)
1956 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1958 switch (arg_type->type) {
1960 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1963 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1966 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1978 if (ins->opcode == OP_REGVAR) {
1979 /* Argument allocated to (non-volatile) register */
1980 switch (ainfo->storage) {
1982 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1983 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1986 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1987 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
2000 static Ia64CodegenState
2001 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2006 /* Move return value to the target register */
2007 switch (ins->opcode) {
2009 case OP_VOIDCALL_REG:
2010 case OP_VOIDCALL_MEMBASE:
2014 case OP_CALL_MEMBASE:
2017 case OP_LCALL_MEMBASE:
2018 g_assert (ins->dreg == IA64_R8);
2022 case OP_FCALL_MEMBASE:
2023 g_assert (ins->dreg == 8);
2027 case OP_VCALL_MEMBASE: {
2030 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
2031 storage = cinfo->ret.storage;
2033 if (storage == ArgAggregate) {
2034 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2036 /* Load address of stack space allocated for the return value */
2037 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2038 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2039 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2041 for (i = 0; i < cinfo->ret.nregs; ++i) {
2042 switch (cinfo->ret.atype) {
2043 case AggregateNormal:
2044 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2046 case AggregateSingleHFA:
2047 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2049 case AggregateDoubleHFA:
2050 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2053 g_assert_not_reached ();
2061 g_assert_not_reached ();
2067 #define add_patch_info(cfg,code,patch_type,data) do { \
2068 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2071 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2072 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2074 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2076 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2077 ia64_br_cond_pred (code, (predicate), 0); \
2080 static Ia64CodegenState
2081 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2083 add_patch_info (cfg, code, patch_type, data);
2085 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2087 /* mono_arch_patch_callsite will patch this */
2088 /* mono_arch_nullify_class_init_trampoline will patch this */
2089 ia64_movl (code, GP_SCRATCH_REG, 0);
2090 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2091 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2092 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2093 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2096 /* Can't use a direct call since the displacement might be too small */
2097 /* mono_arch_patch_callsite will patch this */
2098 ia64_movl (code, GP_SCRATCH_REG, 0);
2099 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2100 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2106 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2109 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2114 Ia64CodegenState code;
2115 guint8 *code_start = cfg->native_code + cfg->code_len;
2116 MonoInst *last_ins = NULL;
2117 guint last_offset = 0;
2120 if (cfg->opt & MONO_OPT_PEEPHOLE)
2121 peephole_pass (cfg, bb);
2123 if (cfg->opt & MONO_OPT_LOOP) {
2127 if (cfg->verbose_level > 2)
2128 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2130 cpos = bb->max_offset;
2132 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2136 offset = code_start - cfg->native_code;
2138 ia64_codegen_init (code, code_start);
2141 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2147 offset = code.buf - cfg->native_code;
2149 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2151 while (offset + max_len + 16 > cfg->code_size) {
2152 ia64_codegen_close (code);
2154 offset = code.buf - cfg->native_code;
2156 cfg->code_size *= 2;
2157 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2158 code_start = cfg->native_code + offset;
2159 mono_jit_stats.code_reallocs++;
2161 ia64_codegen_init (code, code_start);
2164 mono_debug_record_line_number (cfg, ins, offset);
2166 switch (ins->opcode) {
2169 if (ia64_is_imm14 (ins->inst_c0))
2170 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2172 ia64_movl (code, ins->dreg, ins->inst_c0);
2175 ia64_mov (code, ins->dreg, ins->sreg1);
2178 case OP_IA64_BR_COND: {
2180 if (ins->opcode == OP_IA64_BR_COND)
2182 if (ins->flags & MONO_INST_BRLABEL) {
2183 if (ins->inst_i0->inst_c0) {
2186 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2187 ia64_br_cond_pred (code, pred, 0);
2190 if (ins->inst_target_bb->native_offset) {
2191 guint8 *pos = code.buf + code.nins;
2193 ia64_br_cond_pred (code, pred, 0);
2194 ia64_begin_bundle (code);
2195 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2197 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2198 ia64_br_cond_pred (code, pred, 0);
2204 ia64_begin_bundle (code);
2205 ins->inst_c0 = code.buf - cfg->native_code;
2210 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2211 ia64_br_cond_reg (code, IA64_B6);
2215 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2219 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2223 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2227 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2231 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2235 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2238 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2242 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2245 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2246 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2250 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2253 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2257 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2260 /* p6 and p7 is set if there is signed/unsigned overflow */
2262 /* Set p8-p9 == (sreg2 > 0) */
2263 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2265 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2267 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2268 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2269 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2270 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2272 /* res <u sreg1 => unsigned overflow */
2273 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2275 /* FIXME: Predicate this since this is a side effect */
2276 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2279 /* p6 and p7 is set if there is signed/unsigned overflow */
2281 /* Set p8-p9 == (sreg2 > 0) */
2282 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2284 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2286 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2287 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2288 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2289 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2291 /* sreg1 <u sreg2 => unsigned overflow */
2292 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2294 /* FIXME: Predicate this since this is a side effect */
2295 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2298 /* Same as OP_IADDCC */
2299 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2301 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2303 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2304 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2306 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2308 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2311 /* Same as OP_ISUBCC */
2313 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2315 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2317 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2318 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2320 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2322 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2326 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2330 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2333 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2336 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2341 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2346 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2348 case OP_ISHR_UN_IMM:
2349 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2350 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2352 case OP_LSHR_UN_IMM:
2353 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2356 /* Based on gcc code */
2357 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2358 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2359 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2360 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2363 case OP_STOREI1_MEMBASE_REG:
2364 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2366 case OP_STOREI2_MEMBASE_REG:
2367 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2369 case OP_STOREI4_MEMBASE_REG:
2370 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2372 case OP_STOREI8_MEMBASE_REG:
2373 case OP_STORE_MEMBASE_REG:
2374 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2377 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2378 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2380 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2381 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2383 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2384 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2386 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2387 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2390 case OP_LOADU1_MEMBASE:
2391 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2393 case OP_LOADU2_MEMBASE:
2394 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2396 case OP_LOADU4_MEMBASE:
2397 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2399 case OP_LOADI1_MEMBASE:
2400 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2401 ia64_sxt1 (code, ins->dreg, ins->dreg);
2403 case OP_LOADI2_MEMBASE:
2404 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2405 ia64_sxt2 (code, ins->dreg, ins->dreg);
2407 case OP_LOADI4_MEMBASE:
2408 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2409 ia64_sxt4 (code, ins->dreg, ins->dreg);
2411 case OP_LOAD_MEMBASE:
2412 case OP_LOADI8_MEMBASE:
2413 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2416 case OP_IA64_LOADU1_MEMBASE_INC:
2417 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2419 case OP_IA64_LOADU2_MEMBASE_INC:
2420 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2422 case OP_IA64_LOADU4_MEMBASE_INC:
2423 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2425 case OP_IA64_LOADI8_MEMBASE_INC:
2426 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2430 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2433 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2436 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2439 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2442 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2445 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2448 /* Compare opcodes */
2449 case OP_IA64_CMP4_EQ:
2450 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2452 case OP_IA64_CMP4_NE:
2453 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2455 case OP_IA64_CMP4_LE:
2456 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2458 case OP_IA64_CMP4_LT:
2459 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2461 case OP_IA64_CMP4_GE:
2462 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2464 case OP_IA64_CMP4_GT:
2465 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2467 case OP_IA64_CMP4_LT_UN:
2468 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2470 case OP_IA64_CMP4_LE_UN:
2471 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2473 case OP_IA64_CMP4_GT_UN:
2474 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2476 case OP_IA64_CMP4_GE_UN:
2477 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2479 case OP_IA64_CMP_EQ:
2480 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2482 case OP_IA64_CMP_NE:
2483 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2485 case OP_IA64_CMP_LE:
2486 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2488 case OP_IA64_CMP_LT:
2489 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2491 case OP_IA64_CMP_GE:
2492 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2494 case OP_IA64_CMP_GT:
2495 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2497 case OP_IA64_CMP_GT_UN:
2498 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2500 case OP_IA64_CMP_LT_UN:
2501 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2503 case OP_IA64_CMP_GE_UN:
2504 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2506 case OP_IA64_CMP_LE_UN:
2507 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2509 case OP_IA64_CMP4_EQ_IMM:
2510 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2512 case OP_IA64_CMP4_NE_IMM:
2513 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2515 case OP_IA64_CMP4_LE_IMM:
2516 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2518 case OP_IA64_CMP4_LT_IMM:
2519 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2521 case OP_IA64_CMP4_GE_IMM:
2522 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2524 case OP_IA64_CMP4_GT_IMM:
2525 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2527 case OP_IA64_CMP4_LT_UN_IMM:
2528 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2530 case OP_IA64_CMP4_LE_UN_IMM:
2531 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2533 case OP_IA64_CMP4_GT_UN_IMM:
2534 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2536 case OP_IA64_CMP4_GE_UN_IMM:
2537 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2539 case OP_IA64_CMP_EQ_IMM:
2540 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2542 case OP_IA64_CMP_NE_IMM:
2543 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2545 case OP_IA64_CMP_LE_IMM:
2546 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2548 case OP_IA64_CMP_LT_IMM:
2549 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2551 case OP_IA64_CMP_GE_IMM:
2552 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2554 case OP_IA64_CMP_GT_IMM:
2555 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2557 case OP_IA64_CMP_GT_UN_IMM:
2558 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2560 case OP_IA64_CMP_LT_UN_IMM:
2561 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2563 case OP_IA64_CMP_GE_UN_IMM:
2564 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2566 case OP_IA64_CMP_LE_UN_IMM:
2567 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2569 case OP_IA64_FCMP_EQ:
2570 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2572 case OP_IA64_FCMP_NE:
2573 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2575 case OP_IA64_FCMP_LT:
2576 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2578 case OP_IA64_FCMP_GT:
2579 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2581 case OP_IA64_FCMP_LE:
2582 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2584 case OP_IA64_FCMP_GE:
2585 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2587 case OP_IA64_FCMP_GT_UN:
2588 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2589 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2591 case OP_IA64_FCMP_LT_UN:
2592 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2593 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2595 case OP_IA64_FCMP_GE_UN:
2596 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2597 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2599 case OP_IA64_FCMP_LE_UN:
2600 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2601 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2604 case OP_COND_EXC_IOV:
2605 case OP_COND_EXC_OV:
2606 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2608 case OP_COND_EXC_IC:
2610 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2612 case OP_IA64_COND_EXC:
2613 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2616 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2617 ia64_no_stop (code);
2618 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2621 /* FIXME: Is this needed ? */
2622 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2625 /* FIXME: Is this needed ? */
2626 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2629 /* FIXME: Is this needed ? */
2630 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2633 /* FIXME: Is this needed */
2634 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2637 /* FIXME: Is this needed */
2638 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2641 /* FIXME: Is this needed */
2642 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2646 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2650 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2657 double d = *(double *)ins->inst_p0;
2659 if ((d == 0.0) && (mono_signbit (d) == 0))
2660 ia64_fmov (code, ins->dreg, 0);
2662 ia64_fmov (code, ins->dreg, 1);
2664 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2665 ia64_movl (code, GP_SCRATCH_REG, 0);
2666 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2671 float f = *(float *)ins->inst_p0;
2673 if ((f == 0.0) && (mono_signbit (f) == 0))
2674 ia64_fmov (code, ins->dreg, 0);
2676 ia64_fmov (code, ins->dreg, 1);
2678 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2679 ia64_movl (code, GP_SCRATCH_REG, 0);
2680 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2685 ia64_fmov (code, ins->dreg, ins->sreg1);
2687 case OP_STORER8_MEMBASE_REG:
2688 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2690 case OP_STORER4_MEMBASE_REG:
2691 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2692 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2694 case OP_LOADR8_MEMBASE:
2695 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2697 case OP_LOADR4_MEMBASE:
2698 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2699 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2702 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2703 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2704 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2707 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2708 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2709 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2711 case OP_LCONV_TO_R8:
2712 /* FIXME: Difference with CEE_CONV_R8 ? */
2713 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2714 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2715 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2717 case OP_LCONV_TO_R4:
2718 /* FIXME: Difference with CEE_CONV_R4 ? */
2719 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2720 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2721 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2723 case OP_FCONV_TO_R4:
2724 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2726 case OP_FCONV_TO_I8:
2727 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2728 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2731 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2734 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2737 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2740 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2744 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2745 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2747 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2748 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2749 /* Positive infinity */
2750 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2751 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2752 /* Negative infinity */
2753 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2754 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2759 /* ensure ins->sreg1 is not NULL */
2760 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2763 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2764 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2771 call = (MonoCallInst*)ins;
2773 if (ins->flags & MONO_INST_HAS_METHOD)
2774 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2776 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2778 code = emit_move_return_value (cfg, ins, code);
2785 case OP_VOIDCALL_REG:
2786 call = (MonoCallInst*)ins;
2790 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2793 ia64_mov (code, IA64_R8, ins->sreg1);
2794 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2795 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2796 ia64_ld8 (code, IA64_GP, IA64_R8);
2797 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2799 code = emit_move_return_value (cfg, ins, code);
2802 case OP_FCALL_MEMBASE:
2803 case OP_LCALL_MEMBASE:
2804 case OP_VCALL_MEMBASE:
2805 case OP_VOIDCALL_MEMBASE:
2806 case OP_CALL_MEMBASE:
2808 * There are no membase instructions on ia64, but we can't
2809 * lower this since get_vcall_slot_addr () needs to decode it.
2812 /* Keep this in synch with get_vcall_slot_addr */
2813 if (ia64_is_imm14 (ins->inst_offset))
2814 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2816 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2817 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2820 ia64_begin_bundle (code);
2821 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2823 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2825 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2828 * This nop will tell get_vcall_slot_addr that this is a virtual
2831 ia64_nop_i (code, 0x12345);
2833 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2835 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2837 code = emit_move_return_value (cfg, ins, code);
2841 * Keep in sync with the code in emit_epilog.
2844 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2847 g_assert (!cfg->method->save_lmf);
2849 /* Load arguments into their original registers */
2850 code = emit_load_volatile_arguments (cfg, code);
2852 if (cfg->arch.stack_alloc_size) {
2853 if (cfg->arch.omit_fp) {
2854 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2855 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2857 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2858 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2862 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2864 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2865 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2867 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2868 ia64_movl (code, GP_SCRATCH_REG, 0);
2869 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2870 ia64_br_cond_reg (code, IA64_B6);
2875 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2881 /* FIXME: Sigaltstack support */
2883 /* keep alignment */
2884 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2885 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2886 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2888 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2890 ia64_mov (code, ins->dreg, IA64_SP);
2892 /* An area at sp is reserved by the ABI for parameter passing */
2893 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2894 if (ia64_is_adds_imm (abi_offset))
2895 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2897 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2898 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2901 if (ins->flags & MONO_INST_INIT) {
2903 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2905 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2908 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2909 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2910 ia64_br_cond_pred (code, 8, -2);
2912 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2914 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2920 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2921 ia64_ld8 (code, ins->dreg, ins->dreg);
2924 /* Synchronization */
2925 case OP_MEMORY_BARRIER:
2928 case OP_ATOMIC_ADD_IMM_NEW_I4:
2929 g_assert (ins->inst_offset == 0);
2930 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2931 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2933 case OP_ATOMIC_ADD_IMM_NEW_I8:
2934 g_assert (ins->inst_offset == 0);
2935 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2936 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2938 case OP_ATOMIC_EXCHANGE_I4:
2939 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2940 ia64_sxt4 (code, ins->dreg, ins->dreg);
2942 case OP_ATOMIC_EXCHANGE_I8:
2943 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2945 case OP_ATOMIC_ADD_NEW_I4: {
2946 guint8 *label, *buf;
2948 /* From libatomic_ops */
2951 ia64_begin_bundle (code);
2952 label = code.buf + code.nins;
2953 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2954 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2955 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2956 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2957 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2958 buf = code.buf + code.nins;
2959 ia64_br_cond_pred (code, 7, 0);
2960 ia64_begin_bundle (code);
2961 ia64_patch (buf, label);
2962 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2965 case OP_ATOMIC_ADD_NEW_I8: {
2966 guint8 *label, *buf;
2968 /* From libatomic_ops */
2971 ia64_begin_bundle (code);
2972 label = code.buf + code.nins;
2973 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2974 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2975 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2976 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2977 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2978 buf = code.buf + code.nins;
2979 ia64_br_cond_pred (code, 7, 0);
2980 ia64_begin_bundle (code);
2981 ia64_patch (buf, label);
2982 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2986 /* Exception handling */
2987 case OP_CALL_HANDLER:
2989 * Using a call instruction would mess up the register stack, so
2990 * save the return address to a register and use a
2993 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2994 ia64_mov (code, IA64_R15, IA64_R0);
2995 ia64_mov_from_ip (code, GP_SCRATCH_REG);
2996 /* Add the length of OP_CALL_HANDLER */
2997 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
2998 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2999 ia64_movl (code, GP_SCRATCH_REG2, 0);
3000 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3001 ia64_br_cond_reg (code, IA64_B6);
3002 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3004 case OP_START_HANDLER: {
3006 * We receive the return address in GP_SCRATCH_REG.
3008 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3011 * R15 determines our caller. It is used since it is writable using
3013 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3014 * R15 != 0 means we are called by call_filter ().
3016 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3017 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3019 ia64_br_cond_pred (code, 6, 6);
3022 * Called by call_filter:
3023 * Allocate a new stack frame, and set the fp register from the
3024 * value passed in by the caller.
3025 * We allocate a similar frame as is done by the prolog, so
3026 * if an exception is thrown while executing the filter, the
3027 * unwinder can unwind through the filter frame using the unwind
3028 * info for the prolog.
3030 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);
3031 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3032 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3033 ia64_mov (code, cfg->frame_reg, IA64_R15);
3034 /* Signal to endfilter that we are called by call_filter */
3035 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3037 /* Save the return address */
3038 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3039 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3040 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3045 case OP_ENDFILTER: {
3046 /* FIXME: Return the value in ENDFILTER */
3047 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3049 /* Load the return address */
3050 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3051 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3054 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3055 ia64_br_cond_pred (code, 7, 4);
3057 /* Called by call_filter */
3059 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3060 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3061 ia64_br_ret_reg (code, IA64_B0);
3063 /* Called by CALL_HANDLER */
3064 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3065 ia64_br_cond_reg (code, IA64_B6);
3069 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3070 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3071 (gpointer)"mono_arch_throw_exception");
3074 * This might be the last instruction in the method, so add a dummy
3075 * instruction so the unwinder will work.
3077 ia64_break_i (code, 0);
3080 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3081 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3082 (gpointer)"mono_arch_rethrow_exception");
3084 ia64_break_i (code, 0);
3088 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3089 g_assert_not_reached ();
3092 if ((code.buf - cfg->native_code - offset) > max_len) {
3093 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3094 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3095 g_assert_not_reached ();
3101 last_offset = offset;
3106 ia64_codegen_close (code);
3108 cfg->code_len = code.buf - cfg->native_code;
3112 mono_arch_register_lowlevel_calls (void)
3114 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3117 static Ia64InsType ins_types_in_template [32][3] = {
3118 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3119 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3120 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3121 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3122 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3123 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3126 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3127 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3128 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3129 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3130 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3131 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3132 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3133 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3134 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3135 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3136 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3137 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3140 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3141 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3142 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3143 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3146 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3147 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3152 static gboolean stops_in_template [32][3] = {
3153 { FALSE, FALSE, FALSE },
3154 { FALSE, FALSE, TRUE },
3155 { FALSE, TRUE, FALSE },
3156 { FALSE, TRUE, TRUE },
3157 { FALSE, FALSE, FALSE },
3158 { FALSE, FALSE, TRUE },
3159 { FALSE, FALSE, FALSE },
3160 { FALSE, FALSE, FALSE },
3162 { FALSE, FALSE, FALSE },
3163 { FALSE, FALSE, TRUE },
3164 { TRUE, FALSE, FALSE },
3165 { TRUE, FALSE, TRUE },
3166 { FALSE, FALSE, FALSE },
3167 { FALSE, FALSE, TRUE },
3168 { FALSE, FALSE, FALSE },
3169 { FALSE, FALSE, TRUE },
3171 { FALSE, FALSE, FALSE },
3172 { FALSE, FALSE, TRUE },
3173 { FALSE, FALSE, FALSE },
3174 { FALSE, FALSE, TRUE },
3175 { FALSE, FALSE, FALSE },
3176 { FALSE, FALSE, FALSE },
3177 { FALSE, FALSE, FALSE },
3178 { FALSE, FALSE, TRUE },
3180 { FALSE, FALSE, FALSE },
3181 { FALSE, FALSE, TRUE },
3182 { FALSE, FALSE, FALSE },
3183 { FALSE, FALSE, FALSE },
3184 { FALSE, FALSE, FALSE },
3185 { FALSE, FALSE, TRUE },
3186 { FALSE, FALSE, FALSE },
3187 { FALSE, FALSE, FALSE }
3190 static int last_stop_in_template [32] = {
3191 -1, 2, 1, 2, -1, 2, -1, -1,
3192 -1, 2, 0, 2, -1, 2, -1, 2,
3193 -1, 2, -1, 2, -1, -1, -1, 2,
3194 -1, 2, -1, -1, -1, 2, -1, -1
3197 static guint64 nops_for_ins_types [6] = {
3206 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3213 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3215 #define DEBUG_INS_SCHED(a)
3219 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3221 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3222 guint8 *deps = code->dep_info;
3223 gboolean need_stop, no_stop;
3225 for (i = 0; i < code->nins; ++i)
3229 current_deps_start = 0;
3230 current_ins_start = 0;
3231 deps_start [ins_index] = current_ins_start;
3234 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3235 while (pos < code->dep_info_pos) {
3237 switch (deps [pos]) {
3238 case IA64_END_OF_INS:
3240 current_ins_start = pos + 2;
3241 deps_start [ins_index] = current_ins_start;
3243 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3248 reg = deps [pos + 1];
3250 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3251 for (i = current_deps_start; i < current_ins_start; i += 2)
3252 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3256 reg = code->dep_info [pos + 1];
3258 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3259 for (i = current_deps_start; i < current_ins_start; i += 2)
3260 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3264 reg = deps [pos + 1];
3266 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3267 for (i = current_deps_start; i < current_ins_start; i += 2)
3268 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3271 case IA64_READ_PR_BRANCH:
3272 reg = deps [pos + 1];
3274 /* Writes to prs by non-float instructions are visible to branches */
3275 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3276 for (i = current_deps_start; i < current_ins_start; i += 2)
3277 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3281 reg = code->dep_info [pos + 1];
3283 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3284 for (i = current_deps_start; i < current_ins_start; i += 2)
3285 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3288 case IA64_WRITE_PR_FLOAT:
3289 reg = code->dep_info [pos + 1];
3291 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3292 for (i = current_deps_start; i < current_ins_start; i += 2)
3293 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3297 reg = deps [pos + 1];
3299 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3300 for (i = current_deps_start; i < current_ins_start; i += 2)
3301 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3305 reg = code->dep_info [pos + 1];
3307 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3308 for (i = current_deps_start; i < current_ins_start; i += 2)
3309 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3312 case IA64_READ_BR_BRANCH:
3313 reg = deps [pos + 1];
3315 /* Writes to brs are visible to branches */
3316 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3319 reg = deps [pos + 1];
3321 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3322 for (i = current_deps_start; i < current_ins_start; i += 2)
3323 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3327 reg = code->dep_info [pos + 1];
3329 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3330 for (i = current_deps_start; i < current_ins_start; i += 2)
3331 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3335 reg = deps [pos + 1];
3337 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3338 for (i = current_deps_start; i < current_ins_start; i += 2)
3339 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3343 reg = code->dep_info [pos + 1];
3345 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3346 for (i = current_deps_start; i < current_ins_start; i += 2)
3347 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3352 * Explicitly indicate that a stop is not required. Useful for
3353 * example when two predicated instructions with negated predicates
3354 * write the same registers.
3359 g_assert_not_reached ();
3363 if (need_stop && !no_stop) {
3364 g_assert (ins_index > 0);
3365 stops [ins_index - 1] = 1;
3367 DEBUG_INS_SCHED (printf ("STOP\n"));
3368 current_deps_start = current_ins_start;
3370 /* Skip remaining deps for this instruction */
3371 while (deps [pos] != IA64_END_OF_INS)
3376 if (code->nins > 0) {
3377 /* No dependency info for the last instruction */
3378 stops [code->nins - 1] = 1;
3381 deps_start [code->nins] = code->dep_info_pos;
3385 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3387 int stop_pos, i, deps_to_shift, dep_shift;
3389 g_assert (n <= code->nins);
3391 // if (n > 1) printf ("FOUND: %ld.\n", template);
3393 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3395 stop_pos = last_stop_in_template [template] + 1;
3399 /* Compute the number of 'real' instructions before the stop */
3400 deps_to_shift = stop_pos;
3401 if (stop_pos >= 3 && (nops & (1 << 2)))
3403 if (stop_pos >= 2 && (nops & (1 << 1)))
3405 if (stop_pos >= 1 && (nops & (1 << 0)))
3409 * We have to keep some dependencies whose instructions have been shifted
3410 * out of the buffer. So nullify the end_of_ins markers in the dependency
3413 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3414 if (code->dep_info [i] == IA64_END_OF_INS)
3415 code->dep_info [i] = IA64_NONE;
3417 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3418 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3419 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3421 dep_shift = deps_start [deps_to_shift];
3422 for (i = 0; i < code->nins + 1 - n; ++i)
3423 deps_start [i] = deps_start [n + i] - dep_shift;
3425 /* Determine the exact positions of instructions with unwind ops */
3426 if (code->unw_op_count) {
3428 int curr_ins, curr_ins_pos;
3431 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3432 for (i = 0; i < 3; ++i) {
3433 if (! (nops & (1 << i))) {
3434 ins_pos [curr_ins] = curr_ins_pos + i;
3439 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3440 if (code->unw_ops_pos [i] < n) {
3441 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3442 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3445 if (code->unw_op_pos < code->unw_op_count)
3446 code->unw_op_pos += n;
3449 if (n == code->nins) {
3454 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3455 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3456 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3462 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3464 int i, ins_type, template, nins_to_emit;
3465 int deps_start [16];
3470 * We implement a simple scheduler which tries to put three instructions
3471 * per bundle, then two, then one.
3473 ia64_analyze_deps (code, deps_start, stops);
3475 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3476 /* Find a suitable template */
3477 for (template = 0; template < 32; ++template) {
3478 if (stops_in_template [template][0] != stops [0] ||
3479 stops_in_template [template][1] != stops [1] ||
3480 stops_in_template [template][2] != stops [2])
3484 for (i = 0; i < 3; ++i) {
3485 ins_type = ins_types_in_template [template][i];
3486 switch (code->itypes [i]) {
3487 case IA64_INS_TYPE_A:
3488 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3491 found &= (ins_type == code->itypes [i]);
3497 found = debug_ins_sched ();
3500 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3506 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3507 /* Wait for more instructions */
3510 /* If it didn't work out, try putting two instructions into one bundle */
3511 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3512 /* Try a nop at the end */
3513 for (template = 0; template < 32; ++template) {
3514 if (stops_in_template [template][0] != stops [0] ||
3515 ((stops_in_template [template][1] != stops [1]) &&
3516 (stops_in_template [template][2] != stops [1])))
3520 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3521 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3524 if (!debug_ins_sched ())
3527 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);
3532 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3533 /* Wait for more instructions */
3536 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3537 /* Try a nop in the middle */
3538 for (template = 0; template < 32; ++template) {
3539 if (((stops_in_template [template][0] != stops [0]) &&
3540 (stops_in_template [template][1] != stops [0])) ||
3541 stops_in_template [template][2] != stops [1])
3544 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3545 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3548 if (!debug_ins_sched ())
3551 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);
3556 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3557 /* Try a nop at the beginning */
3558 for (template = 0; template < 32; ++template) {
3559 if ((stops_in_template [template][1] != stops [0]) ||
3560 (stops_in_template [template][2] != stops [1]))
3563 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3564 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3567 if (!debug_ins_sched ())
3570 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);
3575 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3576 /* Wait for more instructions */
3580 nins_to_emit = code->nins;
3584 while (nins_to_emit > 0) {
3585 if (!debug_ins_sched ())
3587 switch (code->itypes [0]) {
3588 case IA64_INS_TYPE_A:
3590 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3592 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3594 case IA64_INS_TYPE_I:
3596 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3598 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3600 case IA64_INS_TYPE_M:
3602 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3604 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3606 case IA64_INS_TYPE_B:
3608 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3610 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3612 case IA64_INS_TYPE_F:
3614 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3616 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3618 case IA64_INS_TYPE_LX:
3619 if (stops [0] || stops [1])
3620 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3622 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3626 g_assert_not_reached ();
3632 unw_dyn_region_info_t*
3633 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3635 unw_dyn_region_info_t *r;
3637 g_assert (code->nins == 0);
3638 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3639 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3640 r->op_count = code->unw_op_count;
3641 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3642 code->unw_op_count = 0;
3643 code->unw_op_pos = 0;
3644 code->region_start = code->buf;
3650 ia64_patch (unsigned char* code, gpointer target)
3653 guint64 instructions [3];
3654 guint8 gen_buf [16];
3655 Ia64CodegenState gen;
3660 * code encodes both the position inside the buffer and code.nins when
3661 * the instruction was emitted.
3663 ins_to_skip = (guint64)code % 16;
3664 code = (unsigned char*)((guint64)code & ~15);
3667 * Search for the first instruction which is 'patchable', skipping
3668 * ins_to_skip instructions.
3673 template = ia64_bundle_template (code);
3674 instructions [0] = ia64_bundle_ins1 (code);
3675 instructions [1] = ia64_bundle_ins2 (code);
3676 instructions [2] = ia64_bundle_ins3 (code);
3678 ia64_codegen_init (gen, gen_buf);
3681 for (i = 0; i < 3; ++i) {
3682 guint64 ins = instructions [i];
3683 int opcode = ia64_ins_opcode (ins);
3685 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3693 switch (ins_types_in_template [template][i]) {
3694 case IA64_INS_TYPE_A:
3695 case IA64_INS_TYPE_M:
3696 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3698 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3699 instructions [i] = gen.instructions [0];
3705 case IA64_INS_TYPE_B:
3706 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3708 gint64 disp = ((guint8*)target - code) >> 4;
3711 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3713 instructions [i] = gen.instructions [0];
3716 else if (opcode == 5) {
3718 gint64 disp = ((guint8*)target - code) >> 4;
3721 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3722 instructions [i] = gen.instructions [0];
3728 case IA64_INS_TYPE_LX:
3732 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3734 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3735 instructions [1] = gen.instructions [0];
3736 instructions [2] = gen.instructions [1];
3749 ia64_codegen_init (gen, code);
3750 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3760 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3762 MonoJumpInfo *patch_info;
3764 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3765 unsigned char *ip = patch_info->ip.i + code;
3766 const unsigned char *target;
3768 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3770 if (patch_info->type == MONO_PATCH_INFO_NONE)
3772 if (mono_compile_aot) {
3776 ia64_patch (ip, (gpointer)target);
3781 mono_arch_emit_prolog (MonoCompile *cfg)
3783 MonoMethod *method = cfg->method;
3784 MonoMethodSignature *sig;
3786 int alloc_size, pos, i;
3787 Ia64CodegenState code;
3790 sig = mono_method_signature (method);
3793 cinfo = get_call_info (sig, FALSE);
3795 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3797 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3798 cfg->code_size += 1024;
3799 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3800 cfg->code_size += 1024;
3802 cfg->native_code = g_malloc (cfg->code_size);
3804 ia64_codegen_init (code, cfg->native_code);
3806 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3807 if (cfg->param_area)
3808 alloc_size += cfg->param_area;
3812 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3814 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3815 /* Force sp to be saved/restored */
3816 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3818 cfg->arch.stack_alloc_size = alloc_size;
3822 if (method->save_lmf) {
3823 /* No LMF on IA64 */
3828 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3829 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);
3830 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3831 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3833 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3834 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3835 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3836 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3837 ia64_mov (code, cfg->frame_reg, IA64_SP);
3841 int pagesize = getpagesize ();
3843 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3844 if (alloc_size >= pagesize) {
3845 gint32 remaining_size = alloc_size;
3847 /* Generate stack touching code */
3848 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3849 while (remaining_size >= pagesize) {
3850 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3851 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3852 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3853 remaining_size -= pagesize;
3857 if (ia64_is_imm14 (-alloc_size)) {
3858 if (cfg->arch.omit_fp)
3859 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3860 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3863 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3864 if (cfg->arch.omit_fp)
3865 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3866 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3870 ia64_begin_bundle (code);
3872 /* Initialize unwind info */
3873 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3875 if (sig->ret->type != MONO_TYPE_VOID) {
3876 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3877 /* Save volatile arguments to the stack */
3882 /* Keep this in sync with emit_load_volatile_arguments */
3883 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3884 ArgInfo *ainfo = cinfo->args + i;
3885 gint32 stack_offset;
3887 inst = cfg->args [i];
3889 if (sig->hasthis && (i == 0))
3890 arg_type = &mono_defaults.object_class->byval_arg;
3892 arg_type = sig->params [i - sig->hasthis];
3894 arg_type = mono_type_get_underlying_type (arg_type);
3896 stack_offset = ainfo->offset + ARGS_OFFSET;
3898 /* Save volatile arguments to the stack */
3899 if (inst->opcode != OP_REGVAR) {
3900 switch (ainfo->storage) {
3903 g_assert (inst->opcode == OP_REGOFFSET);
3904 if (ia64_is_adds_imm (inst->inst_offset))
3905 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3907 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3908 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3910 if (arg_type->byref)
3911 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3913 switch (arg_type->type) {
3915 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3918 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3921 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3929 if (ainfo->nslots != ainfo->nregs)
3932 g_assert (inst->opcode == OP_REGOFFSET);
3933 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3934 for (i = 0; i < ainfo->nregs; ++i) {
3935 switch (ainfo->atype) {
3936 case AggregateNormal:
3937 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3939 case AggregateSingleHFA:
3940 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3942 case AggregateDoubleHFA:
3943 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3951 g_assert_not_reached ();
3955 if (inst->opcode == OP_REGVAR) {
3956 /* Argument allocated to (non-volatile) register */
3957 switch (ainfo->storage) {
3959 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3960 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3963 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3964 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3972 if (method->save_lmf) {
3973 /* No LMF on IA64 */
3976 ia64_codegen_close (code);
3980 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3981 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
3983 cfg->code_len = code.buf - cfg->native_code;
3985 g_assert (cfg->code_len < cfg->code_size);
3987 cfg->arch.prolog_end_offset = cfg->code_len;
3993 mono_arch_emit_epilog (MonoCompile *cfg)
3995 MonoMethod *method = cfg->method;
3997 int max_epilog_size = 16 * 4;
3998 Ia64CodegenState code;
4003 if (mono_jit_trace_calls != NULL)
4004 max_epilog_size += 1024;
4006 cfg->arch.epilog_begin_offset = cfg->code_len;
4008 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4009 cfg->code_size *= 2;
4010 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4011 mono_jit_stats.code_reallocs++;
4014 /* FIXME: Emit unwind info */
4016 buf = cfg->native_code + cfg->code_len;
4018 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4019 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4021 ia64_codegen_init (code, buf);
4023 /* the code restoring the registers must be kept in sync with OP_JMP */
4026 if (method->save_lmf) {
4027 /* No LMF on IA64 */
4030 /* Load returned vtypes into registers if needed */
4031 cinfo = get_call_info (mono_method_signature (method), FALSE);
4032 ainfo = &cinfo->ret;
4033 switch (ainfo->storage) {
4035 if (ainfo->nslots != ainfo->nregs)
4038 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4039 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4040 for (i = 0; i < ainfo->nregs; ++i) {
4041 switch (ainfo->atype) {
4042 case AggregateNormal:
4043 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4045 case AggregateSingleHFA:
4046 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4048 case AggregateDoubleHFA:
4049 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4052 g_assert_not_reached ();
4061 ia64_begin_bundle (code);
4063 code.region_start = cfg->native_code;
4065 /* Label the unwind state at the start of the exception throwing region */
4066 //ia64_unw_label_state (code, 1234);
4068 if (cfg->arch.stack_alloc_size) {
4069 if (cfg->arch.omit_fp) {
4070 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4071 ia64_unw_pop_frames (code, 1);
4072 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4074 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4075 ia64_unw_pop_frames (code, 1);
4076 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4080 ia64_unw_pop_frames (code, 1);
4081 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4084 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4085 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4086 ia64_br_ret_reg (code, IA64_B0);
4088 ia64_codegen_close (code);
4090 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4091 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4093 cfg->code_len = code.buf - cfg->native_code;
4095 g_assert (cfg->code_len < cfg->code_size);
4099 mono_arch_emit_exceptions (MonoCompile *cfg)
4101 MonoJumpInfo *patch_info;
4103 Ia64CodegenState code;
4104 gboolean empty = TRUE;
4105 //unw_dyn_region_info_t *r_exceptions;
4106 MonoClass *exc_classes [16];
4107 guint8 *exc_throw_start [16], *exc_throw_end [16];
4108 guint32 code_size = 0;
4110 /* Compute needed space */
4111 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4112 if (patch_info->type == MONO_PATCH_INFO_EXC)
4114 if (patch_info->type == MONO_PATCH_INFO_R8)
4115 code_size += 8 + 7; /* sizeof (double) + alignment */
4116 if (patch_info->type == MONO_PATCH_INFO_R4)
4117 code_size += 4 + 7; /* sizeof (float) + alignment */
4123 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4124 cfg->code_size *= 2;
4125 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4126 mono_jit_stats.code_reallocs++;
4129 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4131 /* The unwind state here is the same as before the epilog */
4132 //ia64_unw_copy_state (code, 1234);
4134 /* add code to raise exceptions */
4135 /* FIXME: Optimize this */
4137 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4138 switch (patch_info->type) {
4139 case MONO_PATCH_INFO_EXC: {
4140 MonoClass *exc_class;
4143 guint64 exc_token_index;
4145 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4146 g_assert (exc_class);
4147 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4148 throw_ip = cfg->native_code + patch_info->ip.i;
4150 ia64_begin_bundle (code);
4152 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4154 /* Find a throw sequence for the same exception class */
4155 for (i = 0; i < nthrows; ++i)
4156 if (exc_classes [i] == exc_class)
4160 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4162 if (ia64_is_adds_imm (offset))
4163 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4165 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4167 buf = code.buf + code.nins;
4168 ia64_br_cond_pred (code, 0, 0);
4169 ia64_begin_bundle (code);
4170 ia64_patch (buf, exc_throw_start [i]);
4172 patch_info->type = MONO_PATCH_INFO_NONE;
4177 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4179 ia64_begin_bundle (code);
4182 exc_classes [nthrows] = exc_class;
4183 exc_throw_start [nthrows] = code.buf;
4187 if (ia64_is_adds_imm (exc_token_index))
4188 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4190 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4192 patch_info->data.name = "mono_arch_throw_corlib_exception";
4193 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4194 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4197 ia64_movl (code, GP_SCRATCH_REG, 0);
4198 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4199 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4200 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4202 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4204 /* Patch up the throw offset */
4205 ia64_begin_bundle (code);
4207 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4210 exc_throw_end [nthrows] = code.buf;
4224 /* The unwinder needs this to work */
4225 ia64_break_i (code, 0);
4227 ia64_codegen_close (code);
4230 //r_exceptions = mono_ia64_create_unwind_region (&code);
4231 //cfg->arch.r_epilog = r_exceptions;
4233 cfg->code_len = code.buf - cfg->native_code;
4235 g_assert (cfg->code_len < cfg->code_size);
4239 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4241 Ia64CodegenState code;
4242 CallInfo *cinfo = NULL;
4243 MonoMethodSignature *sig;
4245 int i, n, stack_area = 0;
4247 ia64_codegen_init (code, p);
4249 /* Keep this in sync with mono_arch_get_argument_info */
4251 if (enable_arguments) {
4252 /* Allocate a new area on the stack and save arguments there */
4253 sig = mono_method_signature (cfg->method);
4255 cinfo = get_call_info (sig, FALSE);
4257 n = sig->param_count + sig->hasthis;
4259 stack_area = ALIGN_TO (n * 8, 16);
4262 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4264 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4266 /* FIXME: Allocate out registers */
4268 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4270 /* Required by the ABI */
4271 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4273 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4274 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4276 /* Save arguments to the stack */
4277 for (i = 0; i < n; ++i) {
4278 ins = cfg->args [i];
4280 if (ins->opcode == OP_REGVAR) {
4281 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4282 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4283 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4286 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4287 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4288 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4289 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4290 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4291 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4296 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4299 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4301 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4302 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4304 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4306 if (enable_arguments && stack_area) {
4307 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4309 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4311 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4316 ia64_codegen_close (code);
4322 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4324 Ia64CodegenState code;
4325 CallInfo *cinfo = NULL;
4326 MonoMethod *method = cfg->method;
4327 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4329 ia64_codegen_init (code, p);
4331 cinfo = get_call_info (sig, FALSE);
4333 /* Save return value + pass it to func */
4334 switch (cinfo->ret.storage) {
4338 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4339 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4342 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4343 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4344 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4345 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4347 case ArgValuetypeAddrInIReg:
4348 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4359 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4360 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4361 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4363 /* Restore return value */
4364 switch (cinfo->ret.storage) {
4368 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4371 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4372 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4374 case ArgValuetypeAddrInIReg:
4382 ia64_codegen_close (code);
4388 mono_arch_save_unwind_info (MonoCompile *cfg)
4392 /* FIXME: Unregister this for dynamic methods */
4394 di = g_malloc0 (sizeof (unw_dyn_info_t));
4395 di->start_ip = (unw_word_t) cfg->native_code;
4396 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4398 di->format = UNW_INFO_FORMAT_DYNAMIC;
4399 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4400 di->u.pi.regions = cfg->arch.r_pro;
4402 _U_dyn_register (di);
4406 unw_dyn_region_info_t *region = di->u.pi.regions;
4408 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4410 printf (" [Region: %d]\n", region->insn_count);
4411 region = region->next;
4418 mono_arch_flush_icache (guint8 *code, gint size)
4420 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4421 guint8* end = (guint8*)((guint64)code + size);
4423 #ifdef __INTEL_COMPILER
4424 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4431 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4432 /* FIXME: This could be increased to 128 on some cpus */
4439 mono_arch_flush_register_windows (void)
4441 /* Not needed because of libunwind */
4445 mono_arch_is_inst_imm (gint64 imm)
4447 /* The lowering pass will take care of it */
4453 * Determine whenever the trap whose info is in SIGINFO is caused by
4457 mono_arch_is_int_overflow (void *sigctx, void *info)
4459 /* Division is emulated with explicit overflow checks */
4464 mono_arch_get_patch_offset (guint8 *code)
4472 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4474 guint8 *bundle2 = code - 48;
4475 guint8 *bundle3 = code - 32;
4476 guint8 *bundle4 = code - 16;
4477 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4478 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4479 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4480 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4481 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4482 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4483 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4484 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4485 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4489 * Virtual calls are made with:
4491 * [MII] ld8 r31=[r8]
4495 * mov.sptk b6=r31,0x2000000000f32a80
4502 * br.call.sptk.few b0=b6;;
4505 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4506 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4507 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4508 (ins31 == IA64_NOP_M) &&
4509 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4510 (ins33 == IA64_NOP_I) &&
4511 (ins41 == IA64_NOP_M) &&
4512 (ins42 == IA64_NOP_I) &&
4513 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4514 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4515 g_assert (ins21 == IA64_NOP_M);
4516 g_assert (ins23 == IA64_NOP_I);
4517 g_assert (ia64_ins_opcode (ins22) == 0);
4518 g_assert (ia64_ins_x3 (ins22) == 7);
4519 g_assert (ia64_ins_x (ins22) == 0);
4520 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4525 * Must be a scratch register, since only those are saved by the trampoline
4527 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4529 g_assert (regs [reg]);
4538 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4545 static gboolean tls_offset_inited = FALSE;
4548 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4550 if (!tls_offset_inited) {
4551 tls_offset_inited = TRUE;
4553 appdomain_tls_offset = mono_domain_get_tls_offset ();
4554 thread_tls_offset = mono_thread_get_tls_offset ();
4559 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4564 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4566 MonoCallInst *call = (MonoCallInst*)inst;
4567 int out_reg = cfg->arch.reg_out0;
4570 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4573 if (cinfo->ret.storage == ArgAggregate) {
4574 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4577 * The valuetype is in registers after the call, need to be copied
4578 * to the stack. Save the address to a local here, so the call
4579 * instruction can access it.
4581 g_assert (local->opcode == OP_REGOFFSET);
4582 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4585 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4586 vtarg->sreg1 = vt_reg;
4587 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4588 mono_bblock_add_inst (cfg->cbb, vtarg);
4590 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4598 /* add the this argument */
4599 if (this_reg != -1) {
4601 MONO_INST_NEW (cfg, this, OP_MOVE);
4602 this->type = this_type;
4603 this->sreg1 = this_reg;
4604 this->dreg = mono_regstate_next_int (cfg->rs);
4605 mono_bblock_add_inst (cfg->cbb, this);
4607 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4612 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4614 MonoInst *ins = NULL;
4616 if (cmethod->klass == mono_defaults.thread_class &&
4617 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4618 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4619 } else if(cmethod->klass->image == mono_defaults.corlib &&
4620 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4621 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4623 if (strcmp (cmethod->name, "Increment") == 0) {
4626 if (fsig->params [0]->type == MONO_TYPE_I4)
4627 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4628 else if (fsig->params [0]->type == MONO_TYPE_I8)
4629 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4631 g_assert_not_reached ();
4632 MONO_INST_NEW (cfg, ins, opcode);
4634 ins->inst_i0 = args [0];
4635 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4638 if (fsig->params [0]->type == MONO_TYPE_I4)
4639 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4640 else if (fsig->params [0]->type == MONO_TYPE_I8)
4641 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4643 g_assert_not_reached ();
4644 MONO_INST_NEW (cfg, ins, opcode);
4646 ins->inst_i0 = args [0];
4647 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4650 if (fsig->params [0]->type == MONO_TYPE_I4)
4651 opcode = OP_ATOMIC_EXCHANGE_I4;
4652 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4653 (fsig->params [0]->type == MONO_TYPE_I) ||
4654 (fsig->params [0]->type == MONO_TYPE_OBJECT))
4655 opcode = OP_ATOMIC_EXCHANGE_I8;
4659 MONO_INST_NEW (cfg, ins, opcode);
4661 ins->inst_i0 = args [0];
4662 ins->inst_i1 = args [1];
4663 } else if (strcmp (cmethod->name, "Add") == 0) {
4666 if (fsig->params [0]->type == MONO_TYPE_I4)
4667 opcode = OP_ATOMIC_ADD_NEW_I4;
4668 else if (fsig->params [0]->type == MONO_TYPE_I8)
4669 opcode = OP_ATOMIC_ADD_NEW_I8;
4671 g_assert_not_reached ();
4673 MONO_INST_NEW (cfg, ins, opcode);
4675 ins->inst_i0 = args [0];
4676 ins->inst_i1 = args [1];
4677 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4678 /* 64 bit reads are already atomic */
4679 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4680 ins->inst_i0 = args [0];
4688 mono_arch_print_tree (MonoInst *tree, int arity)
4693 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4697 if (appdomain_tls_offset == -1)
4700 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4701 ins->inst_offset = appdomain_tls_offset;
4705 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4709 if (thread_tls_offset == -1)
4712 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4713 ins->inst_offset = thread_tls_offset;