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 (MonoGenericSharingContext *gsctx, 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 = mini_type_stack_size (gsctx, &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 (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
356 int n = sig->hasthis + sig->param_count;
357 guint32 stack_size = 0;
359 MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
362 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
364 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
371 ret_type = mono_type_get_underlying_type (sig->ret);
372 ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
373 switch (ret_type->type) {
374 case MONO_TYPE_BOOLEAN:
385 case MONO_TYPE_FNPTR:
386 case MONO_TYPE_CLASS:
387 case MONO_TYPE_OBJECT:
388 case MONO_TYPE_SZARRAY:
389 case MONO_TYPE_ARRAY:
390 case MONO_TYPE_STRING:
391 cinfo->ret.storage = ArgInIReg;
392 cinfo->ret.reg = IA64_R8;
396 cinfo->ret.storage = ArgInIReg;
397 cinfo->ret.reg = IA64_R8;
401 cinfo->ret.storage = ArgInFloatReg;
404 case MONO_TYPE_GENERICINST:
405 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
406 cinfo->ret.storage = ArgInIReg;
407 cinfo->ret.reg = IA64_R8;
411 case MONO_TYPE_VALUETYPE:
412 case MONO_TYPE_TYPEDBYREF: {
413 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
415 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
416 if (cinfo->ret.storage == ArgOnStack)
417 /* The caller passes the address where the value is stored */
418 add_general (&gr, &stack_size, &cinfo->ret);
419 if (cinfo->ret.storage == ArgInIReg)
420 cinfo->ret.storage = ArgValuetypeAddrInIReg;
424 cinfo->ret.storage = ArgNone;
427 g_error ("Can't handle as return value 0x%x", sig->ret->type);
433 add_general (&gr, &stack_size, cinfo->args + 0);
435 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
437 fr = FLOAT_PARAM_REGS;
439 /* Emit the signature cookie just before the implicit arguments */
440 add_general (&gr, &stack_size, &cinfo->sig_cookie);
443 for (i = 0; i < sig->param_count; ++i) {
444 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
447 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
448 /* We allways pass the sig cookie on the stack for simplicity */
450 * Prevent implicit arguments + the sig cookie from being passed
454 fr = FLOAT_PARAM_REGS;
456 /* Emit the signature cookie just before the implicit arguments */
457 add_general (&gr, &stack_size, &cinfo->sig_cookie);
460 if (sig->params [i]->byref) {
461 add_general (&gr, &stack_size, ainfo);
464 ptype = mono_type_get_underlying_type (sig->params [i]);
465 ptype = mini_get_basic_type_from_generic (gsctx, ptype);
466 switch (ptype->type) {
467 case MONO_TYPE_BOOLEAN:
470 add_general (&gr, &stack_size, ainfo);
475 add_general (&gr, &stack_size, ainfo);
479 add_general (&gr, &stack_size, ainfo);
484 case MONO_TYPE_FNPTR:
485 case MONO_TYPE_CLASS:
486 case MONO_TYPE_OBJECT:
487 case MONO_TYPE_STRING:
488 case MONO_TYPE_SZARRAY:
489 case MONO_TYPE_ARRAY:
490 add_general (&gr, &stack_size, ainfo);
492 case MONO_TYPE_GENERICINST:
493 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
494 add_general (&gr, &stack_size, ainfo);
498 case MONO_TYPE_VALUETYPE:
499 case MONO_TYPE_TYPEDBYREF:
501 /* We allways pass valuetypes on the stack */
502 add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
506 add_general (&gr, &stack_size, ainfo);
509 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
512 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
515 g_assert_not_reached ();
519 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
521 fr = FLOAT_PARAM_REGS;
523 /* Emit the signature cookie just before the implicit arguments */
524 add_general (&gr, &stack_size, &cinfo->sig_cookie);
527 cinfo->stack_usage = stack_size;
528 cinfo->reg_usage = gr;
529 cinfo->freg_usage = fr;
534 * mono_arch_get_argument_info:
535 * @csig: a method signature
536 * @param_count: the number of parameters to consider
537 * @arg_info: an array to store the result infos
539 * Gathers information on parameters such as size, alignment and
540 * padding. arg_info should be large enought to hold param_count + 1 entries.
542 * Returns the size of the argument area on the stack.
545 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
548 CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
549 guint32 args_size = cinfo->stack_usage;
551 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
553 arg_info [0].offset = 0;
556 for (k = 0; k < param_count; k++) {
557 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
559 arg_info [k + 1].size = 0;
568 * Initialize the cpu to execute managed code.
571 mono_arch_cpu_init (void)
576 * Initialize architecture specific code.
579 mono_arch_init (void)
584 * Cleanup architecture specific code.
587 mono_arch_cleanup (void)
592 * This function returns the optimizations supported on this cpu.
595 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
603 mono_arch_break (void)
608 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
612 MonoMethodSignature *sig;
613 MonoMethodHeader *header;
616 header = mono_method_get_header (cfg->method);
618 sig = mono_method_signature (cfg->method);
620 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
622 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
623 MonoInst *ins = cfg->args [i];
625 ArgInfo *ainfo = &cinfo->args [i];
627 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
630 if (ainfo->storage == ArgInIReg) {
631 /* The input registers are non-volatile */
632 ins->opcode = OP_REGVAR;
633 ins->dreg = 32 + ainfo->reg;
637 for (i = 0; i < cfg->num_varinfo; i++) {
638 MonoInst *ins = cfg->varinfo [i];
639 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
642 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
645 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
646 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
649 if (mono_is_regsize_var (ins->inst_vtype)) {
650 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
651 g_assert (i == vmv->idx);
652 vars = g_list_prepend (vars, vmv);
656 vars = mono_varlist_sort (cfg, vars, 0);
662 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
665 guint32 reserved_regs;
666 MonoMethodHeader *header;
668 if (cfg->arch.reg_local0 > 0)
672 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
674 header = mono_method_get_header (cfg->method);
676 /* Some registers are reserved for use by the prolog/epilog */
677 reserved_regs = header->num_clauses ? 4 : 3;
679 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
680 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
681 /* One registers is needed by instrument_epilog to save the return value */
683 if (cinfo->reg_usage < 2)
684 /* Number of arguments passed to function call in instrument_prolog */
685 cinfo->reg_usage = 2;
688 cfg->arch.reg_in0 = 32;
689 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
690 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
692 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
693 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
694 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
697 * Frames without handlers save sp to fp, frames with handlers save it into
698 * a dedicated register.
700 if (header->num_clauses)
701 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
703 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
705 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
706 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
707 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
711 * Need to allocate at least 2 out register for use by OP_THROW / the system
712 * exception throwing code.
714 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
718 mono_arch_get_global_int_regs (MonoCompile *cfg)
723 mono_ia64_alloc_stacked_registers (cfg);
725 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
728 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
735 * mono_arch_regalloc_cost:
737 * Return the cost, in number of memory references, of the action of
738 * allocating the variable VMV into a register during global register
742 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
744 /* FIXME: Increase costs linearly to avoid using all local registers */
750 mono_arch_allocate_vars (MonoCompile *cfg)
752 MonoMethodSignature *sig;
753 MonoMethodHeader *header;
756 guint32 locals_stack_size, locals_stack_align;
760 header = mono_method_get_header (cfg->method);
762 sig = mono_method_signature (cfg->method);
764 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
767 * Determine whenever the frame pointer can be eliminated.
768 * FIXME: Remove some of the restrictions.
770 cfg->arch.omit_fp = TRUE;
772 if (!debug_omit_fp ())
773 cfg->arch.omit_fp = FALSE;
775 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
776 cfg->arch.omit_fp = FALSE;
777 if (header->num_clauses)
778 cfg->arch.omit_fp = FALSE;
780 cfg->arch.omit_fp = FALSE;
781 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
782 ArgInfo *ainfo = &cinfo->args [i];
784 if (ainfo->storage == ArgOnStack) {
786 * The stack offset can only be determined when the frame
789 cfg->arch.omit_fp = FALSE;
793 mono_ia64_alloc_stacked_registers (cfg);
796 * We use the ABI calling conventions for managed code as well.
797 * Exception: valuetypes are never passed or returned in registers.
800 if (cfg->arch.omit_fp) {
801 cfg->frame_reg = IA64_SP;
802 offset = ARGS_OFFSET;
805 /* Locals are allocated backwards from %fp */
806 cfg->frame_reg = cfg->arch.reg_fp;
810 if (cfg->method->save_lmf) {
814 if (sig->ret->type != MONO_TYPE_VOID) {
815 switch (cinfo->ret.storage) {
817 cfg->ret->opcode = OP_REGVAR;
818 cfg->ret->inst_c0 = cinfo->ret.reg;
821 cfg->ret->opcode = OP_REGVAR;
822 cfg->ret->inst_c0 = cinfo->ret.reg;
824 case ArgValuetypeAddrInIReg:
825 cfg->ret->opcode = OP_REGVAR;
826 cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
829 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
830 if (cfg->arch.omit_fp)
831 g_assert_not_reached ();
832 offset = ALIGN_TO (offset, 8);
833 offset += cinfo->ret.nslots * 8;
834 cfg->ret->opcode = OP_REGOFFSET;
835 cfg->ret->inst_basereg = cfg->frame_reg;
836 cfg->ret->inst_offset = - offset;
839 g_assert_not_reached ();
841 cfg->ret->dreg = cfg->ret->inst_c0;
844 /* Allocate locals */
845 offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
846 if (locals_stack_align) {
847 offset = ALIGN_TO (offset, locals_stack_align);
849 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
850 if (offsets [i] != -1) {
851 MonoInst *inst = cfg->varinfo [i];
852 inst->opcode = OP_REGOFFSET;
853 inst->inst_basereg = cfg->frame_reg;
854 if (cfg->arch.omit_fp)
855 inst->inst_offset = (offset + offsets [i]);
857 inst->inst_offset = - (offset + offsets [i]);
858 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
861 offset += locals_stack_size;
863 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
864 if (cfg->arch.omit_fp)
865 g_assert_not_reached ();
866 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
867 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
870 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
871 inst = cfg->args [i];
872 if (inst->opcode != OP_REGVAR) {
873 ArgInfo *ainfo = &cinfo->args [i];
874 gboolean inreg = TRUE;
877 if (sig->hasthis && (i == 0))
878 arg_type = &mono_defaults.object_class->byval_arg;
880 arg_type = sig->params [i - sig->hasthis];
882 /* FIXME: VOLATILE is only set if the liveness pass runs */
883 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
886 inst->opcode = OP_REGOFFSET;
888 switch (ainfo->storage) {
890 inst->opcode = OP_REGVAR;
891 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
895 * Since float regs are volatile, we save the arguments to
896 * the stack in the prolog.
901 if (cfg->arch.omit_fp)
902 g_assert_not_reached ();
903 inst->opcode = OP_REGOFFSET;
904 inst->inst_basereg = cfg->frame_reg;
905 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
914 if (!inreg && (ainfo->storage != ArgOnStack)) {
915 inst->opcode = OP_REGOFFSET;
916 inst->inst_basereg = cfg->frame_reg;
917 /* These arguments are saved to the stack in the prolog */
918 switch (ainfo->storage) {
920 if (ainfo->atype == AggregateSingleHFA)
921 offset += ainfo->nslots * 4;
923 offset += ainfo->nslots * 8;
926 offset += sizeof (gpointer);
929 offset = ALIGN_TO (offset, sizeof (gpointer));
930 if (cfg->arch.omit_fp)
931 inst->inst_offset = offset;
933 inst->inst_offset = - offset;
938 if (cfg->arch.omit_fp && offset == 16)
941 cfg->stack_offset = offset;
945 mono_arch_create_vars (MonoCompile *cfg)
947 MonoMethodSignature *sig;
950 sig = mono_method_signature (cfg->method);
952 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
954 if (cinfo->ret.storage == ArgAggregate)
955 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 (cfg, cfg->mempool, 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 mini_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;
1243 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1245 MonoInst *ins, *last_ins = NULL;
1249 switch (ins->opcode) {
1257 if (ins->dreg == ins->sreg1) {
1259 last_ins->next = ins->next;
1266 * OP_MOVE sreg, dreg
1267 * OP_MOVE dreg, sreg
1269 if (last_ins && last_ins->opcode == OP_MOVE &&
1270 ins->sreg1 == last_ins->dreg &&
1271 ins->dreg == last_ins->sreg1) {
1272 last_ins->next = ins->next;
1279 /* remove unnecessary multiplication with 1 */
1280 if (ins->inst_imm == 1) {
1281 if (ins->dreg != ins->sreg1) {
1282 ins->opcode = OP_MOVE;
1284 last_ins->next = ins->next;
1295 bb->last_ins = last_ins;
1298 int cond_to_ia64_cmp [][3] = {
1299 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1300 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1301 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1302 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1303 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1304 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1305 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1306 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1307 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1308 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1312 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1314 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1317 int cond_to_ia64_cmp_imm [][3] = {
1318 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1319 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1320 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1321 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1322 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1323 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1324 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1325 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1326 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1327 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1331 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1333 /* The condition needs to be reversed */
1334 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1338 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1342 bb->code = to_insert;
1343 to_insert->next = ins;
1346 to_insert->next = ins->next;
1347 ins->next = to_insert;
1351 #define NEW_INS(cfg,dest,op) do { \
1352 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1353 (dest)->opcode = (op); \
1354 insert_after_ins (bb, last_ins, (dest)); \
1355 last_ins = (dest); \
1359 * mono_arch_lowering_pass:
1361 * Converts complex opcodes into simpler ones so that each IR instruction
1362 * corresponds to one machine instruction.
1365 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1367 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1370 if (bb->max_vreg > cfg->rs->next_vreg)
1371 cfg->rs->next_vreg = bb->max_vreg;
1374 switch (ins->opcode) {
1375 case OP_STOREI1_MEMBASE_IMM:
1376 case OP_STOREI2_MEMBASE_IMM:
1377 case OP_STOREI4_MEMBASE_IMM:
1378 case OP_STOREI8_MEMBASE_IMM:
1379 case OP_STORE_MEMBASE_IMM:
1380 /* There are no store_membase instructions on ia64 */
1381 if (ins->inst_offset == 0) {
1383 } else if (ia64_is_imm14 (ins->inst_offset)) {
1384 NEW_INS (cfg, temp2, OP_ADD_IMM);
1385 temp2->sreg1 = ins->inst_destbasereg;
1386 temp2->inst_imm = ins->inst_offset;
1387 temp2->dreg = mono_regstate_next_int (cfg->rs);
1390 NEW_INS (cfg, temp, OP_I8CONST);
1391 temp->inst_c0 = ins->inst_offset;
1392 temp->dreg = mono_regstate_next_int (cfg->rs);
1393 NEW_INS (cfg, temp2, CEE_ADD);
1394 temp2->sreg1 = ins->inst_destbasereg;
1395 temp2->sreg2 = temp->dreg;
1396 temp2->dreg = mono_regstate_next_int (cfg->rs);
1399 switch (ins->opcode) {
1400 case OP_STOREI1_MEMBASE_IMM:
1401 ins->opcode = OP_STOREI1_MEMBASE_REG;
1403 case OP_STOREI2_MEMBASE_IMM:
1404 ins->opcode = OP_STOREI2_MEMBASE_REG;
1406 case OP_STOREI4_MEMBASE_IMM:
1407 ins->opcode = OP_STOREI4_MEMBASE_REG;
1409 case OP_STOREI8_MEMBASE_IMM:
1410 case OP_STORE_MEMBASE_IMM:
1411 ins->opcode = OP_STOREI8_MEMBASE_REG;
1414 g_assert_not_reached ();
1417 if (ins->inst_imm == 0)
1418 ins->sreg1 = IA64_R0;
1420 NEW_INS (cfg, temp3, OP_I8CONST);
1421 temp3->inst_c0 = ins->inst_imm;
1422 temp3->dreg = mono_regstate_next_int (cfg->rs);
1423 ins->sreg1 = temp3->dreg;
1426 ins->inst_offset = 0;
1428 ins->inst_destbasereg = temp2->dreg;
1430 case OP_STOREI1_MEMBASE_REG:
1431 case OP_STOREI2_MEMBASE_REG:
1432 case OP_STOREI4_MEMBASE_REG:
1433 case OP_STOREI8_MEMBASE_REG:
1434 case OP_STORER4_MEMBASE_REG:
1435 case OP_STORER8_MEMBASE_REG:
1436 case OP_STORE_MEMBASE_REG:
1437 /* There are no store_membase instructions on ia64 */
1438 if (ins->inst_offset == 0) {
1441 else if (ia64_is_imm14 (ins->inst_offset)) {
1442 NEW_INS (cfg, temp2, OP_ADD_IMM);
1443 temp2->sreg1 = ins->inst_destbasereg;
1444 temp2->inst_imm = ins->inst_offset;
1445 temp2->dreg = mono_regstate_next_int (cfg->rs);
1448 NEW_INS (cfg, temp, OP_I8CONST);
1449 temp->inst_c0 = ins->inst_offset;
1450 temp->dreg = mono_regstate_next_int (cfg->rs);
1451 NEW_INS (cfg, temp2, CEE_ADD);
1452 temp2->sreg1 = ins->inst_destbasereg;
1453 temp2->sreg2 = temp->dreg;
1454 temp2->dreg = mono_regstate_next_int (cfg->rs);
1457 ins->inst_offset = 0;
1458 ins->inst_destbasereg = temp2->dreg;
1460 case OP_LOADI1_MEMBASE:
1461 case OP_LOADU1_MEMBASE:
1462 case OP_LOADI2_MEMBASE:
1463 case OP_LOADU2_MEMBASE:
1464 case OP_LOADI4_MEMBASE:
1465 case OP_LOADU4_MEMBASE:
1466 case OP_LOADI8_MEMBASE:
1467 case OP_LOAD_MEMBASE:
1468 case OP_LOADR4_MEMBASE:
1469 case OP_LOADR8_MEMBASE:
1470 case OP_ATOMIC_EXCHANGE_I4:
1471 case OP_ATOMIC_EXCHANGE_I8:
1472 case OP_ATOMIC_ADD_NEW_I4:
1473 case OP_ATOMIC_ADD_NEW_I8:
1474 case OP_ATOMIC_ADD_IMM_NEW_I4:
1475 case OP_ATOMIC_ADD_IMM_NEW_I8:
1476 /* There are no membase instructions on ia64 */
1477 if (ins->inst_offset == 0) {
1480 else if (ia64_is_imm14 (ins->inst_offset)) {
1481 NEW_INS (cfg, temp2, OP_ADD_IMM);
1482 temp2->sreg1 = ins->inst_basereg;
1483 temp2->inst_imm = ins->inst_offset;
1484 temp2->dreg = mono_regstate_next_int (cfg->rs);
1487 NEW_INS (cfg, temp, OP_I8CONST);
1488 temp->inst_c0 = ins->inst_offset;
1489 temp->dreg = mono_regstate_next_int (cfg->rs);
1490 NEW_INS (cfg, temp2, CEE_ADD);
1491 temp2->sreg1 = ins->inst_basereg;
1492 temp2->sreg2 = temp->dreg;
1493 temp2->dreg = mono_regstate_next_int (cfg->rs);
1496 ins->inst_offset = 0;
1497 ins->inst_basereg = temp2->dreg;
1512 case OP_ISHR_UN_IMM:
1513 case OP_LSHR_UN_IMM: {
1514 gboolean is_imm = FALSE;
1515 gboolean switched = FALSE;
1517 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1518 ins->opcode = OP_ZEXT_I1;
1522 switch (ins->opcode) {
1525 is_imm = ia64_is_imm14 (ins->inst_imm);
1529 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1531 /* A = B - IMM -> A = B + (-IMM) */
1532 ins->inst_imm = - ins->inst_imm;
1533 ins->opcode = OP_IADD_IMM;
1541 is_imm = ia64_is_imm8 (ins->inst_imm);
1550 case OP_ISHR_UN_IMM:
1551 case OP_LSHR_UN_IMM:
1552 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1560 ins->sreg2 = ins->sreg1;
1564 switch (ins->opcode) {
1566 ins->opcode = CEE_ADD;
1569 ins->opcode = OP_IADD;
1572 ins->opcode = OP_ISUB;
1575 ins->opcode = OP_IAND;
1578 ins->opcode = OP_IOR;
1581 ins->opcode = OP_IXOR;
1584 ins->opcode = OP_ISHL;
1587 ins->opcode = OP_ISHR;
1589 case OP_ISHR_UN_IMM:
1590 ins->opcode = OP_ISHR_UN;
1593 ins->opcode = CEE_AND;
1596 ins->opcode = OP_LSHL;
1599 ins->opcode = OP_LSHR;
1602 ins->opcode = OP_LSHL;
1605 ins->opcode = OP_LSHR;
1607 case OP_LSHR_UN_IMM:
1608 ins->opcode = OP_LSHR_UN;
1611 g_assert_not_reached ();
1614 if (ins->inst_imm == 0)
1615 ins->sreg2 = IA64_R0;
1617 NEW_INS (cfg, temp, OP_I8CONST);
1618 temp->inst_c0 = ins->inst_imm;
1619 temp->dreg = mono_regstate_next_int (cfg->rs);
1620 ins->sreg2 = temp->dreg;
1624 case OP_COMPARE_IMM:
1625 case OP_ICOMPARE_IMM: {
1626 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1631 * The compare_imm instructions have switched up arguments, and
1632 * some of them take an imm between -127 and 128.
1635 cond = mono_opcode_to_cond (next->opcode);
1636 if ((cond == CMP_LT) || (cond == CMP_GE))
1637 imm = ia64_is_imm8 (ins->inst_imm - 1);
1638 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1639 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1641 imm = ia64_is_imm8 (ins->inst_imm);
1644 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1645 ins->sreg2 = ins->sreg1;
1648 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1650 if (ins->inst_imm == 0)
1651 ins->sreg2 = IA64_R0;
1653 NEW_INS (cfg, temp, OP_I8CONST);
1654 temp->inst_c0 = ins->inst_imm;
1655 temp->dreg = mono_regstate_next_int (cfg->rs);
1656 ins->sreg2 = temp->dreg;
1660 switch (next->opcode) {
1681 next->opcode = OP_IA64_BR_COND;
1682 if (! (next->flags & MONO_INST_BRLABEL))
1683 next->inst_target_bb = next->inst_true_bb;
1685 case OP_COND_EXC_EQ:
1686 case OP_COND_EXC_GT:
1687 case OP_COND_EXC_LT:
1688 case OP_COND_EXC_GT_UN:
1689 case OP_COND_EXC_LE_UN:
1690 case OP_COND_EXC_NE_UN:
1691 case OP_COND_EXC_LT_UN:
1692 next->opcode = OP_IA64_COND_EXC;
1704 next->opcode = OP_IA64_CSET;
1707 printf ("%s\n", mono_inst_name (next->opcode));
1717 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1721 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1722 switch (next->opcode) {
1753 next->opcode = OP_IA64_BR_COND;
1754 if (! (next->flags & MONO_INST_BRLABEL))
1755 next->inst_target_bb = next->inst_true_bb;
1757 case OP_COND_EXC_LT:
1758 case OP_COND_EXC_GT:
1759 case OP_COND_EXC_GT_UN:
1760 case OP_COND_EXC_LE_UN:
1761 next->opcode = OP_IA64_COND_EXC;
1778 next->opcode = OP_IA64_CSET;
1781 printf ("%s\n", mono_inst_name (next->opcode));
1790 gboolean found = FALSE;
1791 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1793 /* First the easy cases */
1794 if (ins->inst_imm == 1) {
1795 ins->opcode = OP_MOVE;
1798 for (i = 1; i < 64; ++i)
1799 if (ins->inst_imm == (((gint64)1) << i)) {
1800 ins->opcode = shl_op;
1806 /* This could be optimized */
1809 for (i = 0; i < 64; ++i) {
1810 if (ins->inst_imm & (((gint64)1) << i)) {
1811 NEW_INS (cfg, temp, shl_op);
1812 temp->dreg = mono_regstate_next_int (cfg->rs);
1813 temp->sreg1 = ins->sreg1;
1817 sum_reg = temp->dreg;
1819 NEW_INS (cfg, temp2, CEE_ADD);
1820 temp2->dreg = mono_regstate_next_int (cfg->rs);
1821 temp2->sreg1 = sum_reg;
1822 temp2->sreg2 = temp->dreg;
1823 sum_reg = temp2->dreg;
1827 ins->opcode = OP_MOVE;
1828 ins->sreg1 = sum_reg;
1832 case CEE_CONV_OVF_U4:
1833 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1834 temp->sreg1 = ins->sreg1;
1835 temp->sreg2 = IA64_R0;
1837 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1838 temp->inst_p1 = (char*)"OverflowException";
1840 ins->opcode = OP_MOVE;
1842 case CEE_CONV_OVF_I4_UN:
1843 NEW_INS (cfg, temp, OP_ICONST);
1844 temp->inst_c0 = 0x7fffffff;
1845 temp->dreg = mono_regstate_next_int (cfg->rs);
1847 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1848 temp2->sreg1 = ins->sreg1;
1849 temp2->sreg2 = temp->dreg;
1851 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1852 temp->inst_p1 = (char*)"OverflowException";
1854 ins->opcode = OP_MOVE;
1856 case OP_FCONV_TO_I4:
1857 case OP_FCONV_TO_I2:
1858 case OP_FCONV_TO_U2:
1859 case OP_FCONV_TO_I1:
1860 case OP_FCONV_TO_U1:
1861 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1862 temp->sreg1 = ins->sreg1;
1863 temp->dreg = ins->dreg;
1865 switch (ins->opcode) {
1866 case OP_FCONV_TO_I4:
1867 ins->opcode = OP_SEXT_I4;
1869 case OP_FCONV_TO_I2:
1870 ins->opcode = OP_SEXT_I2;
1872 case OP_FCONV_TO_U2:
1873 ins->opcode = OP_ZEXT_I4;
1875 case OP_FCONV_TO_I1:
1876 ins->opcode = OP_SEXT_I1;
1878 case OP_FCONV_TO_U1:
1879 ins->opcode = OP_ZEXT_I1;
1882 g_assert_not_reached ();
1884 ins->sreg1 = ins->dreg;
1892 bb->last_ins = last_ins;
1894 bb->max_vreg = cfg->rs->next_vreg;
1898 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1903 mono_arch_lowering_pass (cfg, bb);
1905 mono_local_regalloc (cfg, bb);
1909 * emit_load_volatile_arguments:
1911 * Load volatile arguments from the stack to the original input registers.
1912 * Required before a tail call.
1914 static Ia64CodegenState
1915 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1917 MonoMethod *method = cfg->method;
1918 MonoMethodSignature *sig;
1923 /* FIXME: Generate intermediate code instead */
1925 sig = mono_method_signature (method);
1927 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
1929 /* This is the opposite of the code in emit_prolog */
1930 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1931 ArgInfo *ainfo = cinfo->args + i;
1932 gint32 stack_offset;
1934 ins = cfg->args [i];
1936 if (sig->hasthis && (i == 0))
1937 arg_type = &mono_defaults.object_class->byval_arg;
1939 arg_type = sig->params [i - sig->hasthis];
1941 arg_type = mono_type_get_underlying_type (arg_type);
1943 stack_offset = ainfo->offset + ARGS_OFFSET;
1945 /* Save volatile arguments to the stack */
1946 if (ins->opcode != OP_REGVAR) {
1947 switch (ainfo->storage) {
1950 /* FIXME: big offsets */
1951 g_assert (ins->opcode == OP_REGOFFSET);
1952 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1953 if (arg_type->byref)
1954 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1956 switch (arg_type->type) {
1958 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1961 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1964 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1976 if (ins->opcode == OP_REGVAR) {
1977 /* Argument allocated to (non-volatile) register */
1978 switch (ainfo->storage) {
1980 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1981 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1984 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1985 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1996 static Ia64CodegenState
1997 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
2002 /* Move return value to the target register */
2003 switch (ins->opcode) {
2005 case OP_VOIDCALL_REG:
2006 case OP_VOIDCALL_MEMBASE:
2010 case OP_CALL_MEMBASE:
2013 case OP_LCALL_MEMBASE:
2014 g_assert (ins->dreg == IA64_R8);
2018 case OP_FCALL_MEMBASE:
2019 g_assert (ins->dreg == 8);
2023 case OP_VCALL_MEMBASE: {
2026 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
2027 storage = cinfo->ret.storage;
2029 if (storage == ArgAggregate) {
2030 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2032 /* Load address of stack space allocated for the return value */
2033 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2034 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2035 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2037 for (i = 0; i < cinfo->ret.nregs; ++i) {
2038 switch (cinfo->ret.atype) {
2039 case AggregateNormal:
2040 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2042 case AggregateSingleHFA:
2043 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2045 case AggregateDoubleHFA:
2046 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2049 g_assert_not_reached ();
2056 g_assert_not_reached ();
2062 #define add_patch_info(cfg,code,patch_type,data) do { \
2063 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2066 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2067 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2069 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2071 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2072 ia64_br_cond_pred (code, (predicate), 0); \
2075 static Ia64CodegenState
2076 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2078 add_patch_info (cfg, code, patch_type, data);
2080 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2082 /* mono_arch_patch_callsite will patch this */
2083 /* mono_arch_nullify_class_init_trampoline will patch this */
2084 ia64_movl (code, GP_SCRATCH_REG, 0);
2085 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2086 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2087 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2088 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2091 /* Can't use a direct call since the displacement might be too small */
2092 /* mono_arch_patch_callsite will patch this */
2093 ia64_movl (code, GP_SCRATCH_REG, 0);
2094 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2095 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2101 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2104 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2109 Ia64CodegenState code;
2110 guint8 *code_start = cfg->native_code + cfg->code_len;
2111 MonoInst *last_ins = NULL;
2112 guint last_offset = 0;
2115 if (cfg->opt & MONO_OPT_PEEPHOLE)
2116 peephole_pass (cfg, bb);
2118 if (cfg->opt & MONO_OPT_LOOP) {
2122 if (cfg->verbose_level > 2)
2123 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2125 cpos = bb->max_offset;
2127 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2131 offset = code_start - cfg->native_code;
2133 ia64_codegen_init (code, code_start);
2136 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2142 offset = code.buf - cfg->native_code;
2144 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2146 while (offset + max_len + 16 > cfg->code_size) {
2147 ia64_codegen_close (code);
2149 offset = code.buf - cfg->native_code;
2151 cfg->code_size *= 2;
2152 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2153 code_start = cfg->native_code + offset;
2154 mono_jit_stats.code_reallocs++;
2156 ia64_codegen_init (code, code_start);
2159 mono_debug_record_line_number (cfg, ins, offset);
2161 switch (ins->opcode) {
2164 if (ia64_is_imm14 (ins->inst_c0))
2165 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2167 ia64_movl (code, ins->dreg, ins->inst_c0);
2170 ia64_mov (code, ins->dreg, ins->sreg1);
2173 case OP_IA64_BR_COND: {
2175 if (ins->opcode == OP_IA64_BR_COND)
2177 if (ins->flags & MONO_INST_BRLABEL) {
2178 if (ins->inst_i0->inst_c0) {
2181 add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2182 ia64_br_cond_pred (code, pred, 0);
2185 if (ins->inst_target_bb->native_offset) {
2186 guint8 *pos = code.buf + code.nins;
2188 ia64_br_cond_pred (code, pred, 0);
2189 ia64_begin_bundle (code);
2190 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2192 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2193 ia64_br_cond_pred (code, pred, 0);
2199 ia64_begin_bundle (code);
2200 ins->inst_c0 = code.buf - cfg->native_code;
2205 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2206 ia64_br_cond_reg (code, IA64_B6);
2210 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2214 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2218 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2222 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2226 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2230 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2233 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2237 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2240 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2241 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2245 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2248 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2252 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2255 /* p6 and p7 is set if there is signed/unsigned overflow */
2257 /* Set p8-p9 == (sreg2 > 0) */
2258 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2260 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2262 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2263 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2264 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2265 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2267 /* res <u sreg1 => unsigned overflow */
2268 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2270 /* FIXME: Predicate this since this is a side effect */
2271 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2274 /* p6 and p7 is set if there is signed/unsigned overflow */
2276 /* Set p8-p9 == (sreg2 > 0) */
2277 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2279 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2281 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2282 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2283 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2284 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2286 /* sreg1 <u sreg2 => unsigned overflow */
2287 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2289 /* FIXME: Predicate this since this is a side effect */
2290 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2293 /* Same as OP_IADDCC */
2294 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2296 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2298 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2299 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2301 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2303 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2306 /* Same as OP_ISUBCC */
2308 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2310 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2312 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2313 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2315 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2317 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2321 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2325 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2328 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2331 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2336 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2341 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2343 case OP_ISHR_UN_IMM:
2344 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2345 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2347 case OP_LSHR_UN_IMM:
2348 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2351 /* Based on gcc code */
2352 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2353 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2354 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2355 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2358 case OP_STOREI1_MEMBASE_REG:
2359 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2361 case OP_STOREI2_MEMBASE_REG:
2362 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2364 case OP_STOREI4_MEMBASE_REG:
2365 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2367 case OP_STOREI8_MEMBASE_REG:
2368 case OP_STORE_MEMBASE_REG:
2369 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2372 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2373 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2375 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2376 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2378 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2379 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2381 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2382 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2385 case OP_LOADU1_MEMBASE:
2386 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2388 case OP_LOADU2_MEMBASE:
2389 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2391 case OP_LOADU4_MEMBASE:
2392 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2394 case OP_LOADI1_MEMBASE:
2395 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2396 ia64_sxt1 (code, ins->dreg, ins->dreg);
2398 case OP_LOADI2_MEMBASE:
2399 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2400 ia64_sxt2 (code, ins->dreg, ins->dreg);
2402 case OP_LOADI4_MEMBASE:
2403 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2404 ia64_sxt4 (code, ins->dreg, ins->dreg);
2406 case OP_LOAD_MEMBASE:
2407 case OP_LOADI8_MEMBASE:
2408 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2411 case OP_IA64_LOADU1_MEMBASE_INC:
2412 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2414 case OP_IA64_LOADU2_MEMBASE_INC:
2415 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2417 case OP_IA64_LOADU4_MEMBASE_INC:
2418 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2420 case OP_IA64_LOADI8_MEMBASE_INC:
2421 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2425 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2428 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2431 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2434 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2437 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2440 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2443 /* Compare opcodes */
2444 case OP_IA64_CMP4_EQ:
2445 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2447 case OP_IA64_CMP4_NE:
2448 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2450 case OP_IA64_CMP4_LE:
2451 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2453 case OP_IA64_CMP4_LT:
2454 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2456 case OP_IA64_CMP4_GE:
2457 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2459 case OP_IA64_CMP4_GT:
2460 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2462 case OP_IA64_CMP4_LT_UN:
2463 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2465 case OP_IA64_CMP4_LE_UN:
2466 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2468 case OP_IA64_CMP4_GT_UN:
2469 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2471 case OP_IA64_CMP4_GE_UN:
2472 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2474 case OP_IA64_CMP_EQ:
2475 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2477 case OP_IA64_CMP_NE:
2478 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2480 case OP_IA64_CMP_LE:
2481 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2483 case OP_IA64_CMP_LT:
2484 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2486 case OP_IA64_CMP_GE:
2487 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2489 case OP_IA64_CMP_GT:
2490 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2492 case OP_IA64_CMP_GT_UN:
2493 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2495 case OP_IA64_CMP_LT_UN:
2496 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2498 case OP_IA64_CMP_GE_UN:
2499 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2501 case OP_IA64_CMP_LE_UN:
2502 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2504 case OP_IA64_CMP4_EQ_IMM:
2505 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2507 case OP_IA64_CMP4_NE_IMM:
2508 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2510 case OP_IA64_CMP4_LE_IMM:
2511 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2513 case OP_IA64_CMP4_LT_IMM:
2514 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2516 case OP_IA64_CMP4_GE_IMM:
2517 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2519 case OP_IA64_CMP4_GT_IMM:
2520 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2522 case OP_IA64_CMP4_LT_UN_IMM:
2523 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2525 case OP_IA64_CMP4_LE_UN_IMM:
2526 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2528 case OP_IA64_CMP4_GT_UN_IMM:
2529 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2531 case OP_IA64_CMP4_GE_UN_IMM:
2532 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2534 case OP_IA64_CMP_EQ_IMM:
2535 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2537 case OP_IA64_CMP_NE_IMM:
2538 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2540 case OP_IA64_CMP_LE_IMM:
2541 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2543 case OP_IA64_CMP_LT_IMM:
2544 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2546 case OP_IA64_CMP_GE_IMM:
2547 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2549 case OP_IA64_CMP_GT_IMM:
2550 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2552 case OP_IA64_CMP_GT_UN_IMM:
2553 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2555 case OP_IA64_CMP_LT_UN_IMM:
2556 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2558 case OP_IA64_CMP_GE_UN_IMM:
2559 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2561 case OP_IA64_CMP_LE_UN_IMM:
2562 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2564 case OP_IA64_FCMP_EQ:
2565 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2567 case OP_IA64_FCMP_NE:
2568 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2570 case OP_IA64_FCMP_LT:
2571 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2573 case OP_IA64_FCMP_GT:
2574 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2576 case OP_IA64_FCMP_LE:
2577 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2579 case OP_IA64_FCMP_GE:
2580 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2582 case OP_IA64_FCMP_GT_UN:
2583 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2584 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2586 case OP_IA64_FCMP_LT_UN:
2587 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2588 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2590 case OP_IA64_FCMP_GE_UN:
2591 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2592 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2594 case OP_IA64_FCMP_LE_UN:
2595 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2596 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2599 case OP_COND_EXC_IOV:
2600 case OP_COND_EXC_OV:
2601 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2603 case OP_COND_EXC_IC:
2605 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2607 case OP_IA64_COND_EXC:
2608 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2611 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2612 ia64_no_stop (code);
2613 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2616 /* FIXME: Is this needed ? */
2617 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2620 /* FIXME: Is this needed ? */
2621 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2624 /* FIXME: Is this needed ? */
2625 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2628 /* FIXME: Is this needed */
2629 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2632 /* FIXME: Is this needed */
2633 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2636 /* FIXME: Is this needed */
2637 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2641 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2645 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2652 double d = *(double *)ins->inst_p0;
2654 if ((d == 0.0) && (mono_signbit (d) == 0))
2655 ia64_fmov (code, ins->dreg, 0);
2657 ia64_fmov (code, ins->dreg, 1);
2659 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2660 ia64_movl (code, GP_SCRATCH_REG, 0);
2661 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2666 float f = *(float *)ins->inst_p0;
2668 if ((f == 0.0) && (mono_signbit (f) == 0))
2669 ia64_fmov (code, ins->dreg, 0);
2671 ia64_fmov (code, ins->dreg, 1);
2673 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2674 ia64_movl (code, GP_SCRATCH_REG, 0);
2675 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2680 ia64_fmov (code, ins->dreg, ins->sreg1);
2682 case OP_STORER8_MEMBASE_REG:
2683 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2685 case OP_STORER4_MEMBASE_REG:
2686 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2687 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2689 case OP_LOADR8_MEMBASE:
2690 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2692 case OP_LOADR4_MEMBASE:
2693 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2694 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2697 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2698 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2699 ia64_fnorm_s_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_d_sf (code, ins->dreg, ins->dreg, 0);
2706 case OP_LCONV_TO_R8:
2707 /* FIXME: Difference with CEE_CONV_R8 ? */
2708 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2709 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2710 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2712 case OP_LCONV_TO_R4:
2713 /* FIXME: Difference with CEE_CONV_R4 ? */
2714 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2715 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2716 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2718 case OP_FCONV_TO_R4:
2719 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2721 case OP_FCONV_TO_I8:
2722 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2723 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2726 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2729 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2732 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2735 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2739 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2740 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2742 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2743 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2744 /* Positive infinity */
2745 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2746 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2747 /* Negative infinity */
2748 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2749 emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2754 /* ensure ins->sreg1 is not NULL */
2755 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2758 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2759 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2766 call = (MonoCallInst*)ins;
2768 if (ins->flags & MONO_INST_HAS_METHOD)
2769 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2771 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2773 code = emit_move_return_value (cfg, ins, code);
2780 case OP_VOIDCALL_REG:
2781 call = (MonoCallInst*)ins;
2785 * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is
2788 ia64_mov (code, IA64_R8, ins->sreg1);
2789 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2790 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2791 ia64_ld8 (code, IA64_GP, IA64_R8);
2792 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2794 code = emit_move_return_value (cfg, ins, code);
2797 case OP_FCALL_MEMBASE:
2798 case OP_LCALL_MEMBASE:
2799 case OP_VCALL_MEMBASE:
2800 case OP_VOIDCALL_MEMBASE:
2801 case OP_CALL_MEMBASE: {
2802 MonoCallInst *call = (MonoCallInst*)ins;
2807 * There are no membase instructions on ia64, but we can't
2808 * lower this since get_vcall_slot_addr () needs to decode it.
2811 /* Keep this in synch with get_vcall_slot_addr */
2812 ia64_mov (code, IA64_R11, ins->sreg1);
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 if (call->method && ins->inst_offset < 0) {
2822 * This is a possible IMT call so save the IMT method in a global
2823 * register where mono_arch_find_imt_method () and its friends can access
2826 ia64_movl (code, IA64_R9, call->method);
2830 * mono_arch_find_this_arg () needs to find the this argument in a global
2833 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2834 out_reg = cfg->arch.reg_out0;
2835 if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
2837 ia64_mov (code, IA64_R10, out_reg);
2839 ia64_begin_bundle (code);
2840 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2842 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2844 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2847 * This nop will tell get_vcall_slot_addr that this is a virtual
2850 ia64_nop_i (code, 0x12345);
2852 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2854 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2856 code = emit_move_return_value (cfg, ins, code);
2861 * Keep in sync with the code in emit_epilog.
2864 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2867 g_assert (!cfg->method->save_lmf);
2869 /* Load arguments into their original registers */
2870 code = emit_load_volatile_arguments (cfg, code);
2872 if (cfg->arch.stack_alloc_size) {
2873 if (cfg->arch.omit_fp) {
2874 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2875 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2877 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2878 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2882 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2884 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2885 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2887 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2888 ia64_movl (code, GP_SCRATCH_REG, 0);
2889 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2890 ia64_br_cond_reg (code, IA64_B6);
2895 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2901 /* FIXME: Sigaltstack support */
2903 /* keep alignment */
2904 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2905 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2906 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2908 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2910 ia64_mov (code, ins->dreg, IA64_SP);
2912 /* An area at sp is reserved by the ABI for parameter passing */
2913 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2914 if (ia64_is_adds_imm (abi_offset))
2915 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2917 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2918 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2921 if (ins->flags & MONO_INST_INIT) {
2923 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2925 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2928 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2929 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2930 ia64_br_cond_pred (code, 8, -2);
2932 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2934 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2940 ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2941 ia64_ld8 (code, ins->dreg, ins->dreg);
2944 /* Synchronization */
2945 case OP_MEMORY_BARRIER:
2948 case OP_ATOMIC_ADD_IMM_NEW_I4:
2949 g_assert (ins->inst_offset == 0);
2950 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2951 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2953 case OP_ATOMIC_ADD_IMM_NEW_I8:
2954 g_assert (ins->inst_offset == 0);
2955 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2956 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2958 case OP_ATOMIC_EXCHANGE_I4:
2959 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2960 ia64_sxt4 (code, ins->dreg, ins->dreg);
2962 case OP_ATOMIC_EXCHANGE_I8:
2963 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2965 case OP_ATOMIC_ADD_NEW_I4: {
2966 guint8 *label, *buf;
2968 /* From libatomic_ops */
2971 ia64_begin_bundle (code);
2972 label = code.buf + code.nins;
2973 ia64_ld4_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_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2977 ia64_cmp4_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);
2985 case OP_ATOMIC_ADD_NEW_I8: {
2986 guint8 *label, *buf;
2988 /* From libatomic_ops */
2991 ia64_begin_bundle (code);
2992 label = code.buf + code.nins;
2993 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2994 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2995 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2996 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2997 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2998 buf = code.buf + code.nins;
2999 ia64_br_cond_pred (code, 7, 0);
3000 ia64_begin_bundle (code);
3001 ia64_patch (buf, label);
3002 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3006 /* Exception handling */
3007 case OP_CALL_HANDLER:
3009 * Using a call instruction would mess up the register stack, so
3010 * save the return address to a register and use a
3013 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3014 ia64_mov (code, IA64_R15, IA64_R0);
3015 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3016 /* Add the length of OP_CALL_HANDLER */
3017 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3018 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3019 ia64_movl (code, GP_SCRATCH_REG2, 0);
3020 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3021 ia64_br_cond_reg (code, IA64_B6);
3022 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3024 case OP_START_HANDLER: {
3026 * We receive the return address in GP_SCRATCH_REG.
3028 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3031 * R15 determines our caller. It is used since it is writable using
3033 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3034 * R15 != 0 means we are called by call_filter ().
3036 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3037 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3039 ia64_br_cond_pred (code, 6, 6);
3042 * Called by call_filter:
3043 * Allocate a new stack frame, and set the fp register from the
3044 * value passed in by the caller.
3045 * We allocate a similar frame as is done by the prolog, so
3046 * if an exception is thrown while executing the filter, the
3047 * unwinder can unwind through the filter frame using the unwind
3048 * info for the prolog.
3050 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);
3051 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3052 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3053 ia64_mov (code, cfg->frame_reg, IA64_R15);
3054 /* Signal to endfilter that we are called by call_filter */
3055 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3057 /* Save the return address */
3058 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3059 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3060 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3065 case OP_ENDFILTER: {
3066 /* FIXME: Return the value in ENDFILTER */
3067 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3069 /* Load the return address */
3070 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3071 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3074 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3075 ia64_br_cond_pred (code, 7, 4);
3077 /* Called by call_filter */
3079 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3080 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3081 ia64_br_ret_reg (code, IA64_B0);
3083 /* Called by CALL_HANDLER */
3084 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3085 ia64_br_cond_reg (code, IA64_B6);
3089 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3090 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3091 (gpointer)"mono_arch_throw_exception");
3094 * This might be the last instruction in the method, so add a dummy
3095 * instruction so the unwinder will work.
3097 ia64_break_i (code, 0);
3100 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3101 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3102 (gpointer)"mono_arch_rethrow_exception");
3104 ia64_break_i (code, 0);
3108 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3109 g_assert_not_reached ();
3112 if ((code.buf - cfg->native_code - offset) > max_len) {
3113 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3114 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3115 g_assert_not_reached ();
3121 last_offset = offset;
3126 ia64_codegen_close (code);
3128 cfg->code_len = code.buf - cfg->native_code;
3132 mono_arch_register_lowlevel_calls (void)
3134 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3137 static Ia64InsType ins_types_in_template [32][3] = {
3138 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3139 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3140 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3141 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3142 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3143 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3146 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3147 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3148 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3149 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3150 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3151 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3152 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3153 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3154 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3155 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3156 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3157 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3160 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3161 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3162 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3163 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3166 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3167 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3172 static gboolean stops_in_template [32][3] = {
3173 { FALSE, FALSE, FALSE },
3174 { FALSE, FALSE, TRUE },
3175 { FALSE, TRUE, FALSE },
3176 { FALSE, TRUE, TRUE },
3177 { FALSE, FALSE, FALSE },
3178 { FALSE, FALSE, TRUE },
3179 { FALSE, FALSE, FALSE },
3180 { FALSE, FALSE, FALSE },
3182 { FALSE, FALSE, FALSE },
3183 { FALSE, FALSE, TRUE },
3184 { TRUE, FALSE, FALSE },
3185 { TRUE, FALSE, TRUE },
3186 { FALSE, FALSE, FALSE },
3187 { FALSE, FALSE, TRUE },
3188 { FALSE, FALSE, FALSE },
3189 { FALSE, FALSE, TRUE },
3191 { FALSE, FALSE, FALSE },
3192 { FALSE, FALSE, TRUE },
3193 { FALSE, FALSE, FALSE },
3194 { FALSE, FALSE, TRUE },
3195 { FALSE, FALSE, FALSE },
3196 { FALSE, FALSE, FALSE },
3197 { FALSE, FALSE, FALSE },
3198 { FALSE, FALSE, TRUE },
3200 { FALSE, FALSE, FALSE },
3201 { FALSE, FALSE, TRUE },
3202 { FALSE, FALSE, FALSE },
3203 { FALSE, FALSE, FALSE },
3204 { FALSE, FALSE, FALSE },
3205 { FALSE, FALSE, TRUE },
3206 { FALSE, FALSE, FALSE },
3207 { FALSE, FALSE, FALSE }
3210 static int last_stop_in_template [32] = {
3211 -1, 2, 1, 2, -1, 2, -1, -1,
3212 -1, 2, 0, 2, -1, 2, -1, 2,
3213 -1, 2, -1, 2, -1, -1, -1, 2,
3214 -1, 2, -1, -1, -1, 2, -1, -1
3217 static guint64 nops_for_ins_types [6] = {
3226 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3233 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3235 #define DEBUG_INS_SCHED(a)
3239 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3241 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3242 guint8 *deps = code->dep_info;
3243 gboolean need_stop, no_stop;
3245 for (i = 0; i < code->nins; ++i)
3249 current_deps_start = 0;
3250 current_ins_start = 0;
3251 deps_start [ins_index] = current_ins_start;
3254 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3255 while (pos < code->dep_info_pos) {
3257 switch (deps [pos]) {
3258 case IA64_END_OF_INS:
3260 current_ins_start = pos + 2;
3261 deps_start [ins_index] = current_ins_start;
3263 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3268 reg = deps [pos + 1];
3270 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3271 for (i = current_deps_start; i < current_ins_start; i += 2)
3272 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3276 reg = code->dep_info [pos + 1];
3278 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3279 for (i = current_deps_start; i < current_ins_start; i += 2)
3280 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3284 reg = deps [pos + 1];
3286 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3287 for (i = current_deps_start; i < current_ins_start; i += 2)
3288 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3291 case IA64_READ_PR_BRANCH:
3292 reg = deps [pos + 1];
3294 /* Writes to prs by non-float instructions are visible to branches */
3295 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3296 for (i = current_deps_start; i < current_ins_start; i += 2)
3297 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3301 reg = code->dep_info [pos + 1];
3303 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3304 for (i = current_deps_start; i < current_ins_start; i += 2)
3305 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3308 case IA64_WRITE_PR_FLOAT:
3309 reg = code->dep_info [pos + 1];
3311 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3312 for (i = current_deps_start; i < current_ins_start; i += 2)
3313 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3317 reg = deps [pos + 1];
3319 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3320 for (i = current_deps_start; i < current_ins_start; i += 2)
3321 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3325 reg = code->dep_info [pos + 1];
3327 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3328 for (i = current_deps_start; i < current_ins_start; i += 2)
3329 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3332 case IA64_READ_BR_BRANCH:
3333 reg = deps [pos + 1];
3335 /* Writes to brs are visible to branches */
3336 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3339 reg = deps [pos + 1];
3341 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3342 for (i = current_deps_start; i < current_ins_start; i += 2)
3343 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3347 reg = code->dep_info [pos + 1];
3349 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3350 for (i = current_deps_start; i < current_ins_start; i += 2)
3351 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3355 reg = deps [pos + 1];
3357 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3358 for (i = current_deps_start; i < current_ins_start; i += 2)
3359 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3363 reg = code->dep_info [pos + 1];
3365 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3366 for (i = current_deps_start; i < current_ins_start; i += 2)
3367 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3372 * Explicitly indicate that a stop is not required. Useful for
3373 * example when two predicated instructions with negated predicates
3374 * write the same registers.
3379 g_assert_not_reached ();
3383 if (need_stop && !no_stop) {
3384 g_assert (ins_index > 0);
3385 stops [ins_index - 1] = 1;
3387 DEBUG_INS_SCHED (printf ("STOP\n"));
3388 current_deps_start = current_ins_start;
3390 /* Skip remaining deps for this instruction */
3391 while (deps [pos] != IA64_END_OF_INS)
3396 if (code->nins > 0) {
3397 /* No dependency info for the last instruction */
3398 stops [code->nins - 1] = 1;
3401 deps_start [code->nins] = code->dep_info_pos;
3405 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3407 int stop_pos, i, deps_to_shift, dep_shift;
3409 g_assert (n <= code->nins);
3411 // if (n > 1) printf ("FOUND: %ld.\n", template);
3413 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3415 stop_pos = last_stop_in_template [template] + 1;
3419 /* Compute the number of 'real' instructions before the stop */
3420 deps_to_shift = stop_pos;
3421 if (stop_pos >= 3 && (nops & (1 << 2)))
3423 if (stop_pos >= 2 && (nops & (1 << 1)))
3425 if (stop_pos >= 1 && (nops & (1 << 0)))
3429 * We have to keep some dependencies whose instructions have been shifted
3430 * out of the buffer. So nullify the end_of_ins markers in the dependency
3433 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3434 if (code->dep_info [i] == IA64_END_OF_INS)
3435 code->dep_info [i] = IA64_NONE;
3437 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3438 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3439 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3441 dep_shift = deps_start [deps_to_shift];
3442 for (i = 0; i < code->nins + 1 - n; ++i)
3443 deps_start [i] = deps_start [n + i] - dep_shift;
3445 /* Determine the exact positions of instructions with unwind ops */
3446 if (code->unw_op_count) {
3448 int curr_ins, curr_ins_pos;
3451 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3452 for (i = 0; i < 3; ++i) {
3453 if (! (nops & (1 << i))) {
3454 ins_pos [curr_ins] = curr_ins_pos + i;
3459 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3460 if (code->unw_ops_pos [i] < n) {
3461 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3462 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3465 if (code->unw_op_pos < code->unw_op_count)
3466 code->unw_op_pos += n;
3469 if (n == code->nins) {
3474 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3475 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3476 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3482 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3484 int i, ins_type, template, nins_to_emit;
3485 int deps_start [16];
3490 * We implement a simple scheduler which tries to put three instructions
3491 * per bundle, then two, then one.
3493 ia64_analyze_deps (code, deps_start, stops);
3495 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3496 /* Find a suitable template */
3497 for (template = 0; template < 32; ++template) {
3498 if (stops_in_template [template][0] != stops [0] ||
3499 stops_in_template [template][1] != stops [1] ||
3500 stops_in_template [template][2] != stops [2])
3504 for (i = 0; i < 3; ++i) {
3505 ins_type = ins_types_in_template [template][i];
3506 switch (code->itypes [i]) {
3507 case IA64_INS_TYPE_A:
3508 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3511 found &= (ins_type == code->itypes [i]);
3517 found = debug_ins_sched ();
3520 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3526 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3527 /* Wait for more instructions */
3530 /* If it didn't work out, try putting two instructions into one bundle */
3531 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3532 /* Try a nop at the end */
3533 for (template = 0; template < 32; ++template) {
3534 if (stops_in_template [template][0] != stops [0] ||
3535 ((stops_in_template [template][1] != stops [1]) &&
3536 (stops_in_template [template][2] != stops [1])))
3540 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3541 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3544 if (!debug_ins_sched ())
3547 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);
3552 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3553 /* Wait for more instructions */
3556 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3557 /* Try a nop in the middle */
3558 for (template = 0; template < 32; ++template) {
3559 if (((stops_in_template [template][0] != stops [0]) &&
3560 (stops_in_template [template][1] != stops [0])) ||
3561 stops_in_template [template][2] != stops [1])
3564 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3565 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3568 if (!debug_ins_sched ())
3571 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);
3576 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3577 /* Try a nop at the beginning */
3578 for (template = 0; template < 32; ++template) {
3579 if ((stops_in_template [template][1] != stops [0]) ||
3580 (stops_in_template [template][2] != stops [1]))
3583 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3584 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3587 if (!debug_ins_sched ())
3590 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);
3595 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3596 /* Wait for more instructions */
3600 nins_to_emit = code->nins;
3604 while (nins_to_emit > 0) {
3605 if (!debug_ins_sched ())
3607 switch (code->itypes [0]) {
3608 case IA64_INS_TYPE_A:
3610 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3612 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3614 case IA64_INS_TYPE_I:
3616 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3618 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3620 case IA64_INS_TYPE_M:
3622 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3624 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3626 case IA64_INS_TYPE_B:
3628 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3630 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3632 case IA64_INS_TYPE_F:
3634 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3636 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3638 case IA64_INS_TYPE_LX:
3639 if (stops [0] || stops [1])
3640 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3642 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3646 g_assert_not_reached ();
3652 unw_dyn_region_info_t*
3653 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3655 unw_dyn_region_info_t *r;
3657 g_assert (code->nins == 0);
3658 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3659 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3660 r->op_count = code->unw_op_count;
3661 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3662 code->unw_op_count = 0;
3663 code->unw_op_pos = 0;
3664 code->region_start = code->buf;
3670 ia64_patch (unsigned char* code, gpointer target)
3673 guint64 instructions [3];
3674 guint8 gen_buf [16];
3675 Ia64CodegenState gen;
3680 * code encodes both the position inside the buffer and code.nins when
3681 * the instruction was emitted.
3683 ins_to_skip = (guint64)code % 16;
3684 code = (unsigned char*)((guint64)code & ~15);
3687 * Search for the first instruction which is 'patchable', skipping
3688 * ins_to_skip instructions.
3693 template = ia64_bundle_template (code);
3694 instructions [0] = ia64_bundle_ins1 (code);
3695 instructions [1] = ia64_bundle_ins2 (code);
3696 instructions [2] = ia64_bundle_ins3 (code);
3698 ia64_codegen_init (gen, gen_buf);
3701 for (i = 0; i < 3; ++i) {
3702 guint64 ins = instructions [i];
3703 int opcode = ia64_ins_opcode (ins);
3705 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3713 switch (ins_types_in_template [template][i]) {
3714 case IA64_INS_TYPE_A:
3715 case IA64_INS_TYPE_M:
3716 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3718 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3719 instructions [i] = gen.instructions [0];
3725 case IA64_INS_TYPE_B:
3726 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3728 gint64 disp = ((guint8*)target - code) >> 4;
3731 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3733 instructions [i] = gen.instructions [0];
3736 else if (opcode == 5) {
3738 gint64 disp = ((guint8*)target - code) >> 4;
3741 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3742 instructions [i] = gen.instructions [0];
3748 case IA64_INS_TYPE_LX:
3752 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3754 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3755 instructions [1] = gen.instructions [0];
3756 instructions [2] = gen.instructions [1];
3769 ia64_codegen_init (gen, code);
3770 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3780 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3782 MonoJumpInfo *patch_info;
3784 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3785 unsigned char *ip = patch_info->ip.i + code;
3786 const unsigned char *target;
3788 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3790 if (patch_info->type == MONO_PATCH_INFO_NONE)
3792 if (mono_compile_aot) {
3796 ia64_patch (ip, (gpointer)target);
3801 mono_arch_emit_prolog (MonoCompile *cfg)
3803 MonoMethod *method = cfg->method;
3804 MonoMethodSignature *sig;
3806 int alloc_size, pos, i;
3807 Ia64CodegenState code;
3810 sig = mono_method_signature (method);
3813 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
3815 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3817 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3818 cfg->code_size += 1024;
3819 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3820 cfg->code_size += 1024;
3822 cfg->native_code = g_malloc (cfg->code_size);
3824 ia64_codegen_init (code, cfg->native_code);
3826 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3827 if (cfg->param_area)
3828 alloc_size += cfg->param_area;
3832 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3834 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3835 /* Force sp to be saved/restored */
3836 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3838 cfg->arch.stack_alloc_size = alloc_size;
3842 if (method->save_lmf) {
3843 /* No LMF on IA64 */
3848 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3849 ia64_alloc (code, cfg->arch.reg_saved_ar_pfs, cfg->arch.reg_local0 - cfg->arch.reg_in0, cfg->arch.reg_out0 - cfg->arch.reg_local0, cfg->arch.n_out_regs, 0);
3850 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3851 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3853 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3854 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3855 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3856 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3857 ia64_mov (code, cfg->frame_reg, IA64_SP);
3861 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3862 int pagesize = getpagesize ();
3864 if (alloc_size >= pagesize) {
3865 gint32 remaining_size = alloc_size;
3867 /* Generate stack touching code */
3868 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3869 while (remaining_size >= pagesize) {
3870 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3871 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3872 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3873 remaining_size -= pagesize;
3877 if (ia64_is_imm14 (-alloc_size)) {
3878 if (cfg->arch.omit_fp)
3879 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3880 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3883 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3884 if (cfg->arch.omit_fp)
3885 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3886 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3890 ia64_begin_bundle (code);
3892 /* Initialize unwind info */
3893 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3895 if (sig->ret->type != MONO_TYPE_VOID) {
3896 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3897 /* Save volatile arguments to the stack */
3902 /* Keep this in sync with emit_load_volatile_arguments */
3903 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3904 ArgInfo *ainfo = cinfo->args + i;
3905 gint32 stack_offset;
3907 inst = cfg->args [i];
3909 if (sig->hasthis && (i == 0))
3910 arg_type = &mono_defaults.object_class->byval_arg;
3912 arg_type = sig->params [i - sig->hasthis];
3914 arg_type = mono_type_get_underlying_type (arg_type);
3916 stack_offset = ainfo->offset + ARGS_OFFSET;
3918 /* Save volatile arguments to the stack */
3919 if (inst->opcode != OP_REGVAR) {
3920 switch (ainfo->storage) {
3923 g_assert (inst->opcode == OP_REGOFFSET);
3924 if (ia64_is_adds_imm (inst->inst_offset))
3925 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3927 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3928 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3930 if (arg_type->byref)
3931 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3933 switch (arg_type->type) {
3935 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3938 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3941 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3949 if (ainfo->nslots != ainfo->nregs)
3952 g_assert (inst->opcode == OP_REGOFFSET);
3953 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3954 for (i = 0; i < ainfo->nregs; ++i) {
3955 switch (ainfo->atype) {
3956 case AggregateNormal:
3957 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3959 case AggregateSingleHFA:
3960 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3962 case AggregateDoubleHFA:
3963 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3971 g_assert_not_reached ();
3975 if (inst->opcode == OP_REGVAR) {
3976 /* Argument allocated to (non-volatile) register */
3977 switch (ainfo->storage) {
3979 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3980 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3983 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3984 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3992 if (method->save_lmf) {
3993 /* No LMF on IA64 */
3996 ia64_codegen_close (code);
3998 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3999 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4001 cfg->code_len = code.buf - cfg->native_code;
4003 g_assert (cfg->code_len < cfg->code_size);
4005 cfg->arch.prolog_end_offset = cfg->code_len;
4011 mono_arch_emit_epilog (MonoCompile *cfg)
4013 MonoMethod *method = cfg->method;
4015 int max_epilog_size = 16 * 4;
4016 Ia64CodegenState code;
4021 if (mono_jit_trace_calls != NULL)
4022 max_epilog_size += 1024;
4024 cfg->arch.epilog_begin_offset = cfg->code_len;
4026 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4027 cfg->code_size *= 2;
4028 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4029 mono_jit_stats.code_reallocs++;
4032 /* FIXME: Emit unwind info */
4034 buf = cfg->native_code + cfg->code_len;
4036 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4037 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4039 ia64_codegen_init (code, buf);
4041 /* the code restoring the registers must be kept in sync with OP_JMP */
4044 if (method->save_lmf) {
4045 /* No LMF on IA64 */
4048 /* Load returned vtypes into registers if needed */
4049 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4050 ainfo = &cinfo->ret;
4051 switch (ainfo->storage) {
4053 if (ainfo->nslots != ainfo->nregs)
4056 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4057 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4058 for (i = 0; i < ainfo->nregs; ++i) {
4059 switch (ainfo->atype) {
4060 case AggregateNormal:
4061 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4063 case AggregateSingleHFA:
4064 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4066 case AggregateDoubleHFA:
4067 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4070 g_assert_not_reached ();
4078 ia64_begin_bundle (code);
4080 code.region_start = cfg->native_code;
4082 /* Label the unwind state at the start of the exception throwing region */
4083 //ia64_unw_label_state (code, 1234);
4085 if (cfg->arch.stack_alloc_size) {
4086 if (cfg->arch.omit_fp) {
4087 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4088 ia64_unw_pop_frames (code, 1);
4089 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4091 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4092 ia64_unw_pop_frames (code, 1);
4093 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4097 ia64_unw_pop_frames (code, 1);
4098 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4101 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4102 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4103 ia64_br_ret_reg (code, IA64_B0);
4105 ia64_codegen_close (code);
4107 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4108 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4110 cfg->code_len = code.buf - cfg->native_code;
4112 g_assert (cfg->code_len < cfg->code_size);
4116 mono_arch_emit_exceptions (MonoCompile *cfg)
4118 MonoJumpInfo *patch_info;
4120 Ia64CodegenState code;
4121 gboolean empty = TRUE;
4122 //unw_dyn_region_info_t *r_exceptions;
4123 MonoClass *exc_classes [16];
4124 guint8 *exc_throw_start [16], *exc_throw_end [16];
4125 guint32 code_size = 0;
4127 /* Compute needed space */
4128 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4129 if (patch_info->type == MONO_PATCH_INFO_EXC)
4131 if (patch_info->type == MONO_PATCH_INFO_R8)
4132 code_size += 8 + 7; /* sizeof (double) + alignment */
4133 if (patch_info->type == MONO_PATCH_INFO_R4)
4134 code_size += 4 + 7; /* sizeof (float) + alignment */
4140 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4141 cfg->code_size *= 2;
4142 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4143 mono_jit_stats.code_reallocs++;
4146 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4148 /* The unwind state here is the same as before the epilog */
4149 //ia64_unw_copy_state (code, 1234);
4151 /* add code to raise exceptions */
4152 /* FIXME: Optimize this */
4154 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4155 switch (patch_info->type) {
4156 case MONO_PATCH_INFO_EXC: {
4157 MonoClass *exc_class;
4160 guint64 exc_token_index;
4162 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4163 g_assert (exc_class);
4164 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4165 throw_ip = cfg->native_code + patch_info->ip.i;
4167 ia64_begin_bundle (code);
4169 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4171 /* Find a throw sequence for the same exception class */
4172 for (i = 0; i < nthrows; ++i)
4173 if (exc_classes [i] == exc_class)
4177 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4179 if (ia64_is_adds_imm (offset))
4180 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4182 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4184 buf = code.buf + code.nins;
4185 ia64_br_cond_pred (code, 0, 0);
4186 ia64_begin_bundle (code);
4187 ia64_patch (buf, exc_throw_start [i]);
4189 patch_info->type = MONO_PATCH_INFO_NONE;
4194 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4196 ia64_begin_bundle (code);
4199 exc_classes [nthrows] = exc_class;
4200 exc_throw_start [nthrows] = code.buf;
4204 if (ia64_is_adds_imm (exc_token_index))
4205 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4207 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4209 patch_info->data.name = "mono_arch_throw_corlib_exception";
4210 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4211 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4214 ia64_movl (code, GP_SCRATCH_REG, 0);
4215 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4216 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4217 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4219 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4221 /* Patch up the throw offset */
4222 ia64_begin_bundle (code);
4224 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4227 exc_throw_end [nthrows] = code.buf;
4241 /* The unwinder needs this to work */
4242 ia64_break_i (code, 0);
4244 ia64_codegen_close (code);
4247 //r_exceptions = mono_ia64_create_unwind_region (&code);
4248 //cfg->arch.r_epilog = r_exceptions;
4250 cfg->code_len = code.buf - cfg->native_code;
4252 g_assert (cfg->code_len < cfg->code_size);
4256 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4258 Ia64CodegenState code;
4259 CallInfo *cinfo = NULL;
4260 MonoMethodSignature *sig;
4262 int i, n, stack_area = 0;
4264 ia64_codegen_init (code, p);
4266 /* Keep this in sync with mono_arch_get_argument_info */
4268 if (enable_arguments) {
4269 /* Allocate a new area on the stack and save arguments there */
4270 sig = mono_method_signature (cfg->method);
4272 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4274 n = sig->param_count + sig->hasthis;
4276 stack_area = ALIGN_TO (n * 8, 16);
4279 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4281 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4283 /* FIXME: Allocate out registers */
4285 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4287 /* Required by the ABI */
4288 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4290 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4291 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4293 /* Save arguments to the stack */
4294 for (i = 0; i < n; ++i) {
4295 ins = cfg->args [i];
4297 if (ins->opcode == OP_REGVAR) {
4298 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4299 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4300 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4303 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4304 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4305 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4306 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4307 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4308 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4313 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4316 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4318 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4319 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4321 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4323 if (enable_arguments && stack_area) {
4324 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4326 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4328 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4331 ia64_codegen_close (code);
4337 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4339 Ia64CodegenState code;
4340 CallInfo *cinfo = NULL;
4341 MonoMethod *method = cfg->method;
4342 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4344 ia64_codegen_init (code, p);
4346 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4348 /* Save return value + pass it to func */
4349 switch (cinfo->ret.storage) {
4353 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4354 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4357 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4358 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4359 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4360 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4362 case ArgValuetypeAddrInIReg:
4363 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4372 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4373 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4374 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4376 /* Restore return value */
4377 switch (cinfo->ret.storage) {
4381 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4384 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4385 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4387 case ArgValuetypeAddrInIReg:
4395 ia64_codegen_close (code);
4401 mono_arch_save_unwind_info (MonoCompile *cfg)
4405 /* FIXME: Unregister this for dynamic methods */
4407 di = g_malloc0 (sizeof (unw_dyn_info_t));
4408 di->start_ip = (unw_word_t) cfg->native_code;
4409 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4411 di->format = UNW_INFO_FORMAT_DYNAMIC;
4412 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4413 di->u.pi.regions = cfg->arch.r_pro;
4415 _U_dyn_register (di);
4419 unw_dyn_region_info_t *region = di->u.pi.regions;
4421 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4423 printf (" [Region: %d]\n", region->insn_count);
4424 region = region->next;
4431 mono_arch_flush_icache (guint8 *code, gint size)
4433 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4434 guint8* end = (guint8*)((guint64)code + size);
4436 #ifdef __INTEL_COMPILER
4437 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4444 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4445 /* FIXME: This could be increased to 128 on some cpus */
4452 mono_arch_flush_register_windows (void)
4454 /* Not needed because of libunwind */
4458 mono_arch_is_inst_imm (gint64 imm)
4460 /* The lowering pass will take care of it */
4466 * Determine whenever the trap whose info is in SIGINFO is caused by
4470 mono_arch_is_int_overflow (void *sigctx, void *info)
4472 /* Division is emulated with explicit overflow checks */
4477 mono_arch_get_patch_offset (guint8 *code)
4485 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4487 guint8 *bundle2 = code - 48;
4488 guint8 *bundle3 = code - 32;
4489 guint8 *bundle4 = code - 16;
4490 guint64 ins21 = ia64_bundle_ins1 (bundle2);
4491 guint64 ins22 = ia64_bundle_ins2 (bundle2);
4492 guint64 ins23 = ia64_bundle_ins3 (bundle2);
4493 guint64 ins31 = ia64_bundle_ins1 (bundle3);
4494 guint64 ins32 = ia64_bundle_ins2 (bundle3);
4495 guint64 ins33 = ia64_bundle_ins3 (bundle3);
4496 guint64 ins41 = ia64_bundle_ins1 (bundle4);
4497 guint64 ins42 = ia64_bundle_ins2 (bundle4);
4498 guint64 ins43 = ia64_bundle_ins3 (bundle4);
4501 * Virtual calls are made with:
4503 * [MII] ld8 r31=[r8]
4507 * mov.sptk b6=r31,0x2000000000f32a80
4514 * br.call.sptk.few b0=b6;;
4517 if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4518 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4519 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4520 (ins31 == IA64_NOP_M) &&
4521 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4522 (ins33 == IA64_NOP_I) &&
4523 (ins41 == IA64_NOP_M) &&
4524 (ins42 == IA64_NOP_I) &&
4525 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4526 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4527 g_assert (ins21 == IA64_NOP_M);
4528 g_assert (ins23 == IA64_NOP_I);
4529 g_assert (ia64_ins_opcode (ins22) == 0);
4530 g_assert (ia64_ins_x3 (ins22) == 7);
4531 g_assert (ia64_ins_x (ins22) == 0);
4532 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4534 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4536 return regs [IA64_R11];
4543 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4547 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4550 return (gpointer*)(gpointer)((char*)vt + displacement);
4554 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4561 static gboolean tls_offset_inited = FALSE;
4564 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4566 if (!tls_offset_inited) {
4567 tls_offset_inited = TRUE;
4569 appdomain_tls_offset = mono_domain_get_tls_offset ();
4570 thread_tls_offset = mono_thread_get_tls_offset ();
4575 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4580 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4582 MonoCallInst *call = (MonoCallInst*)inst;
4583 int out_reg = cfg->arch.reg_out0;
4586 CallInfo * cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
4589 if (cinfo->ret.storage == ArgAggregate) {
4590 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4593 * The valuetype is in registers after the call, need to be copied
4594 * to the stack. Save the address to a local here, so the call
4595 * instruction can access it.
4597 g_assert (local->opcode == OP_REGOFFSET);
4598 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4601 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4602 vtarg->sreg1 = vt_reg;
4603 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4604 mono_bblock_add_inst (cfg->cbb, vtarg);
4606 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4612 /* add the this argument */
4613 if (this_reg != -1) {
4615 MONO_INST_NEW (cfg, this, OP_MOVE);
4616 this->type = this_type;
4617 this->sreg1 = this_reg;
4618 this->dreg = mono_regstate_next_int (cfg->rs);
4619 mono_bblock_add_inst (cfg->cbb, this);
4621 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4626 #ifdef MONO_ARCH_HAVE_IMT
4629 * LOCKING: called with the domain lock held
4632 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4636 guint8 *start, *buf;
4637 Ia64CodegenState code;
4640 buf = g_malloc0 (size);
4641 ia64_codegen_init (code, buf);
4643 /* IA64_R9 contains the IMT method */
4645 for (i = 0; i < count; ++i) {
4646 MonoIMTCheckItem *item = imt_entries [i];
4647 ia64_begin_bundle (code);
4648 item->code_target = (guint8*)code.buf + code.nins;
4649 if (item->is_equals) {
4650 if (item->check_target_idx) {
4651 if (!item->compare_done) {
4652 ia64_movl (code, GP_SCRATCH_REG, item->method);
4653 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4655 item->jmp_code = (guint8*)code.buf + code.nins;
4656 ia64_br_cond_pred (code, 7, 0);
4658 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4659 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4660 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4661 ia64_br_cond_reg (code, IA64_B6);
4663 /* enable the commented code to assert on wrong method */
4664 #if ENABLE_WRONG_METHOD_CHECK
4665 g_assert_not_reached ();
4667 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4668 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4669 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4670 ia64_br_cond_reg (code, IA64_B6);
4671 #if ENABLE_WRONG_METHOD_CHECK
4672 g_assert_not_reached ();
4676 ia64_movl (code, GP_SCRATCH_REG, item->method);
4677 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4678 item->jmp_code = (guint8*)code.buf + code.nins;
4679 ia64_br_cond_pred (code, 6, 0);
4682 /* patch the branches to get to the target items */
4683 for (i = 0; i < count; ++i) {
4684 MonoIMTCheckItem *item = imt_entries [i];
4685 if (item->jmp_code) {
4686 if (item->check_target_idx) {
4687 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4692 ia64_codegen_close (code);
4693 g_assert (code.buf - buf <= size);
4695 size = code.buf - buf;
4696 start = mono_code_manager_reserve (domain->code_mp, size);
4697 memcpy (start, buf, size);
4699 mono_arch_flush_icache (start, size);
4701 mono_stats.imt_thunks_size += size;
4707 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4709 return regs [IA64_R9];
4713 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
4715 return regs [IA64_R10];
4719 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
4721 /* Done by the implementation of the CALL_MEMBASE opcodes */
4726 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4728 MonoInst *ins = NULL;
4730 if(cmethod->klass->image == mono_defaults.corlib &&
4731 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4732 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4734 * We don't use the generic version in mini_get_inst_for_method () since the
4735 * ia64 has atomic_add_imm opcodes.
4737 if (strcmp (cmethod->name, "Increment") == 0) {
4740 if (fsig->params [0]->type == MONO_TYPE_I4)
4741 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4742 else if (fsig->params [0]->type == MONO_TYPE_I8)
4743 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4745 g_assert_not_reached ();
4746 MONO_INST_NEW (cfg, ins, opcode);
4748 ins->inst_i0 = args [0];
4749 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4752 if (fsig->params [0]->type == MONO_TYPE_I4)
4753 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4754 else if (fsig->params [0]->type == MONO_TYPE_I8)
4755 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4757 g_assert_not_reached ();
4758 MONO_INST_NEW (cfg, ins, opcode);
4760 ins->inst_i0 = args [0];
4761 } else if (strcmp (cmethod->name, "Add") == 0) {
4764 if (fsig->params [0]->type == MONO_TYPE_I4)
4765 opcode = OP_ATOMIC_ADD_NEW_I4;
4766 else if (fsig->params [0]->type == MONO_TYPE_I8)
4767 opcode = OP_ATOMIC_ADD_NEW_I8;
4769 g_assert_not_reached ();
4771 MONO_INST_NEW (cfg, ins, opcode);
4773 ins->inst_i0 = args [0];
4774 ins->inst_i1 = args [1];
4782 mono_arch_print_tree (MonoInst *tree, int arity)
4787 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4791 if (appdomain_tls_offset == -1)
4794 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4795 ins->inst_offset = appdomain_tls_offset;
4799 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4803 if (thread_tls_offset == -1)
4806 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4807 ins->inst_offset = thread_tls_offset;