3 * IA64 backend for the Mono code generator
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2003 Ximian, Inc.
16 #ifdef __INTEL_COMPILER
17 #include <ia64intrin.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/utils/mono-math.h>
25 #include <mono/utils/mono-hwcap.h>
28 #include "mini-ia64.h"
30 #include "jit-icalls.h"
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 static const char* gregs [] = {
65 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
66 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
67 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
68 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
69 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
70 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
71 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
72 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
73 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
74 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
75 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
76 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
77 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
81 mono_arch_regname (int reg)
89 static const char* fregs [] = {
90 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
91 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
92 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
93 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
94 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
95 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
96 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
97 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
98 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
99 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
100 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
101 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
102 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
106 mono_arch_fregname (int reg)
115 debug_ins_sched (void)
118 return mono_debug_count ();
128 return mono_debug_count ();
135 ia64_patch (unsigned char* code, gpointer target);
142 ArgValuetypeAddrInIReg,
160 /* Only if storage == ArgAggregate */
170 gboolean need_stack_align;
171 gboolean vtype_retaddr;
172 /* The index of the vret arg in the argument list */
179 #define DEBUG(a) if (cfg->verbose_level > 1) a
184 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
186 ainfo->offset = *stack_size;
188 if (*gr >= PARAM_REGS) {
189 ainfo->storage = ArgOnStack;
190 (*stack_size) += sizeof (gpointer);
193 ainfo->storage = ArgInIReg;
199 #define FLOAT_PARAM_REGS 8
202 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
204 ainfo->offset = *stack_size;
206 if (*gr >= PARAM_REGS) {
207 ainfo->storage = ArgOnStack;
208 (*stack_size) += sizeof (gpointer);
211 ainfo->storage = is_double ? ArgInFloatReg : ArgInFloatRegR4;
212 ainfo->reg = 8 + *fr;
219 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
221 guint32 *gr, guint32 *fr, guint32 *stack_size)
225 MonoMarshalType *info;
226 gboolean is_hfa = TRUE;
227 guint32 hfa_type = 0;
229 klass = mono_class_from_mono_type (type);
230 if (type->type == MONO_TYPE_TYPEDBYREF)
231 size = 3 * sizeof (gpointer);
232 else if (sig->pinvoke)
233 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
235 size = mini_type_stack_size (&klass->byval_arg, NULL);
237 if (!sig->pinvoke || (size == 0)) {
238 /* Allways pass in memory */
239 ainfo->offset = *stack_size;
240 *stack_size += ALIGN_TO (size, 8);
241 ainfo->storage = ArgOnStack;
246 /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
247 info = mono_marshal_load_type_info (klass);
249 for (i = 0; i < info->num_fields; ++i) {
250 guint32 ftype = info->fields [i].field->type->type;
251 if (!(info->fields [i].field->type->byref) &&
252 ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
255 else if (hfa_type != ftype)
264 ainfo->storage = ArgAggregate;
265 ainfo->atype = AggregateNormal;
268 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
270 if (info->num_fields <= 8) {
272 ainfo->nregs = info->num_fields;
273 ainfo->nslots = ainfo->nregs;
279 if ((*fr) + info->num_fields > 8)
282 ainfo->reg = 8 + (*fr);
283 ainfo->nregs = info->num_fields;
284 ainfo->nslots = ainfo->nregs;
285 (*fr) += info->num_fields;
286 if (ainfo->atype == AggregateSingleHFA) {
288 * FIXME: Have to keep track of the parameter slot number, which is
289 * not the same as *gr.
291 (*gr) += ALIGN_TO (info->num_fields, 2) / 2;
293 (*gr) += info->num_fields;
299 /* This also handles returning of TypedByRef used by some icalls */
302 ainfo->reg = IA64_R8;
303 ainfo->nregs = (size + 7) / 8;
304 ainfo->nslots = ainfo->nregs;
311 ainfo->offset = *stack_size;
312 ainfo->nslots = (size + 7) / 8;
314 if (((*gr) + ainfo->nslots) <= 8) {
315 /* Fits entirely in registers */
316 ainfo->nregs = ainfo->nslots;
317 (*gr) += ainfo->nregs;
321 ainfo->nregs = 8 - (*gr);
323 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
329 * Obtain information about a call according to the calling convention.
330 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
331 * Gude" document for more information.
334 get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
336 guint32 i, gr, fr, pstart;
338 int n = sig->hasthis + sig->param_count;
339 guint32 stack_size = 0;
343 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
345 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
352 ret_type = mini_get_underlying_type (sig->ret);
353 switch (ret_type->type) {
363 case MONO_TYPE_FNPTR:
364 case MONO_TYPE_OBJECT:
365 cinfo->ret.storage = ArgInIReg;
366 cinfo->ret.reg = IA64_R8;
370 cinfo->ret.storage = ArgInIReg;
371 cinfo->ret.reg = IA64_R8;
375 cinfo->ret.storage = ArgInFloatReg;
378 case MONO_TYPE_GENERICINST:
379 if (!mono_type_generic_inst_is_valuetype (ret_type)) {
380 cinfo->ret.storage = ArgInIReg;
381 cinfo->ret.reg = IA64_R8;
385 case MONO_TYPE_VALUETYPE:
386 case MONO_TYPE_TYPEDBYREF: {
387 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
389 if (sig->ret->byref) {
390 /* This seems to happen with ldfld wrappers */
391 cinfo->ret.storage = ArgInIReg;
393 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
394 if (cinfo->ret.storage == ArgOnStack) {
395 /* The caller passes the address where the value is stored */
396 cinfo->vtype_retaddr = TRUE;
402 cinfo->ret.storage = ArgNone;
405 g_error ("Can't handle as return value 0x%x", sig->ret->type);
411 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
412 * the first argument, allowing 'this' to be always passed in the first arg reg.
413 * Also do this if the first argument is a reference type, since virtual calls
414 * are sometimes made using calli without sig->hasthis set, like in the delegate
417 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
419 add_general (&gr, &stack_size, cinfo->args + 0);
421 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
424 add_general (&gr, &stack_size, &cinfo->ret);
425 if (cinfo->ret.storage == ArgInIReg)
426 cinfo->ret.storage = ArgValuetypeAddrInIReg;
427 cinfo->vret_arg_index = 1;
431 add_general (&gr, &stack_size, cinfo->args + 0);
433 if (cinfo->vtype_retaddr) {
434 add_general (&gr, &stack_size, &cinfo->ret);
435 if (cinfo->ret.storage == ArgInIReg)
436 cinfo->ret.storage = ArgValuetypeAddrInIReg;
440 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
442 fr = FLOAT_PARAM_REGS;
444 /* Emit the signature cookie just before the implicit arguments */
445 add_general (&gr, &stack_size, &cinfo->sig_cookie);
448 for (i = pstart; i < sig->param_count; ++i) {
449 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
452 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
453 /* We allways pass the sig cookie on the stack for simplicity */
455 * Prevent implicit arguments + the sig cookie from being passed
459 fr = FLOAT_PARAM_REGS;
461 /* Emit the signature cookie just before the implicit arguments */
462 add_general (&gr, &stack_size, &cinfo->sig_cookie);
465 if (sig->params [i]->byref) {
466 add_general (&gr, &stack_size, ainfo);
469 ptype = mini_get_underlying_type (sig->params [i]);
470 switch (ptype->type) {
471 case MONO_TYPE_BOOLEAN:
474 add_general (&gr, &stack_size, ainfo);
479 add_general (&gr, &stack_size, ainfo);
483 add_general (&gr, &stack_size, ainfo);
488 case MONO_TYPE_FNPTR:
489 case MONO_TYPE_CLASS:
490 case MONO_TYPE_OBJECT:
491 case MONO_TYPE_STRING:
492 case MONO_TYPE_SZARRAY:
493 case MONO_TYPE_ARRAY:
494 add_general (&gr, &stack_size, ainfo);
496 case MONO_TYPE_GENERICINST:
497 if (!mono_type_generic_inst_is_valuetype (ptype)) {
498 add_general (&gr, &stack_size, ainfo);
502 case MONO_TYPE_VALUETYPE:
503 case MONO_TYPE_TYPEDBYREF:
505 /* We allways pass valuetypes on the stack */
506 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
510 add_general (&gr, &stack_size, ainfo);
513 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
516 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
519 g_assert_not_reached ();
523 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
525 fr = FLOAT_PARAM_REGS;
527 /* Emit the signature cookie just before the implicit arguments */
528 add_general (&gr, &stack_size, &cinfo->sig_cookie);
531 cinfo->stack_usage = stack_size;
532 cinfo->reg_usage = gr;
533 cinfo->freg_usage = fr;
538 * mono_arch_get_argument_info:
539 * @csig: a method signature
540 * @param_count: the number of parameters to consider
541 * @arg_info: an array to store the result infos
543 * Gathers information on parameters such as size, alignment and
544 * padding. arg_info should be large enought to hold param_count + 1 entries.
546 * Returns the size of the argument area on the stack.
549 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
552 CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
553 guint32 args_size = cinfo->stack_usage;
555 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
557 arg_info [0].offset = 0;
560 for (k = 0; k < param_count; k++) {
561 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
563 arg_info [k + 1].size = 0;
572 * Initialize the cpu to execute managed code.
575 mono_arch_cpu_init (void)
580 * Initialize architecture specific code.
583 mono_arch_init (void)
588 * Cleanup architecture specific code.
591 mono_arch_cleanup (void)
596 mono_arch_have_fast_tls (void)
602 * This function returns the optimizations supported on this cpu.
605 mono_arch_cpu_optimizations (guint32 *exclude_mask)
613 * This function test for all SIMD functions supported.
615 * Returns a bitmask corresponding to all supported versions.
619 mono_arch_cpu_enumerate_simd_versions (void)
621 /* SIMD is currently unimplemented */
626 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
630 MonoMethodSignature *sig;
631 MonoMethodHeader *header;
634 header = cfg->header;
636 sig = mono_method_signature (cfg->method);
638 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
640 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
641 MonoInst *ins = cfg->args [i];
643 ArgInfo *ainfo = &cinfo->args [i];
645 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
648 if (ainfo->storage == ArgInIReg) {
649 /* The input registers are non-volatile */
650 ins->opcode = OP_REGVAR;
651 ins->dreg = 32 + ainfo->reg;
655 for (i = 0; i < cfg->num_varinfo; i++) {
656 MonoInst *ins = cfg->varinfo [i];
657 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
660 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
663 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
664 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
667 if (mono_is_regsize_var (ins->inst_vtype)) {
668 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
669 g_assert (i == vmv->idx);
670 vars = g_list_prepend (vars, vmv);
674 vars = mono_varlist_sort (cfg, vars, 0);
680 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
683 guint32 reserved_regs;
684 MonoMethodHeader *header;
686 if (cfg->arch.reg_local0 > 0)
690 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
692 header = cfg->header;
694 /* Some registers are reserved for use by the prolog/epilog */
695 reserved_regs = header->num_clauses ? 4 : 3;
697 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
698 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
699 /* One registers is needed by instrument_epilog to save the return value */
701 if (cinfo->reg_usage < 2)
702 /* Number of arguments passed to function call in instrument_prolog */
703 cinfo->reg_usage = 2;
706 cfg->arch.reg_in0 = 32;
707 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
708 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
710 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
711 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
712 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
715 * Frames without handlers save sp to fp, frames with handlers save it into
716 * a dedicated register.
718 if (header->num_clauses)
719 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
721 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
723 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
724 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
725 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
729 * Need to allocate at least 2 out register for use by OP_THROW / the system
730 * exception throwing code.
732 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
736 mono_arch_get_global_int_regs (MonoCompile *cfg)
741 mono_ia64_alloc_stacked_registers (cfg);
743 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
746 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
753 * mono_arch_regalloc_cost:
755 * Return the cost, in number of memory references, of the action of
756 * allocating the variable VMV into a register during global register
760 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
762 /* FIXME: Increase costs linearly to avoid using all local registers */
768 mono_arch_allocate_vars (MonoCompile *cfg)
770 MonoMethodSignature *sig;
771 MonoMethodHeader *header;
774 guint32 locals_stack_size, locals_stack_align;
778 header = cfg->header;
780 sig = mono_method_signature (cfg->method);
782 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
785 * Determine whenever the frame pointer can be eliminated.
786 * FIXME: Remove some of the restrictions.
788 cfg->arch.omit_fp = TRUE;
790 if (!debug_omit_fp ())
791 cfg->arch.omit_fp = FALSE;
793 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
794 cfg->arch.omit_fp = FALSE;
795 if (header->num_clauses)
796 cfg->arch.omit_fp = FALSE;
798 cfg->arch.omit_fp = FALSE;
799 if ((sig->ret->type != MONO_TYPE_VOID) && (cinfo->ret.storage == ArgAggregate))
800 cfg->arch.omit_fp = FALSE;
801 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
802 cfg->arch.omit_fp = FALSE;
803 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
804 ArgInfo *ainfo = &cinfo->args [i];
806 if (ainfo->storage == ArgOnStack) {
808 * The stack offset can only be determined when the frame
811 cfg->arch.omit_fp = FALSE;
815 mono_ia64_alloc_stacked_registers (cfg);
818 * We use the ABI calling conventions for managed code as well.
819 * Exception: valuetypes are never passed or returned in registers.
822 if (cfg->arch.omit_fp) {
823 cfg->flags |= MONO_CFG_HAS_SPILLUP;
824 cfg->frame_reg = IA64_SP;
825 offset = ARGS_OFFSET;
828 /* Locals are allocated backwards from %fp */
829 cfg->frame_reg = cfg->arch.reg_fp;
833 if (cfg->method->save_lmf) {
837 if (sig->ret->type != MONO_TYPE_VOID) {
838 switch (cinfo->ret.storage) {
840 cfg->ret->opcode = OP_REGVAR;
841 cfg->ret->inst_c0 = cinfo->ret.reg;
844 cfg->ret->opcode = OP_REGVAR;
845 cfg->ret->inst_c0 = cinfo->ret.reg;
847 case ArgValuetypeAddrInIReg:
848 cfg->vret_addr->opcode = OP_REGVAR;
849 cfg->vret_addr->dreg = cfg->arch.reg_in0 + cinfo->ret.reg;
852 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
853 if (cfg->arch.omit_fp)
854 g_assert_not_reached ();
855 offset = ALIGN_TO (offset, 8);
856 offset += cinfo->ret.nslots * 8;
857 cfg->ret->opcode = OP_REGOFFSET;
858 cfg->ret->inst_basereg = cfg->frame_reg;
859 cfg->ret->inst_offset = - offset;
862 g_assert_not_reached ();
864 cfg->ret->dreg = cfg->ret->inst_c0;
867 /* Allocate locals */
868 offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
869 if (locals_stack_align) {
870 offset = ALIGN_TO (offset, locals_stack_align);
872 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
873 if (offsets [i] != -1) {
874 MonoInst *inst = cfg->varinfo [i];
875 inst->opcode = OP_REGOFFSET;
876 inst->inst_basereg = cfg->frame_reg;
877 if (cfg->arch.omit_fp)
878 inst->inst_offset = (offset + offsets [i]);
880 inst->inst_offset = - (offset + offsets [i]);
881 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
884 offset += locals_stack_size;
886 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
887 if (cfg->arch.omit_fp)
888 g_assert_not_reached ();
889 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
890 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
893 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
894 inst = cfg->args [i];
895 if (inst->opcode != OP_REGVAR) {
896 ArgInfo *ainfo = &cinfo->args [i];
897 gboolean inreg = TRUE;
900 if (sig->hasthis && (i == 0))
901 arg_type = &mono_defaults.object_class->byval_arg;
903 arg_type = sig->params [i - sig->hasthis];
905 /* FIXME: VOLATILE is only set if the liveness pass runs */
906 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
909 inst->opcode = OP_REGOFFSET;
911 switch (ainfo->storage) {
913 inst->opcode = OP_REGVAR;
914 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
917 case ArgInFloatRegR4:
919 * Since float regs are volatile, we save the arguments to
920 * the stack in the prolog.
925 if (cfg->arch.omit_fp)
926 g_assert_not_reached ();
927 inst->opcode = OP_REGOFFSET;
928 inst->inst_basereg = cfg->frame_reg;
929 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
938 if (!inreg && (ainfo->storage != ArgOnStack)) {
941 inst->opcode = OP_REGOFFSET;
942 inst->inst_basereg = cfg->frame_reg;
943 /* These arguments are saved to the stack in the prolog */
944 switch (ainfo->storage) {
946 if (ainfo->atype == AggregateSingleHFA)
947 size = ainfo->nslots * 4;
949 size = ainfo->nslots * 8;
952 size = sizeof (gpointer);
956 offset = ALIGN_TO (offset, sizeof (gpointer));
958 if (cfg->arch.omit_fp) {
959 inst->inst_offset = offset;
963 inst->inst_offset = - offset;
970 * FIXME: This doesn't work because some variables are allocated during local
974 if (cfg->arch.omit_fp && offset == 16)
978 cfg->stack_offset = offset;
982 mono_arch_create_vars (MonoCompile *cfg)
984 MonoMethodSignature *sig;
987 sig = mono_method_signature (cfg->method);
989 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
991 if (cinfo->ret.storage == ArgAggregate)
992 cfg->ret_var_is_local = TRUE;
993 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
994 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
995 if (G_UNLIKELY (cfg->verbose_level > 1)) {
996 printf ("vret_addr = ");
997 mono_print_ins (cfg->vret_addr);
1003 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
1007 MONO_INST_NEW (cfg, arg, OP_NOP);
1008 arg->sreg1 = tree->dreg;
1012 arg->opcode = OP_MOVE;
1013 arg->dreg = mono_alloc_ireg (cfg);
1015 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, FALSE);
1018 arg->opcode = OP_FMOVE;
1019 arg->dreg = mono_alloc_freg (cfg);
1021 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1023 case ArgInFloatRegR4:
1024 arg->opcode = OP_FCONV_TO_R4;
1025 arg->dreg = mono_alloc_freg (cfg);
1027 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1030 g_assert_not_reached ();
1033 MONO_ADD_INS (cfg->cbb, arg);
1037 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1039 MonoMethodSignature *tmp_sig;
1041 /* Emit the signature cookie just before the implicit arguments */
1043 /* FIXME: Add support for signature tokens to AOT */
1044 cfg->disable_aot = TRUE;
1046 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1049 * mono_ArgIterator_Setup assumes the signature cookie is
1050 * passed first and all the arguments which were before it are
1051 * passed on the stack after the signature. So compensate by
1052 * passing a different signature.
1054 tmp_sig = mono_metadata_signature_dup (call->signature);
1055 tmp_sig->param_count -= call->signature->sentinelpos;
1056 tmp_sig->sentinelpos = 0;
1057 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1059 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1060 sig_arg->dreg = mono_alloc_ireg (cfg);
1061 sig_arg->inst_p0 = tmp_sig;
1062 MONO_ADD_INS (cfg->cbb, sig_arg);
1064 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + cinfo->sig_cookie.offset, sig_arg->dreg);
1068 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1071 MonoMethodSignature *sig;
1072 int i, n, stack_size;
1078 mono_ia64_alloc_stacked_registers (cfg);
1080 sig = call->signature;
1081 n = sig->param_count + sig->hasthis;
1083 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1085 if (cinfo->ret.storage == ArgAggregate) {
1090 * The valuetype is in registers after the call, need to be copied
1091 * to the stack. Save the address to a local here, so the call
1092 * instruction can access it.
1094 local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1095 local->flags |= MONO_INST_VOLATILE;
1096 cfg->arch.ret_var_addr_local = local;
1098 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1099 vtarg->sreg1 = call->vret_var->dreg;
1100 vtarg->dreg = local->dreg;
1101 MONO_ADD_INS (cfg->cbb, vtarg);
1104 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
1105 add_outarg_reg (cfg, call, ArgInIReg, cfg->arch.reg_out0 + cinfo->ret.reg, call->vret_var);
1108 for (i = 0; i < n; ++i) {
1111 ainfo = cinfo->args + i;
1113 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1114 /* Emit the signature cookie just before the implicit arguments */
1115 emit_sig_cookie (cfg, call, cinfo);
1118 in = call->args [i];
1120 if (sig->hasthis && (i == 0))
1121 arg_type = &mono_defaults.object_class->byval_arg;
1123 arg_type = sig->params [i - sig->hasthis];
1125 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1129 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1130 size = sizeof (MonoTypedRef);
1131 align = sizeof (gpointer);
1133 else if (sig->pinvoke)
1134 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1137 * Other backends use mono_type_stack_size (), but that
1138 * aligns the size to 8, which is larger than the size of
1139 * the source, leading to reads of invalid memory if the
1140 * source is at the end of address space.
1142 size = mono_class_value_size (in->klass, &align);
1148 MONO_INST_NEW (cfg, arg, OP_OUTARG_VT);
1149 arg->sreg1 = in->dreg;
1150 arg->klass = in->klass;
1151 arg->backend.size = size;
1152 arg->inst_p0 = call;
1153 arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1154 memcpy (arg->inst_p1, ainfo, sizeof (ArgInfo));
1156 MONO_ADD_INS (cfg->cbb, arg);
1160 switch (ainfo->storage) {
1162 add_outarg_reg (cfg, call, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1165 case ArgInFloatRegR4:
1166 add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, in);
1169 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref)
1170 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1171 else if (arg_type->type == MONO_TYPE_R8 && !arg_type->byref)
1172 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1174 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1177 g_assert_not_reached ();
1182 /* Handle the case where there are no implicit arguments */
1183 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1184 emit_sig_cookie (cfg, call, cinfo);
1187 call->stack_usage = cinfo->stack_usage;
1188 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1192 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1194 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1195 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1196 int size = ins->backend.size;
1198 if (ainfo->storage == ArgAggregate) {
1199 MonoInst *load, *store;
1203 * Part of the structure is passed in registers.
1205 for (i = 0; i < ainfo->nregs; ++i) {
1206 slot = ainfo->reg + i;
1208 if (ainfo->atype == AggregateSingleHFA) {
1209 MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
1210 load->inst_basereg = src->dreg;
1211 load->inst_offset = i * 4;
1212 load->dreg = mono_alloc_freg (cfg);
1214 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1215 } else if (ainfo->atype == AggregateDoubleHFA) {
1216 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1217 load->inst_basereg = src->dreg;
1218 load->inst_offset = i * 8;
1219 load->dreg = mono_alloc_freg (cfg);
1221 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1223 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1224 load->inst_basereg = src->dreg;
1225 load->inst_offset = i * 8;
1226 load->dreg = mono_alloc_ireg (cfg);
1228 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, cfg->arch.reg_out0 + ainfo->reg + i, FALSE);
1230 MONO_ADD_INS (cfg->cbb, load);
1234 * Part of the structure is passed on the stack.
1236 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1237 slot = ainfo->reg + i;
1239 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1240 load->inst_basereg = src->dreg;
1241 load->inst_offset = i * sizeof (gpointer);
1242 load->dreg = mono_alloc_preg (cfg);
1243 MONO_ADD_INS (cfg->cbb, load);
1245 MONO_INST_NEW (cfg, store, OP_STOREI8_MEMBASE_REG);
1246 store->sreg1 = load->dreg;
1247 store->inst_destbasereg = IA64_SP;
1248 store->inst_offset = 16 + ainfo->offset + (slot - 8) * 8;
1249 MONO_ADD_INS (cfg->cbb, store);
1252 mini_emit_memcpy (cfg, IA64_SP, 16 + ainfo->offset, src->dreg, 0, size, SIZEOF_VOID_P);
1257 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1259 CallInfo *cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
1261 switch (cinfo->ret.storage) {
1263 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1266 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1269 g_assert_not_reached ();
1274 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1279 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1281 MonoInst *ins, *n, *last_ins = NULL;
1284 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1285 switch (ins->opcode) {
1293 if (ins->dreg == ins->sreg1) {
1294 MONO_DELETE_INS (bb, ins);
1300 * OP_MOVE sreg, dreg
1301 * OP_MOVE dreg, sreg
1303 if (last_ins && last_ins->opcode == OP_MOVE &&
1304 ins->sreg1 == last_ins->dreg &&
1305 ins->dreg == last_ins->sreg1) {
1306 MONO_DELETE_INS (bb, ins);
1312 /* remove unnecessary multiplication with 1 */
1313 if (ins->inst_imm == 1) {
1314 if (ins->dreg != ins->sreg1) {
1315 ins->opcode = OP_MOVE;
1317 MONO_DELETE_INS (bb, ins);
1327 bb->last_ins = last_ins;
1330 int cond_to_ia64_cmp [][3] = {
1331 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1332 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1333 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1334 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1335 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1336 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1337 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1338 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1339 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1340 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1344 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1346 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1349 int cond_to_ia64_cmp_imm [][3] = {
1350 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1351 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1352 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1353 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1354 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1355 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1356 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1357 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1358 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1359 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1363 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1365 /* The condition needs to be reversed */
1366 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1369 #define NEW_INS(cfg,dest,op) do { \
1370 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1371 (dest)->opcode = (op); \
1372 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1373 last_ins = (dest); \
1377 * mono_arch_lowering_pass:
1379 * Converts complex opcodes into simpler ones so that each IR instruction
1380 * corresponds to one machine instruction.
1383 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1385 MonoInst *ins, *n, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1388 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1389 switch (ins->opcode) {
1390 case OP_STOREI1_MEMBASE_IMM:
1391 case OP_STOREI2_MEMBASE_IMM:
1392 case OP_STOREI4_MEMBASE_IMM:
1393 case OP_STOREI8_MEMBASE_IMM:
1394 case OP_STORE_MEMBASE_IMM:
1395 /* There are no store_membase instructions on ia64 */
1396 if (ins->inst_offset == 0) {
1398 } else if (ia64_is_imm14 (ins->inst_offset)) {
1399 NEW_INS (cfg, temp2, OP_ADD_IMM);
1400 temp2->sreg1 = ins->inst_destbasereg;
1401 temp2->inst_imm = ins->inst_offset;
1402 temp2->dreg = mono_alloc_ireg (cfg);
1405 NEW_INS (cfg, temp, OP_I8CONST);
1406 temp->inst_c0 = ins->inst_offset;
1407 temp->dreg = mono_alloc_ireg (cfg);
1409 NEW_INS (cfg, temp2, OP_LADD);
1410 temp2->sreg1 = ins->inst_destbasereg;
1411 temp2->sreg2 = temp->dreg;
1412 temp2->dreg = mono_alloc_ireg (cfg);
1415 switch (ins->opcode) {
1416 case OP_STOREI1_MEMBASE_IMM:
1417 ins->opcode = OP_STOREI1_MEMBASE_REG;
1419 case OP_STOREI2_MEMBASE_IMM:
1420 ins->opcode = OP_STOREI2_MEMBASE_REG;
1422 case OP_STOREI4_MEMBASE_IMM:
1423 ins->opcode = OP_STOREI4_MEMBASE_REG;
1425 case OP_STOREI8_MEMBASE_IMM:
1426 case OP_STORE_MEMBASE_IMM:
1427 ins->opcode = OP_STOREI8_MEMBASE_REG;
1430 g_assert_not_reached ();
1433 if (ins->inst_imm == 0)
1434 ins->sreg1 = IA64_R0;
1436 NEW_INS (cfg, temp3, OP_I8CONST);
1437 temp3->inst_c0 = ins->inst_imm;
1438 temp3->dreg = mono_alloc_ireg (cfg);
1439 ins->sreg1 = temp3->dreg;
1442 ins->inst_offset = 0;
1444 ins->inst_destbasereg = temp2->dreg;
1446 case OP_STOREI1_MEMBASE_REG:
1447 case OP_STOREI2_MEMBASE_REG:
1448 case OP_STOREI4_MEMBASE_REG:
1449 case OP_STOREI8_MEMBASE_REG:
1450 case OP_STORER4_MEMBASE_REG:
1451 case OP_STORER8_MEMBASE_REG:
1452 case OP_STORE_MEMBASE_REG:
1453 /* There are no store_membase instructions on ia64 */
1454 if (ins->inst_offset == 0) {
1457 else if (ia64_is_imm14 (ins->inst_offset)) {
1458 NEW_INS (cfg, temp2, OP_ADD_IMM);
1459 temp2->sreg1 = ins->inst_destbasereg;
1460 temp2->inst_imm = ins->inst_offset;
1461 temp2->dreg = mono_alloc_ireg (cfg);
1464 NEW_INS (cfg, temp, OP_I8CONST);
1465 temp->inst_c0 = ins->inst_offset;
1466 temp->dreg = mono_alloc_ireg (cfg);
1467 NEW_INS (cfg, temp2, OP_LADD);
1468 temp2->sreg1 = ins->inst_destbasereg;
1469 temp2->sreg2 = temp->dreg;
1470 temp2->dreg = mono_alloc_ireg (cfg);
1473 ins->inst_offset = 0;
1474 ins->inst_destbasereg = temp2->dreg;
1476 case OP_LOADI1_MEMBASE:
1477 case OP_LOADU1_MEMBASE:
1478 case OP_LOADI2_MEMBASE:
1479 case OP_LOADU2_MEMBASE:
1480 case OP_LOADI4_MEMBASE:
1481 case OP_LOADU4_MEMBASE:
1482 case OP_LOADI8_MEMBASE:
1483 case OP_LOAD_MEMBASE:
1484 case OP_LOADR4_MEMBASE:
1485 case OP_LOADR8_MEMBASE:
1486 case OP_ATOMIC_EXCHANGE_I4:
1487 case OP_ATOMIC_EXCHANGE_I8:
1488 case OP_ATOMIC_ADD_I4:
1489 case OP_ATOMIC_ADD_I8:
1490 case OP_ATOMIC_ADD_IMM_I4:
1491 case OP_ATOMIC_ADD_IMM_I8:
1492 /* There are no membase instructions on ia64 */
1493 if (ins->inst_offset == 0) {
1496 else if (ia64_is_imm14 (ins->inst_offset)) {
1497 NEW_INS (cfg, temp2, OP_ADD_IMM);
1498 temp2->sreg1 = ins->inst_basereg;
1499 temp2->inst_imm = ins->inst_offset;
1500 temp2->dreg = mono_alloc_ireg (cfg);
1503 NEW_INS (cfg, temp, OP_I8CONST);
1504 temp->inst_c0 = ins->inst_offset;
1505 temp->dreg = mono_alloc_ireg (cfg);
1506 NEW_INS (cfg, temp2, OP_LADD);
1507 temp2->sreg1 = ins->inst_basereg;
1508 temp2->sreg2 = temp->dreg;
1509 temp2->dreg = mono_alloc_ireg (cfg);
1512 ins->inst_offset = 0;
1513 ins->inst_basereg = temp2->dreg;
1533 case OP_ISHR_UN_IMM:
1534 case OP_LSHR_UN_IMM: {
1535 gboolean is_imm = FALSE;
1536 gboolean switched = FALSE;
1538 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1539 ins->opcode = OP_ZEXT_I1;
1543 switch (ins->opcode) {
1547 is_imm = ia64_is_imm14 (ins->inst_imm);
1552 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1554 /* A = B - IMM -> A = B + (-IMM) */
1555 ins->inst_imm = - ins->inst_imm;
1556 ins->opcode = OP_IADD_IMM;
1567 is_imm = ia64_is_imm8 (ins->inst_imm);
1576 case OP_ISHR_UN_IMM:
1577 case OP_LSHR_UN_IMM:
1578 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1586 ins->sreg2 = ins->sreg1;
1590 if (mono_op_imm_to_op (ins->opcode) == -1)
1591 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (ins->opcode));
1592 ins->opcode = mono_op_imm_to_op (ins->opcode);
1594 if (ins->inst_imm == 0)
1595 ins->sreg2 = IA64_R0;
1597 NEW_INS (cfg, temp, OP_I8CONST);
1598 temp->inst_c0 = ins->inst_imm;
1599 temp->dreg = mono_alloc_ireg (cfg);
1600 ins->sreg2 = temp->dreg;
1604 case OP_COMPARE_IMM:
1605 case OP_ICOMPARE_IMM:
1606 case OP_LCOMPARE_IMM: {
1607 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1613 /* Branch opts can eliminate the branch */
1614 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1620 * The compare_imm instructions have switched up arguments, and
1621 * some of them take an imm between -127 and 128.
1624 cond = mono_opcode_to_cond (next->opcode);
1625 if ((cond == CMP_LT) || (cond == CMP_GE))
1626 imm = ia64_is_imm8 (ins->inst_imm - 1);
1627 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1628 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1630 imm = ia64_is_imm8 (ins->inst_imm);
1633 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1634 ins->sreg2 = ins->sreg1;
1637 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1639 if (ins->inst_imm == 0)
1640 ins->sreg2 = IA64_R0;
1642 NEW_INS (cfg, temp, OP_I8CONST);
1643 temp->inst_c0 = ins->inst_imm;
1644 temp->dreg = mono_alloc_ireg (cfg);
1645 ins->sreg2 = temp->dreg;
1649 if (MONO_IS_COND_BRANCH_OP (next)) {
1650 next->opcode = OP_IA64_BR_COND;
1651 next->inst_target_bb = next->inst_true_bb;
1652 } else if (MONO_IS_COND_EXC (next)) {
1653 next->opcode = OP_IA64_COND_EXC;
1654 } else if (MONO_IS_SETCC (next)) {
1655 next->opcode = OP_IA64_CSET;
1657 printf ("%s\n", mono_inst_name (next->opcode));
1667 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1671 /* Branch opts can eliminate the branch */
1672 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1677 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1679 if (MONO_IS_COND_BRANCH_OP (next)) {
1680 next->opcode = OP_IA64_BR_COND;
1681 next->inst_target_bb = next->inst_true_bb;
1682 } else if (MONO_IS_COND_EXC (next)) {
1683 next->opcode = OP_IA64_COND_EXC;
1684 } else if (MONO_IS_SETCC (next)) {
1685 next->opcode = OP_IA64_CSET;
1687 printf ("%s\n", mono_inst_name (next->opcode));
1698 /* The front end removes the fcompare, so introduce it again */
1699 NEW_INS (cfg, temp, opcode_to_ia64_cmp (ins->opcode, OP_FCOMPARE));
1700 temp->sreg1 = ins->sreg1;
1701 temp->sreg2 = ins->sreg2;
1703 ins->opcode = OP_IA64_CSET;
1704 MONO_INST_NULLIFY_SREGS (ins);
1710 gboolean found = FALSE;
1711 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1713 /* First the easy cases */
1714 if (ins->inst_imm == 1) {
1715 ins->opcode = OP_MOVE;
1718 for (i = 1; i < 64; ++i)
1719 if (ins->inst_imm == (((gint64)1) << i)) {
1720 ins->opcode = shl_op;
1726 /* This could be optimized */
1729 for (i = 0; i < 64; ++i) {
1730 if (ins->inst_imm & (((gint64)1) << i)) {
1731 NEW_INS (cfg, temp, shl_op);
1732 temp->dreg = mono_alloc_ireg (cfg);
1733 temp->sreg1 = ins->sreg1;
1737 sum_reg = temp->dreg;
1739 NEW_INS (cfg, temp2, OP_LADD);
1740 temp2->dreg = mono_alloc_ireg (cfg);
1741 temp2->sreg1 = sum_reg;
1742 temp2->sreg2 = temp->dreg;
1743 sum_reg = temp2->dreg;
1747 ins->opcode = OP_MOVE;
1748 ins->sreg1 = sum_reg;
1752 case OP_LCONV_TO_OVF_U4:
1753 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1754 temp->sreg1 = ins->sreg1;
1755 temp->sreg2 = IA64_R0;
1757 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1758 temp->inst_p1 = (char*)"OverflowException";
1760 ins->opcode = OP_MOVE;
1762 case OP_LCONV_TO_OVF_I4_UN:
1763 NEW_INS (cfg, temp, OP_ICONST);
1764 temp->inst_c0 = 0x7fffffff;
1765 temp->dreg = mono_alloc_ireg (cfg);
1767 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1768 temp2->sreg1 = ins->sreg1;
1769 temp2->sreg2 = temp->dreg;
1771 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1772 temp->inst_p1 = (char*)"OverflowException";
1774 ins->opcode = OP_MOVE;
1776 case OP_FCONV_TO_I4:
1777 case OP_FCONV_TO_I2:
1778 case OP_FCONV_TO_U2:
1779 case OP_FCONV_TO_I1:
1780 case OP_FCONV_TO_U1:
1781 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1782 temp->sreg1 = ins->sreg1;
1783 temp->dreg = ins->dreg;
1785 switch (ins->opcode) {
1786 case OP_FCONV_TO_I4:
1787 ins->opcode = OP_SEXT_I4;
1789 case OP_FCONV_TO_I2:
1790 ins->opcode = OP_SEXT_I2;
1792 case OP_FCONV_TO_U2:
1793 ins->opcode = OP_ZEXT_I4;
1795 case OP_FCONV_TO_I1:
1796 ins->opcode = OP_SEXT_I1;
1798 case OP_FCONV_TO_U1:
1799 ins->opcode = OP_ZEXT_I1;
1802 g_assert_not_reached ();
1804 ins->sreg1 = ins->dreg;
1812 bb->last_ins = last_ins;
1814 bb->max_vreg = cfg->next_vreg;
1818 * emit_load_volatile_arguments:
1820 * Load volatile arguments from the stack to the original input registers.
1821 * Required before a tail call.
1823 static Ia64CodegenState
1824 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1826 MonoMethod *method = cfg->method;
1827 MonoMethodSignature *sig;
1832 /* FIXME: Generate intermediate code instead */
1834 sig = mono_method_signature (method);
1836 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
1838 /* This is the opposite of the code in emit_prolog */
1839 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1840 ArgInfo *ainfo = cinfo->args + i;
1841 gint32 stack_offset;
1844 ins = cfg->args [i];
1846 if (sig->hasthis && (i == 0))
1847 arg_type = &mono_defaults.object_class->byval_arg;
1849 arg_type = sig->params [i - sig->hasthis];
1851 arg_type = mini_get_underlying_type (arg_type);
1853 stack_offset = ainfo->offset + ARGS_OFFSET;
1855 /* Save volatile arguments to the stack */
1856 if (ins->opcode != OP_REGVAR) {
1857 switch (ainfo->storage) {
1860 /* FIXME: big offsets */
1861 g_assert (ins->opcode == OP_REGOFFSET);
1862 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1863 if (arg_type->byref)
1864 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1866 switch (arg_type->type) {
1868 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1871 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1874 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1886 if (ins->opcode == OP_REGVAR) {
1887 /* Argument allocated to (non-volatile) register */
1888 switch (ainfo->storage) {
1890 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1891 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1894 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1895 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1906 static Ia64CodegenState
1907 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1912 /* Move return value to the target register */
1913 switch (ins->opcode) {
1915 case OP_VOIDCALL_REG:
1916 case OP_VOIDCALL_MEMBASE:
1920 case OP_CALL_MEMBASE:
1923 case OP_LCALL_MEMBASE:
1924 g_assert (ins->dreg == IA64_R8);
1928 case OP_FCALL_MEMBASE:
1929 g_assert (ins->dreg == 8);
1930 if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4)
1931 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
1935 case OP_VCALL_MEMBASE:
1938 case OP_VCALL2_MEMBASE: {
1941 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
1942 storage = cinfo->ret.storage;
1944 if (storage == ArgAggregate) {
1945 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
1947 /* Load address of stack space allocated for the return value */
1948 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
1949 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
1950 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
1952 for (i = 0; i < cinfo->ret.nregs; ++i) {
1953 switch (cinfo->ret.atype) {
1954 case AggregateNormal:
1955 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1957 case AggregateSingleHFA:
1958 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
1960 case AggregateDoubleHFA:
1961 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1964 g_assert_not_reached ();
1971 g_assert_not_reached ();
1977 #define add_patch_info(cfg,code,patch_type,data) do { \
1978 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
1981 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
1982 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1984 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
1986 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
1987 ia64_br_cond_pred (code, (predicate), 0); \
1990 static Ia64CodegenState
1991 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
1993 add_patch_info (cfg, code, patch_type, data);
1995 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
1997 /* mono_arch_patch_callsite will patch this */
1998 ia64_movl (code, GP_SCRATCH_REG, 0);
1999 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2000 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2001 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2002 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2005 /* Can't use a direct call since the displacement might be too small */
2006 /* mono_arch_patch_callsite will patch this */
2007 ia64_movl (code, GP_SCRATCH_REG, 0);
2008 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2009 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2015 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2018 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2023 Ia64CodegenState code;
2024 guint8 *code_start = cfg->native_code + cfg->code_len;
2025 MonoInst *last_ins = NULL;
2026 guint last_offset = 0;
2029 if (cfg->opt & MONO_OPT_LOOP) {
2033 if (cfg->verbose_level > 2)
2034 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2036 cpos = bb->max_offset;
2038 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2042 offset = code_start - cfg->native_code;
2044 ia64_codegen_init (code, code_start);
2047 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2051 MONO_BB_FOR_EACH_INS (bb, ins) {
2052 offset = code.buf - cfg->native_code;
2054 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2056 while (offset + max_len + 16 > cfg->code_size) {
2057 ia64_codegen_close (code);
2059 offset = code.buf - cfg->native_code;
2061 cfg->code_size *= 2;
2062 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2063 code_start = cfg->native_code + offset;
2064 cfg->stat_code_reallocs++;
2066 ia64_codegen_init (code, code_start);
2069 mono_debug_record_line_number (cfg, ins, offset);
2071 switch (ins->opcode) {
2074 if (ia64_is_imm14 (ins->inst_c0))
2075 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2077 ia64_movl (code, ins->dreg, ins->inst_c0);
2080 add_patch_info (cfg, code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2081 ia64_movl (code, ins->dreg, 0);
2084 ia64_mov (code, ins->dreg, ins->sreg1);
2087 case OP_IA64_BR_COND: {
2089 if (ins->opcode == OP_IA64_BR_COND)
2091 if (ins->inst_target_bb->native_offset) {
2092 guint8 *pos = code.buf + code.nins;
2094 ia64_br_cond_pred (code, pred, 0);
2095 ia64_begin_bundle (code);
2096 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2098 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2099 ia64_br_cond_pred (code, pred, 0);
2104 ia64_begin_bundle (code);
2105 ins->inst_c0 = code.buf - cfg->native_code;
2108 case OP_RELAXED_NOP:
2110 case OP_DUMMY_STORE:
2111 case OP_NOT_REACHED:
2115 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2116 ia64_br_cond_reg (code, IA64_B6);
2120 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2124 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2128 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2132 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2136 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2140 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2144 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2148 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2151 ia64_sxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2152 ia64_shr (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2155 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2158 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2159 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2162 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2165 /* p6 and p7 is set if there is signed/unsigned overflow */
2167 /* Set p8-p9 == (sreg2 > 0) */
2168 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2170 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2172 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2173 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2174 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2175 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2177 /* res <u sreg1 => unsigned overflow */
2178 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2180 /* FIXME: Predicate this since this is a side effect */
2181 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2184 /* p6 and p7 is set if there is signed/unsigned overflow */
2186 /* Set p8-p9 == (sreg2 > 0) */
2187 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2189 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2191 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2192 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2193 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2194 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2196 /* sreg1 <u sreg2 => unsigned overflow */
2197 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2199 /* FIXME: Predicate this since this is a side effect */
2200 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2203 /* Same as OP_IADDCC */
2204 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2206 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2208 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2209 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2211 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2213 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2216 /* Same as OP_ISUBCC */
2218 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2220 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2222 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2223 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2225 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2227 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2232 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2237 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2241 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2245 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2250 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2254 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2257 g_assert (ins->inst_imm <= 64);
2258 ia64_extr (code, ins->dreg, ins->sreg1, ins->inst_imm, 32 - ins->inst_imm);
2260 case OP_ISHR_UN_IMM:
2261 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2262 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2264 case OP_LSHR_UN_IMM:
2265 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2268 /* Based on gcc code */
2269 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2270 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2271 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2272 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2275 case OP_STOREI1_MEMBASE_REG:
2276 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2278 case OP_STOREI2_MEMBASE_REG:
2279 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2281 case OP_STOREI4_MEMBASE_REG:
2282 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2284 case OP_STOREI8_MEMBASE_REG:
2285 case OP_STORE_MEMBASE_REG:
2286 if (ins->inst_offset != 0) {
2287 /* This is generated by local regalloc */
2288 if (ia64_is_imm14 (ins->inst_offset)) {
2289 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2291 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2292 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2294 ins->inst_destbasereg = GP_SCRATCH_REG;
2296 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2299 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2300 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2302 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2303 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2305 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2306 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2308 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2309 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2312 case OP_LOADU1_MEMBASE:
2313 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2315 case OP_LOADU2_MEMBASE:
2316 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2318 case OP_LOADU4_MEMBASE:
2319 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2321 case OP_LOADI1_MEMBASE:
2322 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2323 ia64_sxt1 (code, ins->dreg, ins->dreg);
2325 case OP_LOADI2_MEMBASE:
2326 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2327 ia64_sxt2 (code, ins->dreg, ins->dreg);
2329 case OP_LOADI4_MEMBASE:
2330 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2331 ia64_sxt4 (code, ins->dreg, ins->dreg);
2333 case OP_LOAD_MEMBASE:
2334 case OP_LOADI8_MEMBASE:
2335 if (ins->inst_offset != 0) {
2336 /* This is generated by local regalloc */
2337 if (ia64_is_imm14 (ins->inst_offset)) {
2338 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2340 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2341 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2343 ins->inst_basereg = GP_SCRATCH_REG;
2345 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2348 case OP_IA64_LOADU1_MEMBASE_INC:
2349 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2351 case OP_IA64_LOADU2_MEMBASE_INC:
2352 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2354 case OP_IA64_LOADU4_MEMBASE_INC:
2355 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2357 case OP_IA64_LOADI8_MEMBASE_INC:
2358 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2362 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2365 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2368 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2371 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2374 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2377 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2380 /* Compare opcodes */
2381 case OP_IA64_CMP4_EQ:
2382 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2384 case OP_IA64_CMP4_NE:
2385 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2387 case OP_IA64_CMP4_LE:
2388 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2390 case OP_IA64_CMP4_LT:
2391 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2393 case OP_IA64_CMP4_GE:
2394 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2396 case OP_IA64_CMP4_GT:
2397 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2399 case OP_IA64_CMP4_LT_UN:
2400 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2402 case OP_IA64_CMP4_LE_UN:
2403 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2405 case OP_IA64_CMP4_GT_UN:
2406 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2408 case OP_IA64_CMP4_GE_UN:
2409 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2411 case OP_IA64_CMP_EQ:
2412 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2414 case OP_IA64_CMP_NE:
2415 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2417 case OP_IA64_CMP_LE:
2418 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2420 case OP_IA64_CMP_LT:
2421 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2423 case OP_IA64_CMP_GE:
2424 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2426 case OP_IA64_CMP_GT:
2427 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2429 case OP_IA64_CMP_GT_UN:
2430 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2432 case OP_IA64_CMP_LT_UN:
2433 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2435 case OP_IA64_CMP_GE_UN:
2436 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2438 case OP_IA64_CMP_LE_UN:
2439 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2441 case OP_IA64_CMP4_EQ_IMM:
2442 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2444 case OP_IA64_CMP4_NE_IMM:
2445 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2447 case OP_IA64_CMP4_LE_IMM:
2448 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2450 case OP_IA64_CMP4_LT_IMM:
2451 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2453 case OP_IA64_CMP4_GE_IMM:
2454 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2456 case OP_IA64_CMP4_GT_IMM:
2457 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2459 case OP_IA64_CMP4_LT_UN_IMM:
2460 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2462 case OP_IA64_CMP4_LE_UN_IMM:
2463 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2465 case OP_IA64_CMP4_GT_UN_IMM:
2466 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2468 case OP_IA64_CMP4_GE_UN_IMM:
2469 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2471 case OP_IA64_CMP_EQ_IMM:
2472 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2474 case OP_IA64_CMP_NE_IMM:
2475 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2477 case OP_IA64_CMP_LE_IMM:
2478 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2480 case OP_IA64_CMP_LT_IMM:
2481 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2483 case OP_IA64_CMP_GE_IMM:
2484 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2486 case OP_IA64_CMP_GT_IMM:
2487 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2489 case OP_IA64_CMP_GT_UN_IMM:
2490 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2492 case OP_IA64_CMP_LT_UN_IMM:
2493 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2495 case OP_IA64_CMP_GE_UN_IMM:
2496 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2498 case OP_IA64_CMP_LE_UN_IMM:
2499 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2501 case OP_IA64_FCMP_EQ:
2502 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2504 case OP_IA64_FCMP_NE:
2505 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2507 case OP_IA64_FCMP_LT:
2508 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2510 case OP_IA64_FCMP_GT:
2511 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2513 case OP_IA64_FCMP_LE:
2514 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2516 case OP_IA64_FCMP_GE:
2517 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2519 case OP_IA64_FCMP_GT_UN:
2520 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2521 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2523 case OP_IA64_FCMP_LT_UN:
2524 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2525 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2527 case OP_IA64_FCMP_GE_UN:
2528 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2529 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2531 case OP_IA64_FCMP_LE_UN:
2532 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2533 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2536 case OP_COND_EXC_IOV:
2537 case OP_COND_EXC_OV:
2538 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2540 case OP_COND_EXC_IC:
2542 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2544 case OP_IA64_COND_EXC:
2545 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2548 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2549 ia64_no_stop (code);
2550 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2552 case OP_ICONV_TO_I1:
2553 case OP_LCONV_TO_I1:
2554 /* FIXME: Is this needed ? */
2555 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2557 case OP_ICONV_TO_I2:
2558 case OP_LCONV_TO_I2:
2559 /* FIXME: Is this needed ? */
2560 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2562 case OP_LCONV_TO_I4:
2563 /* FIXME: Is this needed ? */
2564 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2566 case OP_ICONV_TO_U1:
2567 case OP_LCONV_TO_U1:
2568 /* FIXME: Is this needed */
2569 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2571 case OP_ICONV_TO_U2:
2572 case OP_LCONV_TO_U2:
2573 /* FIXME: Is this needed */
2574 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2576 case OP_LCONV_TO_U4:
2577 /* FIXME: Is this needed */
2578 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2580 case OP_ICONV_TO_I8:
2582 case OP_LCONV_TO_I8:
2584 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2586 case OP_LCONV_TO_U8:
2588 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2595 double d = *(double *)ins->inst_p0;
2597 if ((d == 0.0) && (mono_signbit (d) == 0))
2598 ia64_fmov (code, ins->dreg, 0);
2600 ia64_fmov (code, ins->dreg, 1);
2602 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2603 ia64_movl (code, GP_SCRATCH_REG, 0);
2604 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2609 float f = *(float *)ins->inst_p0;
2611 if ((f == 0.0) && (mono_signbit (f) == 0))
2612 ia64_fmov (code, ins->dreg, 0);
2614 ia64_fmov (code, ins->dreg, 1);
2616 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2617 ia64_movl (code, GP_SCRATCH_REG, 0);
2618 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2623 ia64_fmov (code, ins->dreg, ins->sreg1);
2625 case OP_STORER8_MEMBASE_REG:
2626 if (ins->inst_offset != 0) {
2627 /* This is generated by local regalloc */
2628 if (ia64_is_imm14 (ins->inst_offset)) {
2629 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2631 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2632 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2634 ins->inst_destbasereg = GP_SCRATCH_REG;
2636 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2638 case OP_STORER4_MEMBASE_REG:
2639 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2640 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2642 case OP_LOADR8_MEMBASE:
2643 if (ins->inst_offset != 0) {
2644 /* This is generated by local regalloc */
2645 if (ia64_is_imm14 (ins->inst_offset)) {
2646 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2648 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2649 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2651 ins->inst_basereg = GP_SCRATCH_REG;
2653 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2655 case OP_LOADR4_MEMBASE:
2656 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2657 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2659 case OP_ICONV_TO_R4:
2660 case OP_LCONV_TO_R4:
2661 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2662 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2663 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2665 case OP_ICONV_TO_R8:
2666 case OP_LCONV_TO_R8:
2667 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2668 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2669 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2671 case OP_FCONV_TO_R4:
2672 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2674 case OP_FCONV_TO_I8:
2676 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2677 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2680 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2683 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2686 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2689 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2693 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2694 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2696 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2697 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2698 /* Positive infinity */
2699 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2700 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2701 /* Negative infinity */
2702 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2703 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2708 /* ensure ins->sreg1 is not NULL */
2709 /* Can't use ld8 as this could be a vtype address */
2710 ia64_ld1 (code, GP_SCRATCH_REG, ins->sreg1);
2713 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2714 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2722 call = (MonoCallInst*)ins;
2724 if (ins->flags & MONO_INST_HAS_METHOD)
2725 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2727 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2729 code = emit_move_return_value (cfg, ins, code);
2737 case OP_VOIDCALL_REG: {
2738 MonoCallInst *call = (MonoCallInst*)ins;
2743 * mono_arch_get_this_arg_from_call () needs to find the this argument in a global
2746 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2747 out_reg = cfg->arch.reg_out0;
2748 ia64_mov (code, IA64_R10, out_reg);
2751 ia64_mov (code, IA64_R8, ins->sreg1);
2752 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2753 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2754 ia64_ld8 (code, IA64_GP, IA64_R8);
2755 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2757 code = emit_move_return_value (cfg, ins, code);
2760 case OP_FCALL_MEMBASE:
2761 case OP_LCALL_MEMBASE:
2762 case OP_VCALL_MEMBASE:
2763 case OP_VCALL2_MEMBASE:
2764 case OP_VOIDCALL_MEMBASE:
2765 case OP_CALL_MEMBASE: {
2766 MonoCallInst *call = (MonoCallInst*)ins;
2770 ia64_mov (code, IA64_R11, ins->sreg1);
2771 if (ia64_is_imm14 (ins->inst_offset))
2772 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2774 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2775 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2778 if (call->method && ins->inst_offset < 0) {
2780 * This is a possible IMT call so save the IMT method in a global
2781 * register where mono_arch_find_imt_method () and its friends can
2784 ia64_movl (code, IA64_R9, call->method);
2788 * mono_arch_find_this_arg () needs to find the this argument in a global
2791 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2792 out_reg = cfg->arch.reg_out0;
2793 ia64_mov (code, IA64_R10, out_reg);
2795 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2797 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2799 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2801 code = emit_move_return_value (cfg, ins, code);
2806 * Keep in sync with the code in emit_epilog.
2809 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2812 g_assert (!cfg->method->save_lmf);
2814 /* Load arguments into their original registers */
2815 code = emit_load_volatile_arguments (cfg, code);
2817 if (cfg->arch.stack_alloc_size) {
2818 if (cfg->arch.omit_fp) {
2819 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2820 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2822 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2823 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2827 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2829 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2830 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2832 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2833 ia64_movl (code, GP_SCRATCH_REG, 0);
2834 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2835 ia64_br_cond_reg (code, IA64_B6);
2840 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
2846 /* FIXME: Sigaltstack support */
2848 /* keep alignment */
2849 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2850 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2851 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2853 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2855 ia64_mov (code, ins->dreg, IA64_SP);
2857 /* An area at sp is reserved by the ABI for parameter passing */
2858 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2859 if (ia64_is_adds_imm (abi_offset))
2860 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2862 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2863 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2866 if (ins->flags & MONO_INST_INIT) {
2868 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2870 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2873 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2874 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2875 ia64_br_cond_pred (code, 8, -2);
2877 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2879 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2884 case OP_LOCALLOC_IMM: {
2887 /* FIXME: Sigaltstack support */
2889 gssize size = ins->inst_imm;
2890 size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
2892 if (ia64_is_adds_imm (size))
2893 ia64_adds_imm (code, GP_SCRATCH_REG, size, IA64_R0);
2895 ia64_movl (code, GP_SCRATCH_REG, size);
2897 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2898 ia64_mov (code, ins->dreg, IA64_SP);
2900 /* An area at sp is reserved by the ABI for parameter passing */
2901 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
2902 if (ia64_is_adds_imm (abi_offset))
2903 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2905 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2906 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2909 if (ins->flags & MONO_INST_INIT) {
2911 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2913 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2916 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2917 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2918 ia64_br_cond_pred (code, 8, -2);
2920 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2922 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2927 /* Synchronization */
2928 case OP_MEMORY_BARRIER:
2931 case OP_ATOMIC_ADD_IMM_I4:
2932 g_assert (ins->inst_offset == 0);
2933 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2934 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2936 case OP_ATOMIC_ADD_IMM_I8:
2937 g_assert (ins->inst_offset == 0);
2938 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2939 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2941 case OP_ATOMIC_EXCHANGE_I4:
2942 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2943 ia64_sxt4 (code, ins->dreg, ins->dreg);
2945 case OP_ATOMIC_EXCHANGE_I8:
2946 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2948 case OP_ATOMIC_ADD_I4: {
2949 guint8 *label, *buf;
2951 /* From libatomic_ops */
2954 ia64_begin_bundle (code);
2955 label = code.buf + code.nins;
2956 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2957 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2958 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2959 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2960 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2961 buf = code.buf + code.nins;
2962 ia64_br_cond_pred (code, 7, 0);
2963 ia64_begin_bundle (code);
2964 ia64_patch (buf, label);
2965 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2968 case OP_ATOMIC_ADD_I8: {
2969 guint8 *label, *buf;
2971 /* From libatomic_ops */
2974 ia64_begin_bundle (code);
2975 label = code.buf + code.nins;
2976 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2977 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2978 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2979 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2980 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2981 buf = code.buf + code.nins;
2982 ia64_br_cond_pred (code, 7, 0);
2983 ia64_begin_bundle (code);
2984 ia64_patch (buf, label);
2985 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2989 /* Exception handling */
2990 case OP_CALL_HANDLER:
2992 * Using a call instruction would mess up the register stack, so
2993 * save the return address to a register and use a
2996 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2997 ia64_mov (code, IA64_R15, IA64_R0);
2998 ia64_mov_from_ip (code, GP_SCRATCH_REG);
2999 /* Add the length of OP_CALL_HANDLER */
3000 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3001 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3002 ia64_movl (code, GP_SCRATCH_REG2, 0);
3003 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3004 ia64_br_cond_reg (code, IA64_B6);
3006 //mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3007 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3009 case OP_START_HANDLER: {
3011 * We receive the return address in GP_SCRATCH_REG.
3013 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3016 * R15 determines our caller. It is used since it is writable using
3018 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3019 * R15 != 0 means we are called by call_filter ().
3021 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3022 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3024 ia64_br_cond_pred (code, 6, 6);
3027 * Called by call_filter:
3028 * Allocate a new stack frame, and set the fp register from the
3029 * value passed in by the caller.
3030 * We allocate a similar frame as is done by the prolog, so
3031 * if an exception is thrown while executing the filter, the
3032 * unwinder can unwind through the filter frame using the unwind
3033 * info for the prolog.
3035 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);
3036 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3037 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3038 ia64_mov (code, cfg->frame_reg, IA64_R15);
3039 /* Signal to endfilter that we are called by call_filter */
3040 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3042 /* Branch target: */
3043 if (ia64_is_imm14 (spvar->inst_offset))
3044 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3046 ia64_movl (code, GP_SCRATCH_REG2, spvar->inst_offset);
3047 ia64_add (code, GP_SCRATCH_REG2, cfg->frame_reg, GP_SCRATCH_REG2);
3050 /* Save the return address */
3051 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3052 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3057 case OP_ENDFILTER: {
3058 /* FIXME: Return the value in ENDFILTER */
3059 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3061 /* Load the return address */
3062 if (ia64_is_imm14 (spvar->inst_offset)) {
3063 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3065 ia64_movl (code, GP_SCRATCH_REG, spvar->inst_offset);
3066 ia64_add (code, GP_SCRATCH_REG, cfg->frame_reg, GP_SCRATCH_REG);
3068 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3071 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3072 ia64_br_cond_pred (code, 7, 4);
3074 /* Called by call_filter */
3076 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3077 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3078 ia64_br_ret_reg (code, IA64_B0);
3080 /* Called by CALL_HANDLER */
3081 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3082 ia64_br_cond_reg (code, IA64_B6);
3086 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3087 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3088 (gpointer)"mono_arch_throw_exception");
3091 * This might be the last instruction in the method, so add a dummy
3092 * instruction so the unwinder will work.
3094 ia64_break_i (code, 0);
3097 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3098 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3099 (gpointer)"mono_arch_rethrow_exception");
3101 ia64_break_i (code, 0);
3103 case OP_GC_SAFE_POINT:
3107 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3108 g_assert_not_reached ();
3111 if ((code.buf - cfg->native_code - offset) > max_len) {
3112 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3113 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3114 g_assert_not_reached ();
3120 last_offset = offset;
3123 ia64_codegen_close (code);
3125 cfg->code_len = code.buf - cfg->native_code;
3129 mono_arch_register_lowlevel_calls (void)
3133 static Ia64InsType ins_types_in_template [32][3] = {
3134 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3135 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3136 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3137 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3138 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3139 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3142 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3143 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3144 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3145 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3146 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3147 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3148 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3149 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3150 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3151 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3152 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3153 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3156 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3157 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3158 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3159 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3162 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3163 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3168 static gboolean stops_in_template [32][3] = {
3169 { FALSE, FALSE, FALSE },
3170 { FALSE, FALSE, TRUE },
3171 { FALSE, TRUE, FALSE },
3172 { FALSE, TRUE, TRUE },
3173 { FALSE, FALSE, FALSE },
3174 { FALSE, FALSE, TRUE },
3175 { FALSE, FALSE, FALSE },
3176 { FALSE, FALSE, FALSE },
3178 { FALSE, FALSE, FALSE },
3179 { FALSE, FALSE, TRUE },
3180 { TRUE, FALSE, FALSE },
3181 { TRUE, FALSE, TRUE },
3182 { FALSE, FALSE, FALSE },
3183 { FALSE, FALSE, TRUE },
3184 { FALSE, FALSE, FALSE },
3185 { FALSE, FALSE, TRUE },
3187 { FALSE, FALSE, FALSE },
3188 { FALSE, FALSE, TRUE },
3189 { FALSE, FALSE, FALSE },
3190 { FALSE, FALSE, TRUE },
3191 { FALSE, FALSE, FALSE },
3192 { FALSE, FALSE, FALSE },
3193 { FALSE, FALSE, FALSE },
3194 { FALSE, FALSE, TRUE },
3196 { FALSE, FALSE, FALSE },
3197 { FALSE, FALSE, TRUE },
3198 { FALSE, FALSE, FALSE },
3199 { FALSE, FALSE, FALSE },
3200 { FALSE, FALSE, FALSE },
3201 { FALSE, FALSE, TRUE },
3202 { FALSE, FALSE, FALSE },
3203 { FALSE, FALSE, FALSE }
3206 static int last_stop_in_template [32] = {
3207 -1, 2, 1, 2, -1, 2, -1, -1,
3208 -1, 2, 0, 2, -1, 2, -1, 2,
3209 -1, 2, -1, 2, -1, -1, -1, 2,
3210 -1, 2, -1, -1, -1, 2, -1, -1
3213 static guint64 nops_for_ins_types [6] = {
3222 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3229 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3231 #define DEBUG_INS_SCHED(a)
3235 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3237 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3238 guint8 *deps = code->dep_info;
3239 gboolean need_stop, no_stop;
3241 for (i = 0; i < code->nins; ++i)
3245 current_deps_start = 0;
3246 current_ins_start = 0;
3247 deps_start [ins_index] = current_ins_start;
3250 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3251 while (pos < code->dep_info_pos) {
3253 switch (deps [pos]) {
3254 case IA64_END_OF_INS:
3256 current_ins_start = pos + 2;
3257 deps_start [ins_index] = current_ins_start;
3259 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3264 reg = deps [pos + 1];
3266 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3267 for (i = current_deps_start; i < current_ins_start; i += 2)
3268 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3272 reg = code->dep_info [pos + 1];
3274 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3275 for (i = current_deps_start; i < current_ins_start; i += 2)
3276 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3280 reg = deps [pos + 1];
3282 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3283 for (i = current_deps_start; i < current_ins_start; i += 2)
3284 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3287 case IA64_READ_PR_BRANCH:
3288 reg = deps [pos + 1];
3290 /* Writes to prs by non-float instructions are visible to branches */
3291 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3292 for (i = current_deps_start; i < current_ins_start; i += 2)
3293 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3297 reg = code->dep_info [pos + 1];
3299 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3300 for (i = current_deps_start; i < current_ins_start; i += 2)
3301 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3304 case IA64_WRITE_PR_FLOAT:
3305 reg = code->dep_info [pos + 1];
3307 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3308 for (i = current_deps_start; i < current_ins_start; i += 2)
3309 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3313 reg = deps [pos + 1];
3315 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3316 for (i = current_deps_start; i < current_ins_start; i += 2)
3317 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3321 reg = code->dep_info [pos + 1];
3323 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3324 for (i = current_deps_start; i < current_ins_start; i += 2)
3325 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3328 case IA64_READ_BR_BRANCH:
3329 reg = deps [pos + 1];
3331 /* Writes to brs are visible to branches */
3332 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3335 reg = deps [pos + 1];
3337 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3338 for (i = current_deps_start; i < current_ins_start; i += 2)
3339 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3343 reg = code->dep_info [pos + 1];
3345 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3346 for (i = current_deps_start; i < current_ins_start; i += 2)
3347 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3351 reg = deps [pos + 1];
3353 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3354 for (i = current_deps_start; i < current_ins_start; i += 2)
3355 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3359 reg = code->dep_info [pos + 1];
3361 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3362 for (i = current_deps_start; i < current_ins_start; i += 2)
3363 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3368 * Explicitly indicate that a stop is not required. Useful for
3369 * example when two predicated instructions with negated predicates
3370 * write the same registers.
3375 g_assert_not_reached ();
3379 if (need_stop && !no_stop) {
3380 g_assert (ins_index > 0);
3381 stops [ins_index - 1] = 1;
3383 DEBUG_INS_SCHED (printf ("STOP\n"));
3384 current_deps_start = current_ins_start;
3386 /* Skip remaining deps for this instruction */
3387 while (deps [pos] != IA64_END_OF_INS)
3392 if (code->nins > 0) {
3393 /* No dependency info for the last instruction */
3394 stops [code->nins - 1] = 1;
3397 deps_start [code->nins] = code->dep_info_pos;
3401 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3403 int stop_pos, i, deps_to_shift, dep_shift;
3405 g_assert (n <= code->nins);
3407 // if (n > 1) printf ("FOUND: %ld.\n", template);
3409 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3411 stop_pos = last_stop_in_template [template] + 1;
3415 /* Compute the number of 'real' instructions before the stop */
3416 deps_to_shift = stop_pos;
3417 if (stop_pos >= 3 && (nops & (1 << 2)))
3419 if (stop_pos >= 2 && (nops & (1 << 1)))
3421 if (stop_pos >= 1 && (nops & (1 << 0)))
3425 * We have to keep some dependencies whose instructions have been shifted
3426 * out of the buffer. So nullify the end_of_ins markers in the dependency
3429 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3430 if (code->dep_info [i] == IA64_END_OF_INS)
3431 code->dep_info [i] = IA64_NONE;
3433 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3434 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3435 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3437 dep_shift = deps_start [deps_to_shift];
3438 for (i = 0; i < code->nins + 1 - n; ++i)
3439 deps_start [i] = deps_start [n + i] - dep_shift;
3441 /* Determine the exact positions of instructions with unwind ops */
3442 if (code->unw_op_count) {
3444 int curr_ins, curr_ins_pos;
3447 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3448 for (i = 0; i < 3; ++i) {
3449 if (! (nops & (1 << i))) {
3450 ins_pos [curr_ins] = curr_ins_pos + i;
3455 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3456 if (code->unw_ops_pos [i] < n) {
3457 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3458 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3461 if (code->unw_op_pos < code->unw_op_count)
3462 code->unw_op_pos += n;
3465 if (n == code->nins) {
3470 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3471 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3472 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3478 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3480 int i, ins_type, template, nins_to_emit;
3481 int deps_start [16];
3486 * We implement a simple scheduler which tries to put three instructions
3487 * per bundle, then two, then one.
3489 ia64_analyze_deps (code, deps_start, stops);
3491 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3492 /* Find a suitable template */
3493 for (template = 0; template < 32; ++template) {
3494 if (stops_in_template [template][0] != stops [0] ||
3495 stops_in_template [template][1] != stops [1] ||
3496 stops_in_template [template][2] != stops [2])
3500 for (i = 0; i < 3; ++i) {
3501 ins_type = ins_types_in_template [template][i];
3502 switch (code->itypes [i]) {
3503 case IA64_INS_TYPE_A:
3504 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3507 found &= (ins_type == code->itypes [i]);
3513 found = debug_ins_sched ();
3516 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3522 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3523 /* Wait for more instructions */
3526 /* If it didn't work out, try putting two instructions into one bundle */
3527 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3528 /* Try a nop at the end */
3529 for (template = 0; template < 32; ++template) {
3530 if (stops_in_template [template][0] != stops [0] ||
3531 ((stops_in_template [template][1] != stops [1]) &&
3532 (stops_in_template [template][2] != stops [1])))
3536 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3537 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3540 if (!debug_ins_sched ())
3543 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);
3548 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3549 /* Wait for more instructions */
3552 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3553 /* Try a nop in the middle */
3554 for (template = 0; template < 32; ++template) {
3555 if (((stops_in_template [template][0] != stops [0]) &&
3556 (stops_in_template [template][1] != stops [0])) ||
3557 stops_in_template [template][2] != stops [1])
3560 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3561 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3564 if (!debug_ins_sched ())
3567 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);
3572 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3573 /* Try a nop at the beginning */
3574 for (template = 0; template < 32; ++template) {
3575 if ((stops_in_template [template][1] != stops [0]) ||
3576 (stops_in_template [template][2] != stops [1]))
3579 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3580 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3583 if (!debug_ins_sched ())
3586 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);
3591 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3592 /* Wait for more instructions */
3596 nins_to_emit = code->nins;
3600 while (nins_to_emit > 0) {
3601 if (!debug_ins_sched ())
3603 switch (code->itypes [0]) {
3604 case IA64_INS_TYPE_A:
3606 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3608 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3610 case IA64_INS_TYPE_I:
3612 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3614 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3616 case IA64_INS_TYPE_M:
3618 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3620 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3622 case IA64_INS_TYPE_B:
3624 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3626 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3628 case IA64_INS_TYPE_F:
3630 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3632 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3634 case IA64_INS_TYPE_LX:
3635 if (stops [0] || stops [1])
3636 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3638 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3642 g_assert_not_reached ();
3648 unw_dyn_region_info_t*
3649 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3651 unw_dyn_region_info_t *r;
3653 g_assert (code->nins == 0);
3654 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3655 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3656 r->op_count = code->unw_op_count;
3657 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3658 code->unw_op_count = 0;
3659 code->unw_op_pos = 0;
3660 code->region_start = code->buf;
3666 ia64_patch (unsigned char* code, gpointer target)
3669 guint64 instructions [3];
3670 guint8 gen_buf [16];
3671 Ia64CodegenState gen;
3676 * code encodes both the position inside the buffer and code.nins when
3677 * the instruction was emitted.
3679 ins_to_skip = (guint64)code % 16;
3680 code = (unsigned char*)((guint64)code & ~15);
3683 * Search for the first instruction which is 'patchable', skipping
3684 * ins_to_skip instructions.
3689 template = ia64_bundle_template (code);
3690 instructions [0] = ia64_bundle_ins1 (code);
3691 instructions [1] = ia64_bundle_ins2 (code);
3692 instructions [2] = ia64_bundle_ins3 (code);
3694 ia64_codegen_init (gen, gen_buf);
3697 for (i = 0; i < 3; ++i) {
3698 guint64 ins = instructions [i];
3699 int opcode = ia64_ins_opcode (ins);
3701 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3709 switch (ins_types_in_template [template][i]) {
3710 case IA64_INS_TYPE_A:
3711 case IA64_INS_TYPE_M:
3712 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3714 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3715 instructions [i] = gen.instructions [0];
3721 case IA64_INS_TYPE_B:
3722 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3724 gint64 disp = ((guint8*)target - code) >> 4;
3727 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3729 instructions [i] = gen.instructions [0];
3732 else if (opcode == 5) {
3734 gint64 disp = ((guint8*)target - code) >> 4;
3737 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3738 instructions [i] = gen.instructions [0];
3744 case IA64_INS_TYPE_LX:
3748 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3750 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3751 instructions [1] = gen.instructions [0];
3752 instructions [2] = gen.instructions [1];
3765 ia64_codegen_init (gen, code);
3766 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3776 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
3778 MonoJumpInfo *patch_info;
3782 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3783 unsigned char *ip = patch_info->ip.i + code;
3784 const unsigned char *target;
3786 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
3787 return_if_nok (error);
3789 if (patch_info->type == MONO_PATCH_INFO_NONE)
3791 if (mono_compile_aot) {
3795 ia64_patch (ip, (gpointer)target);
3800 mono_arch_emit_prolog (MonoCompile *cfg)
3802 MonoMethod *method = cfg->method;
3803 MonoMethodSignature *sig;
3805 int alloc_size, pos, i;
3806 Ia64CodegenState code;
3809 sig = mono_method_signature (method);
3812 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
3814 cfg->code_size = MAX (cfg->header->code_size * 4, 512);
3816 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3817 cfg->code_size += 1024;
3818 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3819 cfg->code_size += 1024;
3821 cfg->native_code = g_malloc (cfg->code_size);
3823 ia64_codegen_init (code, cfg->native_code);
3825 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3826 if (cfg->param_area)
3827 alloc_size += cfg->param_area;
3831 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3833 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3834 /* Force sp to be saved/restored */
3835 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3837 cfg->arch.stack_alloc_size = alloc_size;
3841 if (method->save_lmf) {
3842 /* No LMF on IA64 */
3847 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3848 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);
3849 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3850 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3852 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3853 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3854 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3855 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3856 ia64_mov (code, cfg->frame_reg, IA64_SP);
3860 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3861 int pagesize = getpagesize ();
3863 if (alloc_size >= pagesize) {
3864 gint32 remaining_size = alloc_size;
3866 /* Generate stack touching code */
3867 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3868 while (remaining_size >= pagesize) {
3869 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3870 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3871 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3872 remaining_size -= pagesize;
3876 if (ia64_is_imm14 (-alloc_size)) {
3877 if (cfg->arch.omit_fp)
3878 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3879 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3882 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3883 if (cfg->arch.omit_fp)
3884 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3885 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3889 ia64_begin_bundle (code);
3891 /* Initialize unwind info */
3892 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3894 if (sig->ret->type != MONO_TYPE_VOID) {
3895 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3896 /* Save volatile arguments to the stack */
3901 /* Keep this in sync with emit_load_volatile_arguments */
3902 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3903 ArgInfo *ainfo = cinfo->args + i;
3904 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 = mini_get_underlying_type (arg_type);
3916 stack_offset = ainfo->offset + ARGS_OFFSET;
3919 * FIXME: Native code might pass non register sized integers
3920 * without initializing the upper bits.
3922 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && !arg_type->byref && ainfo->storage == ArgInIReg) {
3923 int reg = cfg->arch.reg_in0 + ainfo->reg;
3925 switch (mono_type_to_load_membase (cfg, arg_type)) {
3926 case OP_LOADI1_MEMBASE:
3927 ia64_sxt1 (code, reg, reg);
3929 case OP_LOADU1_MEMBASE:
3930 ia64_zxt1 (code, reg, reg);
3932 case OP_LOADI2_MEMBASE:
3933 ia64_sxt2 (code, reg, reg);
3935 case OP_LOADU2_MEMBASE:
3936 ia64_zxt2 (code, reg, reg);
3943 /* Save volatile arguments to the stack */
3944 if (inst->opcode != OP_REGVAR) {
3945 switch (ainfo->storage) {
3948 case ArgInFloatRegR4:
3949 g_assert (inst->opcode == OP_REGOFFSET);
3950 if (ia64_is_adds_imm (inst->inst_offset))
3951 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3953 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3954 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3956 if (arg_type->byref)
3957 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3959 switch (arg_type->type) {
3961 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3964 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3967 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3975 if (ainfo->nslots != ainfo->nregs)
3978 g_assert (inst->opcode == OP_REGOFFSET);
3979 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3980 for (i = 0; i < ainfo->nregs; ++i) {
3981 switch (ainfo->atype) {
3982 case AggregateNormal:
3983 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3985 case AggregateSingleHFA:
3986 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3988 case AggregateDoubleHFA:
3989 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3997 g_assert_not_reached ();
4001 if (inst->opcode == OP_REGVAR) {
4002 /* Argument allocated to (non-volatile) register */
4003 switch (ainfo->storage) {
4005 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4006 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4009 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4010 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4018 if (method->save_lmf) {
4019 /* No LMF on IA64 */
4022 ia64_codegen_close (code);
4024 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4025 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4027 cfg->code_len = code.buf - cfg->native_code;
4029 g_assert (cfg->code_len < cfg->code_size);
4031 cfg->arch.prolog_end_offset = cfg->code_len;
4037 mono_arch_emit_epilog (MonoCompile *cfg)
4039 MonoMethod *method = cfg->method;
4041 int max_epilog_size = 16 * 4;
4042 Ia64CodegenState code;
4047 if (mono_jit_trace_calls != NULL)
4048 max_epilog_size += 1024;
4050 cfg->arch.epilog_begin_offset = cfg->code_len;
4052 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4053 cfg->code_size *= 2;
4054 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4055 cfg->stat_code_reallocs++;
4058 /* FIXME: Emit unwind info */
4060 buf = cfg->native_code + cfg->code_len;
4062 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4063 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4065 ia64_codegen_init (code, buf);
4067 /* the code restoring the registers must be kept in sync with OP_JMP */
4070 if (method->save_lmf) {
4071 /* No LMF on IA64 */
4074 /* Load returned vtypes into registers if needed */
4075 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4076 ainfo = &cinfo->ret;
4077 switch (ainfo->storage) {
4079 if (ainfo->nslots != ainfo->nregs)
4082 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4083 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4084 for (i = 0; i < ainfo->nregs; ++i) {
4085 switch (ainfo->atype) {
4086 case AggregateNormal:
4087 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4089 case AggregateSingleHFA:
4090 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4092 case AggregateDoubleHFA:
4093 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4096 g_assert_not_reached ();
4104 ia64_begin_bundle (code);
4106 code.region_start = cfg->native_code;
4108 /* Label the unwind state at the start of the exception throwing region */
4109 //ia64_unw_label_state (code, 1234);
4111 if (cfg->arch.stack_alloc_size) {
4112 if (cfg->arch.omit_fp) {
4113 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4114 ia64_unw_pop_frames (code, 1);
4115 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4117 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4118 ia64_unw_pop_frames (code, 1);
4119 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4123 ia64_unw_pop_frames (code, 1);
4124 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4127 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4128 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4129 ia64_br_ret_reg (code, IA64_B0);
4131 ia64_codegen_close (code);
4133 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4134 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4136 cfg->code_len = code.buf - cfg->native_code;
4138 g_assert (cfg->code_len < cfg->code_size);
4142 mono_arch_emit_exceptions (MonoCompile *cfg)
4144 MonoJumpInfo *patch_info;
4146 Ia64CodegenState code;
4147 gboolean empty = TRUE;
4148 //unw_dyn_region_info_t *r_exceptions;
4149 MonoClass *exc_classes [16];
4150 guint8 *exc_throw_start [16], *exc_throw_end [16];
4151 guint32 code_size = 0;
4153 /* Compute needed space */
4154 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4155 if (patch_info->type == MONO_PATCH_INFO_EXC)
4157 if (patch_info->type == MONO_PATCH_INFO_R8)
4158 code_size += 8 + 7; /* sizeof (double) + alignment */
4159 if (patch_info->type == MONO_PATCH_INFO_R4)
4160 code_size += 4 + 7; /* sizeof (float) + alignment */
4166 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4167 cfg->code_size *= 2;
4168 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4169 cfg->stat_code_reallocs++;
4172 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4174 /* The unwind state here is the same as before the epilog */
4175 //ia64_unw_copy_state (code, 1234);
4177 /* add code to raise exceptions */
4178 /* FIXME: Optimize this */
4180 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4181 switch (patch_info->type) {
4182 case MONO_PATCH_INFO_EXC: {
4183 MonoClass *exc_class;
4186 guint64 exc_token_index;
4188 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4189 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4190 throw_ip = cfg->native_code + patch_info->ip.i;
4192 ia64_begin_bundle (code);
4194 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4196 /* Find a throw sequence for the same exception class */
4197 for (i = 0; i < nthrows; ++i)
4198 if (exc_classes [i] == exc_class)
4202 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4204 if (ia64_is_adds_imm (offset))
4205 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4207 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4209 buf = code.buf + code.nins;
4210 ia64_br_cond_pred (code, 0, 0);
4211 ia64_begin_bundle (code);
4212 ia64_patch (buf, exc_throw_start [i]);
4214 patch_info->type = MONO_PATCH_INFO_NONE;
4219 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4221 ia64_begin_bundle (code);
4224 exc_classes [nthrows] = exc_class;
4225 exc_throw_start [nthrows] = code.buf;
4229 if (ia64_is_adds_imm (exc_token_index))
4230 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4232 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4234 patch_info->data.name = "mono_arch_throw_corlib_exception";
4235 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4236 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4239 ia64_movl (code, GP_SCRATCH_REG, 0);
4240 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4241 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4242 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4244 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4246 /* Patch up the throw offset */
4247 ia64_begin_bundle (code);
4249 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4252 exc_throw_end [nthrows] = code.buf;
4266 /* The unwinder needs this to work */
4267 ia64_break_i (code, 0);
4269 ia64_codegen_close (code);
4272 //r_exceptions = mono_ia64_create_unwind_region (&code);
4273 //cfg->arch.r_epilog = r_exceptions;
4275 cfg->code_len = code.buf - cfg->native_code;
4277 g_assert (cfg->code_len < cfg->code_size);
4281 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4283 Ia64CodegenState code;
4284 CallInfo *cinfo = NULL;
4285 MonoMethodSignature *sig;
4287 int i, n, stack_area = 0;
4289 ia64_codegen_init (code, p);
4291 /* Keep this in sync with mono_arch_get_argument_info */
4293 if (enable_arguments) {
4294 /* Allocate a new area on the stack and save arguments there */
4295 sig = mono_method_signature (cfg->method);
4297 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4299 n = sig->param_count + sig->hasthis;
4301 stack_area = ALIGN_TO (n * 8, 16);
4304 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4306 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4308 /* FIXME: Allocate out registers */
4310 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4312 /* Required by the ABI */
4313 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4315 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4316 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4318 /* Save arguments to the stack */
4319 for (i = 0; i < n; ++i) {
4320 ins = cfg->args [i];
4322 if (ins->opcode == OP_REGVAR) {
4323 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4324 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4325 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4328 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4329 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4330 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4331 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4332 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4333 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4338 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4341 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4343 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4344 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4346 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4348 if (enable_arguments && stack_area) {
4349 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4351 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4353 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4356 ia64_codegen_close (code);
4362 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
4364 Ia64CodegenState code;
4365 CallInfo *cinfo = NULL;
4366 MonoMethod *method = cfg->method;
4367 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4369 ia64_codegen_init (code, p);
4371 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4373 /* Save return value + pass it to func */
4374 switch (cinfo->ret.storage) {
4378 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4379 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4382 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4383 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4384 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4385 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4387 case ArgValuetypeAddrInIReg:
4388 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4397 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4398 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4399 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4401 /* Restore return value */
4402 switch (cinfo->ret.storage) {
4406 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4409 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4410 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4412 case ArgValuetypeAddrInIReg:
4420 ia64_codegen_close (code);
4426 mono_arch_save_unwind_info (MonoCompile *cfg)
4430 /* FIXME: Unregister this for dynamic methods */
4432 di = g_malloc0 (sizeof (unw_dyn_info_t));
4433 di->start_ip = (unw_word_t) cfg->native_code;
4434 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4436 di->format = UNW_INFO_FORMAT_DYNAMIC;
4437 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4438 di->u.pi.regions = cfg->arch.r_pro;
4440 _U_dyn_register (di);
4444 unw_dyn_region_info_t *region = di->u.pi.regions;
4446 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4448 printf (" [Region: %d]\n", region->insn_count);
4449 region = region->next;
4456 mono_arch_flush_icache (guint8 *code, gint size)
4458 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4459 guint8* end = (guint8*)((guint64)code + size);
4461 #ifdef __INTEL_COMPILER
4462 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4469 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4470 /* FIXME: This could be increased to 128 on some cpus */
4477 mono_arch_flush_register_windows (void)
4479 /* Not needed because of libunwind */
4483 mono_arch_is_inst_imm (gint64 imm)
4485 /* The lowering pass will take care of it */
4491 * Determine whenever the trap whose info is in SIGINFO is caused by
4495 mono_arch_is_int_overflow (void *sigctx, void *info)
4497 /* Division is emulated with explicit overflow checks */
4502 mono_arch_get_patch_offset (guint8 *code)
4510 mono_arch_get_delegate_method_ptr_addr (guint8* code, mgreg_t *regs)
4518 mono_arch_finish_init (void)
4523 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4528 * LOCKING: called with the domain lock held
4531 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4532 gpointer fail_tramp)
4536 guint8 *start, *buf;
4537 Ia64CodegenState code;
4540 buf = g_malloc0 (size);
4541 ia64_codegen_init (code, buf);
4543 /* IA64_R9 contains the IMT method */
4545 for (i = 0; i < count; ++i) {
4546 MonoIMTCheckItem *item = imt_entries [i];
4547 ia64_begin_bundle (code);
4548 item->code_target = (guint8*)code.buf + code.nins;
4549 if (item->is_equals) {
4550 gboolean fail_case = !item->check_target_idx && fail_tramp;
4552 if (item->check_target_idx || fail_case) {
4553 if (!item->compare_done || fail_case) {
4554 ia64_movl (code, GP_SCRATCH_REG, item->key);
4555 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4557 item->jmp_code = (guint8*)code.buf + code.nins;
4558 ia64_br_cond_pred (code, 7, 0);
4560 if (item->has_target_code) {
4561 ia64_movl (code, GP_SCRATCH_REG, item->value.target_code);
4563 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4564 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4566 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4567 ia64_br_cond_reg (code, IA64_B6);
4570 ia64_begin_bundle (code);
4571 ia64_patch (item->jmp_code, (guint8*)code.buf + code.nins);
4572 ia64_movl (code, GP_SCRATCH_REG, fail_tramp);
4573 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4574 ia64_br_cond_reg (code, IA64_B6);
4575 item->jmp_code = NULL;
4578 /* enable the commented code to assert on wrong method */
4579 #if ENABLE_WRONG_METHOD_CHECK
4580 g_assert_not_reached ();
4582 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4583 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4584 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4585 ia64_br_cond_reg (code, IA64_B6);
4586 #if ENABLE_WRONG_METHOD_CHECK
4587 g_assert_not_reached ();
4591 ia64_movl (code, GP_SCRATCH_REG, item->key);
4592 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4593 item->jmp_code = (guint8*)code.buf + code.nins;
4594 ia64_br_cond_pred (code, 6, 0);
4597 /* patch the branches to get to the target items */
4598 for (i = 0; i < count; ++i) {
4599 MonoIMTCheckItem *item = imt_entries [i];
4600 if (item->jmp_code) {
4601 if (item->check_target_idx) {
4602 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4607 ia64_codegen_close (code);
4608 g_assert (code.buf - buf <= size);
4610 size = code.buf - buf;
4612 start = mono_method_alloc_generic_virtual_trampoline (domain, size + 16);
4613 start = (gpointer)ALIGN_TO (start, 16);
4615 start = mono_domain_code_reserve (domain, size);
4617 memcpy (start, buf, size);
4619 mono_arch_flush_icache (start, size);
4621 mono_stats.imt_thunks_size += size;
4623 mono_tramp_info_register (mono_tramp_info_create (NULL, start, size, NULL, NULL), domain);
4629 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
4631 return (MonoMethod*)regs [IA64_R9];
4635 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
4637 return (gpointer)regs [IA64_R10];
4641 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
4647 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
4653 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4655 MonoInst *ins = NULL;
4657 if (cmethod->klass->image == mono_defaults.corlib &&
4658 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4659 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4662 * We don't use the generic version in mini_emit_inst_for_method () since we
4663 * ia64 has atomic_add_imm opcodes.
4665 if (strcmp (cmethod->name, "Increment") == 0) {
4668 if (fsig->params [0]->type == MONO_TYPE_I4)
4669 opcode = OP_ATOMIC_ADD_IMM_I4;
4670 else if (fsig->params [0]->type == MONO_TYPE_I8)
4671 opcode = OP_ATOMIC_ADD_IMM_I8;
4673 g_assert_not_reached ();
4674 MONO_INST_NEW (cfg, ins, opcode);
4675 ins->dreg = mono_alloc_preg (cfg);
4677 ins->inst_basereg = args [0]->dreg;
4678 ins->inst_offset = 0;
4679 MONO_ADD_INS (cfg->cbb, ins);
4680 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4683 if (fsig->params [0]->type == MONO_TYPE_I4)
4684 opcode = OP_ATOMIC_ADD_IMM_I4;
4685 else if (fsig->params [0]->type == MONO_TYPE_I8)
4686 opcode = OP_ATOMIC_ADD_IMM_I8;
4688 g_assert_not_reached ();
4689 MONO_INST_NEW (cfg, ins, opcode);
4690 ins->dreg = mono_alloc_preg (cfg);
4692 ins->inst_basereg = args [0]->dreg;
4693 ins->inst_offset = 0;
4694 MONO_ADD_INS (cfg->cbb, ins);
4695 } else if (strcmp (cmethod->name, "Add") == 0) {
4697 gboolean is_imm = FALSE;
4700 if ((args [1]->opcode == OP_ICONST) || (args [1]->opcode == OP_I8CONST)) {
4701 imm = (args [1]->opcode == OP_ICONST) ? args [1]->inst_c0 : args [1]->inst_l;
4703 is_imm = (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
4707 if (fsig->params [0]->type == MONO_TYPE_I4)
4708 opcode = OP_ATOMIC_ADD_IMM_I4;
4709 else if (fsig->params [0]->type == MONO_TYPE_I8)
4710 opcode = OP_ATOMIC_ADD_IMM_I8;
4712 g_assert_not_reached ();
4714 MONO_INST_NEW (cfg, ins, opcode);
4715 ins->dreg = mono_alloc_ireg (cfg);
4716 ins->inst_basereg = args [0]->dreg;
4717 ins->inst_offset = 0;
4718 ins->inst_imm = imm;
4719 ins->type = (opcode == OP_ATOMIC_ADD_IMM_I4) ? STACK_I4 : STACK_I8;
4721 if (fsig->params [0]->type == MONO_TYPE_I4)
4722 opcode = OP_ATOMIC_ADD_I4;
4723 else if (fsig->params [0]->type == MONO_TYPE_I8)
4724 opcode = OP_ATOMIC_ADD_I8;
4726 g_assert_not_reached ();
4728 MONO_INST_NEW (cfg, ins, opcode);
4729 ins->dreg = mono_alloc_ireg (cfg);
4730 ins->inst_basereg = args [0]->dreg;
4731 ins->inst_offset = 0;
4732 ins->sreg2 = args [1]->dreg;
4733 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
4735 MONO_ADD_INS (cfg->cbb, ins);
4743 mono_arch_print_tree (MonoInst *tree, int arity)
4749 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4751 /* FIXME: implement */
4752 g_assert_not_reached ();
4756 mono_arch_opcode_supported (int opcode)
4759 case OP_ATOMIC_ADD_I4:
4760 case OP_ATOMIC_ADD_I8:
4761 case OP_ATOMIC_EXCHANGE_I4:
4762 case OP_ATOMIC_EXCHANGE_I8: