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) {
354 case MONO_TYPE_BOOLEAN:
365 case MONO_TYPE_FNPTR:
366 case MONO_TYPE_CLASS:
367 case MONO_TYPE_OBJECT:
368 case MONO_TYPE_SZARRAY:
369 case MONO_TYPE_ARRAY:
370 case MONO_TYPE_STRING:
371 cinfo->ret.storage = ArgInIReg;
372 cinfo->ret.reg = IA64_R8;
376 cinfo->ret.storage = ArgInIReg;
377 cinfo->ret.reg = IA64_R8;
381 cinfo->ret.storage = ArgInFloatReg;
384 case MONO_TYPE_GENERICINST:
385 if (!mono_type_generic_inst_is_valuetype (ret_type)) {
386 cinfo->ret.storage = ArgInIReg;
387 cinfo->ret.reg = IA64_R8;
391 case MONO_TYPE_VALUETYPE:
392 case MONO_TYPE_TYPEDBYREF: {
393 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
395 if (sig->ret->byref) {
396 /* This seems to happen with ldfld wrappers */
397 cinfo->ret.storage = ArgInIReg;
399 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
400 if (cinfo->ret.storage == ArgOnStack) {
401 /* The caller passes the address where the value is stored */
402 cinfo->vtype_retaddr = TRUE;
408 cinfo->ret.storage = ArgNone;
411 g_error ("Can't handle as return value 0x%x", sig->ret->type);
417 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
418 * the first argument, allowing 'this' to be always passed in the first arg reg.
419 * Also do this if the first argument is a reference type, since virtual calls
420 * are sometimes made using calli without sig->hasthis set, like in the delegate
423 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
425 add_general (&gr, &stack_size, cinfo->args + 0);
427 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
430 add_general (&gr, &stack_size, &cinfo->ret);
431 if (cinfo->ret.storage == ArgInIReg)
432 cinfo->ret.storage = ArgValuetypeAddrInIReg;
433 cinfo->vret_arg_index = 1;
437 add_general (&gr, &stack_size, cinfo->args + 0);
439 if (cinfo->vtype_retaddr) {
440 add_general (&gr, &stack_size, &cinfo->ret);
441 if (cinfo->ret.storage == ArgInIReg)
442 cinfo->ret.storage = ArgValuetypeAddrInIReg;
446 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
448 fr = FLOAT_PARAM_REGS;
450 /* Emit the signature cookie just before the implicit arguments */
451 add_general (&gr, &stack_size, &cinfo->sig_cookie);
454 for (i = pstart; i < sig->param_count; ++i) {
455 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
458 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
459 /* We allways pass the sig cookie on the stack for simplicity */
461 * Prevent implicit arguments + the sig cookie from being passed
465 fr = FLOAT_PARAM_REGS;
467 /* Emit the signature cookie just before the implicit arguments */
468 add_general (&gr, &stack_size, &cinfo->sig_cookie);
471 if (sig->params [i]->byref) {
472 add_general (&gr, &stack_size, ainfo);
475 ptype = mini_get_underlying_type (sig->params [i]);
476 switch (ptype->type) {
477 case MONO_TYPE_BOOLEAN:
480 add_general (&gr, &stack_size, ainfo);
485 add_general (&gr, &stack_size, ainfo);
489 add_general (&gr, &stack_size, ainfo);
494 case MONO_TYPE_FNPTR:
495 case MONO_TYPE_CLASS:
496 case MONO_TYPE_OBJECT:
497 case MONO_TYPE_STRING:
498 case MONO_TYPE_SZARRAY:
499 case MONO_TYPE_ARRAY:
500 add_general (&gr, &stack_size, ainfo);
502 case MONO_TYPE_GENERICINST:
503 if (!mono_type_generic_inst_is_valuetype (ptype)) {
504 add_general (&gr, &stack_size, ainfo);
508 case MONO_TYPE_VALUETYPE:
509 case MONO_TYPE_TYPEDBYREF:
511 /* We allways pass valuetypes on the stack */
512 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
516 add_general (&gr, &stack_size, ainfo);
519 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
522 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
525 g_assert_not_reached ();
529 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
531 fr = FLOAT_PARAM_REGS;
533 /* Emit the signature cookie just before the implicit arguments */
534 add_general (&gr, &stack_size, &cinfo->sig_cookie);
537 cinfo->stack_usage = stack_size;
538 cinfo->reg_usage = gr;
539 cinfo->freg_usage = fr;
544 * mono_arch_get_argument_info:
545 * @csig: a method signature
546 * @param_count: the number of parameters to consider
547 * @arg_info: an array to store the result infos
549 * Gathers information on parameters such as size, alignment and
550 * padding. arg_info should be large enought to hold param_count + 1 entries.
552 * Returns the size of the argument area on the stack.
555 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
558 CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
559 guint32 args_size = cinfo->stack_usage;
561 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
563 arg_info [0].offset = 0;
566 for (k = 0; k < param_count; k++) {
567 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
569 arg_info [k + 1].size = 0;
578 * Initialize the cpu to execute managed code.
581 mono_arch_cpu_init (void)
586 * Initialize architecture specific code.
589 mono_arch_init (void)
594 * Cleanup architecture specific code.
597 mono_arch_cleanup (void)
602 mono_arch_have_fast_tls (void)
608 * This function returns the optimizations supported on this cpu.
611 mono_arch_cpu_optimizations (guint32 *exclude_mask)
619 * This function test for all SIMD functions supported.
621 * Returns a bitmask corresponding to all supported versions.
625 mono_arch_cpu_enumerate_simd_versions (void)
627 /* SIMD is currently unimplemented */
632 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
636 MonoMethodSignature *sig;
637 MonoMethodHeader *header;
640 header = cfg->header;
642 sig = mono_method_signature (cfg->method);
644 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
646 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
647 MonoInst *ins = cfg->args [i];
649 ArgInfo *ainfo = &cinfo->args [i];
651 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
654 if (ainfo->storage == ArgInIReg) {
655 /* The input registers are non-volatile */
656 ins->opcode = OP_REGVAR;
657 ins->dreg = 32 + ainfo->reg;
661 for (i = 0; i < cfg->num_varinfo; i++) {
662 MonoInst *ins = cfg->varinfo [i];
663 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
666 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
669 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
670 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
673 if (mono_is_regsize_var (ins->inst_vtype)) {
674 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
675 g_assert (i == vmv->idx);
676 vars = g_list_prepend (vars, vmv);
680 vars = mono_varlist_sort (cfg, vars, 0);
686 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
689 guint32 reserved_regs;
690 MonoMethodHeader *header;
692 if (cfg->arch.reg_local0 > 0)
696 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
698 header = cfg->header;
700 /* Some registers are reserved for use by the prolog/epilog */
701 reserved_regs = header->num_clauses ? 4 : 3;
703 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
704 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
705 /* One registers is needed by instrument_epilog to save the return value */
707 if (cinfo->reg_usage < 2)
708 /* Number of arguments passed to function call in instrument_prolog */
709 cinfo->reg_usage = 2;
712 cfg->arch.reg_in0 = 32;
713 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
714 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
716 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
717 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
718 cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
721 * Frames without handlers save sp to fp, frames with handlers save it into
722 * a dedicated register.
724 if (header->num_clauses)
725 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
727 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
729 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
730 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
731 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
735 * Need to allocate at least 2 out register for use by OP_THROW / the system
736 * exception throwing code.
738 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
742 mono_arch_get_global_int_regs (MonoCompile *cfg)
747 mono_ia64_alloc_stacked_registers (cfg);
749 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
752 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
759 * mono_arch_regalloc_cost:
761 * Return the cost, in number of memory references, of the action of
762 * allocating the variable VMV into a register during global register
766 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
768 /* FIXME: Increase costs linearly to avoid using all local registers */
774 mono_arch_allocate_vars (MonoCompile *cfg)
776 MonoMethodSignature *sig;
777 MonoMethodHeader *header;
780 guint32 locals_stack_size, locals_stack_align;
784 header = cfg->header;
786 sig = mono_method_signature (cfg->method);
788 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
791 * Determine whenever the frame pointer can be eliminated.
792 * FIXME: Remove some of the restrictions.
794 cfg->arch.omit_fp = TRUE;
796 if (!debug_omit_fp ())
797 cfg->arch.omit_fp = FALSE;
799 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
800 cfg->arch.omit_fp = FALSE;
801 if (header->num_clauses)
802 cfg->arch.omit_fp = FALSE;
804 cfg->arch.omit_fp = FALSE;
805 if ((sig->ret->type != MONO_TYPE_VOID) && (cinfo->ret.storage == ArgAggregate))
806 cfg->arch.omit_fp = FALSE;
807 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
808 cfg->arch.omit_fp = FALSE;
809 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
810 ArgInfo *ainfo = &cinfo->args [i];
812 if (ainfo->storage == ArgOnStack) {
814 * The stack offset can only be determined when the frame
817 cfg->arch.omit_fp = FALSE;
821 mono_ia64_alloc_stacked_registers (cfg);
824 * We use the ABI calling conventions for managed code as well.
825 * Exception: valuetypes are never passed or returned in registers.
828 if (cfg->arch.omit_fp) {
829 cfg->flags |= MONO_CFG_HAS_SPILLUP;
830 cfg->frame_reg = IA64_SP;
831 offset = ARGS_OFFSET;
834 /* Locals are allocated backwards from %fp */
835 cfg->frame_reg = cfg->arch.reg_fp;
839 if (cfg->method->save_lmf) {
843 if (sig->ret->type != MONO_TYPE_VOID) {
844 switch (cinfo->ret.storage) {
846 cfg->ret->opcode = OP_REGVAR;
847 cfg->ret->inst_c0 = cinfo->ret.reg;
850 cfg->ret->opcode = OP_REGVAR;
851 cfg->ret->inst_c0 = cinfo->ret.reg;
853 case ArgValuetypeAddrInIReg:
854 cfg->vret_addr->opcode = OP_REGVAR;
855 cfg->vret_addr->dreg = cfg->arch.reg_in0 + cinfo->ret.reg;
858 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
859 if (cfg->arch.omit_fp)
860 g_assert_not_reached ();
861 offset = ALIGN_TO (offset, 8);
862 offset += cinfo->ret.nslots * 8;
863 cfg->ret->opcode = OP_REGOFFSET;
864 cfg->ret->inst_basereg = cfg->frame_reg;
865 cfg->ret->inst_offset = - offset;
868 g_assert_not_reached ();
870 cfg->ret->dreg = cfg->ret->inst_c0;
873 /* Allocate locals */
874 offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
875 if (locals_stack_align) {
876 offset = ALIGN_TO (offset, locals_stack_align);
878 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
879 if (offsets [i] != -1) {
880 MonoInst *inst = cfg->varinfo [i];
881 inst->opcode = OP_REGOFFSET;
882 inst->inst_basereg = cfg->frame_reg;
883 if (cfg->arch.omit_fp)
884 inst->inst_offset = (offset + offsets [i]);
886 inst->inst_offset = - (offset + offsets [i]);
887 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
890 offset += locals_stack_size;
892 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
893 if (cfg->arch.omit_fp)
894 g_assert_not_reached ();
895 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
896 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
899 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
900 inst = cfg->args [i];
901 if (inst->opcode != OP_REGVAR) {
902 ArgInfo *ainfo = &cinfo->args [i];
903 gboolean inreg = TRUE;
906 if (sig->hasthis && (i == 0))
907 arg_type = &mono_defaults.object_class->byval_arg;
909 arg_type = sig->params [i - sig->hasthis];
911 /* FIXME: VOLATILE is only set if the liveness pass runs */
912 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
915 inst->opcode = OP_REGOFFSET;
917 switch (ainfo->storage) {
919 inst->opcode = OP_REGVAR;
920 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
923 case ArgInFloatRegR4:
925 * Since float regs are volatile, we save the arguments to
926 * the stack in the prolog.
931 if (cfg->arch.omit_fp)
932 g_assert_not_reached ();
933 inst->opcode = OP_REGOFFSET;
934 inst->inst_basereg = cfg->frame_reg;
935 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
944 if (!inreg && (ainfo->storage != ArgOnStack)) {
947 inst->opcode = OP_REGOFFSET;
948 inst->inst_basereg = cfg->frame_reg;
949 /* These arguments are saved to the stack in the prolog */
950 switch (ainfo->storage) {
952 if (ainfo->atype == AggregateSingleHFA)
953 size = ainfo->nslots * 4;
955 size = ainfo->nslots * 8;
958 size = sizeof (gpointer);
962 offset = ALIGN_TO (offset, sizeof (gpointer));
964 if (cfg->arch.omit_fp) {
965 inst->inst_offset = offset;
969 inst->inst_offset = - offset;
976 * FIXME: This doesn't work because some variables are allocated during local
980 if (cfg->arch.omit_fp && offset == 16)
984 cfg->stack_offset = offset;
988 mono_arch_create_vars (MonoCompile *cfg)
990 MonoMethodSignature *sig;
993 sig = mono_method_signature (cfg->method);
995 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
997 if (cinfo->ret.storage == ArgAggregate)
998 cfg->ret_var_is_local = TRUE;
999 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
1000 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1001 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1002 printf ("vret_addr = ");
1003 mono_print_ins (cfg->vret_addr);
1009 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
1013 MONO_INST_NEW (cfg, arg, OP_NOP);
1014 arg->sreg1 = tree->dreg;
1018 arg->opcode = OP_MOVE;
1019 arg->dreg = mono_alloc_ireg (cfg);
1021 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, FALSE);
1024 arg->opcode = OP_FMOVE;
1025 arg->dreg = mono_alloc_freg (cfg);
1027 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1029 case ArgInFloatRegR4:
1030 arg->opcode = OP_FCONV_TO_R4;
1031 arg->dreg = mono_alloc_freg (cfg);
1033 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1036 g_assert_not_reached ();
1039 MONO_ADD_INS (cfg->cbb, arg);
1043 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1045 MonoMethodSignature *tmp_sig;
1047 /* Emit the signature cookie just before the implicit arguments */
1049 /* FIXME: Add support for signature tokens to AOT */
1050 cfg->disable_aot = TRUE;
1052 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1055 * mono_ArgIterator_Setup assumes the signature cookie is
1056 * passed first and all the arguments which were before it are
1057 * passed on the stack after the signature. So compensate by
1058 * passing a different signature.
1060 tmp_sig = mono_metadata_signature_dup (call->signature);
1061 tmp_sig->param_count -= call->signature->sentinelpos;
1062 tmp_sig->sentinelpos = 0;
1063 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1065 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1066 sig_arg->dreg = mono_alloc_ireg (cfg);
1067 sig_arg->inst_p0 = tmp_sig;
1068 MONO_ADD_INS (cfg->cbb, sig_arg);
1070 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + cinfo->sig_cookie.offset, sig_arg->dreg);
1074 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1077 MonoMethodSignature *sig;
1078 int i, n, stack_size;
1084 mono_ia64_alloc_stacked_registers (cfg);
1086 sig = call->signature;
1087 n = sig->param_count + sig->hasthis;
1089 cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1091 if (cinfo->ret.storage == ArgAggregate) {
1096 * The valuetype is in registers after the call, need to be copied
1097 * to the stack. Save the address to a local here, so the call
1098 * instruction can access it.
1100 local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1101 local->flags |= MONO_INST_VOLATILE;
1102 cfg->arch.ret_var_addr_local = local;
1104 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1105 vtarg->sreg1 = call->vret_var->dreg;
1106 vtarg->dreg = local->dreg;
1107 MONO_ADD_INS (cfg->cbb, vtarg);
1110 if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
1111 add_outarg_reg (cfg, call, ArgInIReg, cfg->arch.reg_out0 + cinfo->ret.reg, call->vret_var);
1114 for (i = 0; i < n; ++i) {
1117 ainfo = cinfo->args + i;
1119 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1120 /* Emit the signature cookie just before the implicit arguments */
1121 emit_sig_cookie (cfg, call, cinfo);
1124 in = call->args [i];
1126 if (sig->hasthis && (i == 0))
1127 arg_type = &mono_defaults.object_class->byval_arg;
1129 arg_type = sig->params [i - sig->hasthis];
1131 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1135 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1136 size = sizeof (MonoTypedRef);
1137 align = sizeof (gpointer);
1139 else if (sig->pinvoke)
1140 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1143 * Other backends use mono_type_stack_size (), but that
1144 * aligns the size to 8, which is larger than the size of
1145 * the source, leading to reads of invalid memory if the
1146 * source is at the end of address space.
1148 size = mono_class_value_size (in->klass, &align);
1154 MONO_INST_NEW (cfg, arg, OP_OUTARG_VT);
1155 arg->sreg1 = in->dreg;
1156 arg->klass = in->klass;
1157 arg->backend.size = size;
1158 arg->inst_p0 = call;
1159 arg->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1160 memcpy (arg->inst_p1, ainfo, sizeof (ArgInfo));
1162 MONO_ADD_INS (cfg->cbb, arg);
1166 switch (ainfo->storage) {
1168 add_outarg_reg (cfg, call, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1171 case ArgInFloatRegR4:
1172 add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, in);
1175 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref)
1176 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1177 else if (arg_type->type == MONO_TYPE_R8 && !arg_type->byref)
1178 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1180 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1183 g_assert_not_reached ();
1188 /* Handle the case where there are no implicit arguments */
1189 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1190 emit_sig_cookie (cfg, call, cinfo);
1193 call->stack_usage = cinfo->stack_usage;
1194 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1198 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1200 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1201 ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1202 int size = ins->backend.size;
1204 if (ainfo->storage == ArgAggregate) {
1205 MonoInst *load, *store;
1209 * Part of the structure is passed in registers.
1211 for (i = 0; i < ainfo->nregs; ++i) {
1212 slot = ainfo->reg + i;
1214 if (ainfo->atype == AggregateSingleHFA) {
1215 MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
1216 load->inst_basereg = src->dreg;
1217 load->inst_offset = i * 4;
1218 load->dreg = mono_alloc_freg (cfg);
1220 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1221 } else if (ainfo->atype == AggregateDoubleHFA) {
1222 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1223 load->inst_basereg = src->dreg;
1224 load->inst_offset = i * 8;
1225 load->dreg = mono_alloc_freg (cfg);
1227 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1229 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1230 load->inst_basereg = src->dreg;
1231 load->inst_offset = i * 8;
1232 load->dreg = mono_alloc_ireg (cfg);
1234 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, cfg->arch.reg_out0 + ainfo->reg + i, FALSE);
1236 MONO_ADD_INS (cfg->cbb, load);
1240 * Part of the structure is passed on the stack.
1242 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1243 slot = ainfo->reg + i;
1245 MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
1246 load->inst_basereg = src->dreg;
1247 load->inst_offset = i * sizeof (gpointer);
1248 load->dreg = mono_alloc_preg (cfg);
1249 MONO_ADD_INS (cfg->cbb, load);
1251 MONO_INST_NEW (cfg, store, OP_STOREI8_MEMBASE_REG);
1252 store->sreg1 = load->dreg;
1253 store->inst_destbasereg = IA64_SP;
1254 store->inst_offset = 16 + ainfo->offset + (slot - 8) * 8;
1255 MONO_ADD_INS (cfg->cbb, store);
1258 mini_emit_memcpy (cfg, IA64_SP, 16 + ainfo->offset, src->dreg, 0, size, 4);
1263 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1265 CallInfo *cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
1267 switch (cinfo->ret.storage) {
1269 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1272 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1275 g_assert_not_reached ();
1280 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1285 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1287 MonoInst *ins, *n, *last_ins = NULL;
1290 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1291 switch (ins->opcode) {
1299 if (ins->dreg == ins->sreg1) {
1300 MONO_DELETE_INS (bb, ins);
1306 * OP_MOVE sreg, dreg
1307 * OP_MOVE dreg, sreg
1309 if (last_ins && last_ins->opcode == OP_MOVE &&
1310 ins->sreg1 == last_ins->dreg &&
1311 ins->dreg == last_ins->sreg1) {
1312 MONO_DELETE_INS (bb, ins);
1318 /* remove unnecessary multiplication with 1 */
1319 if (ins->inst_imm == 1) {
1320 if (ins->dreg != ins->sreg1) {
1321 ins->opcode = OP_MOVE;
1323 MONO_DELETE_INS (bb, ins);
1333 bb->last_ins = last_ins;
1336 int cond_to_ia64_cmp [][3] = {
1337 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1338 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1339 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1340 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1341 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1342 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1343 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1344 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1345 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1346 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1350 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1352 return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1355 int cond_to_ia64_cmp_imm [][3] = {
1356 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1357 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1358 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1359 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1360 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1361 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1362 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1363 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1364 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1365 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1369 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1371 /* The condition needs to be reversed */
1372 return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1375 #define NEW_INS(cfg,dest,op) do { \
1376 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1377 (dest)->opcode = (op); \
1378 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1379 last_ins = (dest); \
1383 * mono_arch_lowering_pass:
1385 * Converts complex opcodes into simpler ones so that each IR instruction
1386 * corresponds to one machine instruction.
1389 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1391 MonoInst *ins, *n, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1394 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1395 switch (ins->opcode) {
1396 case OP_STOREI1_MEMBASE_IMM:
1397 case OP_STOREI2_MEMBASE_IMM:
1398 case OP_STOREI4_MEMBASE_IMM:
1399 case OP_STOREI8_MEMBASE_IMM:
1400 case OP_STORE_MEMBASE_IMM:
1401 /* There are no store_membase instructions on ia64 */
1402 if (ins->inst_offset == 0) {
1404 } else if (ia64_is_imm14 (ins->inst_offset)) {
1405 NEW_INS (cfg, temp2, OP_ADD_IMM);
1406 temp2->sreg1 = ins->inst_destbasereg;
1407 temp2->inst_imm = ins->inst_offset;
1408 temp2->dreg = mono_alloc_ireg (cfg);
1411 NEW_INS (cfg, temp, OP_I8CONST);
1412 temp->inst_c0 = ins->inst_offset;
1413 temp->dreg = mono_alloc_ireg (cfg);
1415 NEW_INS (cfg, temp2, OP_LADD);
1416 temp2->sreg1 = ins->inst_destbasereg;
1417 temp2->sreg2 = temp->dreg;
1418 temp2->dreg = mono_alloc_ireg (cfg);
1421 switch (ins->opcode) {
1422 case OP_STOREI1_MEMBASE_IMM:
1423 ins->opcode = OP_STOREI1_MEMBASE_REG;
1425 case OP_STOREI2_MEMBASE_IMM:
1426 ins->opcode = OP_STOREI2_MEMBASE_REG;
1428 case OP_STOREI4_MEMBASE_IMM:
1429 ins->opcode = OP_STOREI4_MEMBASE_REG;
1431 case OP_STOREI8_MEMBASE_IMM:
1432 case OP_STORE_MEMBASE_IMM:
1433 ins->opcode = OP_STOREI8_MEMBASE_REG;
1436 g_assert_not_reached ();
1439 if (ins->inst_imm == 0)
1440 ins->sreg1 = IA64_R0;
1442 NEW_INS (cfg, temp3, OP_I8CONST);
1443 temp3->inst_c0 = ins->inst_imm;
1444 temp3->dreg = mono_alloc_ireg (cfg);
1445 ins->sreg1 = temp3->dreg;
1448 ins->inst_offset = 0;
1450 ins->inst_destbasereg = temp2->dreg;
1452 case OP_STOREI1_MEMBASE_REG:
1453 case OP_STOREI2_MEMBASE_REG:
1454 case OP_STOREI4_MEMBASE_REG:
1455 case OP_STOREI8_MEMBASE_REG:
1456 case OP_STORER4_MEMBASE_REG:
1457 case OP_STORER8_MEMBASE_REG:
1458 case OP_STORE_MEMBASE_REG:
1459 /* There are no store_membase instructions on ia64 */
1460 if (ins->inst_offset == 0) {
1463 else if (ia64_is_imm14 (ins->inst_offset)) {
1464 NEW_INS (cfg, temp2, OP_ADD_IMM);
1465 temp2->sreg1 = ins->inst_destbasereg;
1466 temp2->inst_imm = ins->inst_offset;
1467 temp2->dreg = mono_alloc_ireg (cfg);
1470 NEW_INS (cfg, temp, OP_I8CONST);
1471 temp->inst_c0 = ins->inst_offset;
1472 temp->dreg = mono_alloc_ireg (cfg);
1473 NEW_INS (cfg, temp2, OP_LADD);
1474 temp2->sreg1 = ins->inst_destbasereg;
1475 temp2->sreg2 = temp->dreg;
1476 temp2->dreg = mono_alloc_ireg (cfg);
1479 ins->inst_offset = 0;
1480 ins->inst_destbasereg = temp2->dreg;
1482 case OP_LOADI1_MEMBASE:
1483 case OP_LOADU1_MEMBASE:
1484 case OP_LOADI2_MEMBASE:
1485 case OP_LOADU2_MEMBASE:
1486 case OP_LOADI4_MEMBASE:
1487 case OP_LOADU4_MEMBASE:
1488 case OP_LOADI8_MEMBASE:
1489 case OP_LOAD_MEMBASE:
1490 case OP_LOADR4_MEMBASE:
1491 case OP_LOADR8_MEMBASE:
1492 case OP_ATOMIC_EXCHANGE_I4:
1493 case OP_ATOMIC_EXCHANGE_I8:
1494 case OP_ATOMIC_ADD_I4:
1495 case OP_ATOMIC_ADD_I8:
1496 case OP_ATOMIC_ADD_IMM_I4:
1497 case OP_ATOMIC_ADD_IMM_I8:
1498 /* There are no membase instructions on ia64 */
1499 if (ins->inst_offset == 0) {
1502 else if (ia64_is_imm14 (ins->inst_offset)) {
1503 NEW_INS (cfg, temp2, OP_ADD_IMM);
1504 temp2->sreg1 = ins->inst_basereg;
1505 temp2->inst_imm = ins->inst_offset;
1506 temp2->dreg = mono_alloc_ireg (cfg);
1509 NEW_INS (cfg, temp, OP_I8CONST);
1510 temp->inst_c0 = ins->inst_offset;
1511 temp->dreg = mono_alloc_ireg (cfg);
1512 NEW_INS (cfg, temp2, OP_LADD);
1513 temp2->sreg1 = ins->inst_basereg;
1514 temp2->sreg2 = temp->dreg;
1515 temp2->dreg = mono_alloc_ireg (cfg);
1518 ins->inst_offset = 0;
1519 ins->inst_basereg = temp2->dreg;
1539 case OP_ISHR_UN_IMM:
1540 case OP_LSHR_UN_IMM: {
1541 gboolean is_imm = FALSE;
1542 gboolean switched = FALSE;
1544 if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1545 ins->opcode = OP_ZEXT_I1;
1549 switch (ins->opcode) {
1553 is_imm = ia64_is_imm14 (ins->inst_imm);
1558 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1560 /* A = B - IMM -> A = B + (-IMM) */
1561 ins->inst_imm = - ins->inst_imm;
1562 ins->opcode = OP_IADD_IMM;
1573 is_imm = ia64_is_imm8 (ins->inst_imm);
1582 case OP_ISHR_UN_IMM:
1583 case OP_LSHR_UN_IMM:
1584 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1592 ins->sreg2 = ins->sreg1;
1596 if (mono_op_imm_to_op (ins->opcode) == -1)
1597 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (ins->opcode));
1598 ins->opcode = mono_op_imm_to_op (ins->opcode);
1600 if (ins->inst_imm == 0)
1601 ins->sreg2 = IA64_R0;
1603 NEW_INS (cfg, temp, OP_I8CONST);
1604 temp->inst_c0 = ins->inst_imm;
1605 temp->dreg = mono_alloc_ireg (cfg);
1606 ins->sreg2 = temp->dreg;
1610 case OP_COMPARE_IMM:
1611 case OP_ICOMPARE_IMM:
1612 case OP_LCOMPARE_IMM: {
1613 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1619 /* Branch opts can eliminate the branch */
1620 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1626 * The compare_imm instructions have switched up arguments, and
1627 * some of them take an imm between -127 and 128.
1630 cond = mono_opcode_to_cond (next->opcode);
1631 if ((cond == CMP_LT) || (cond == CMP_GE))
1632 imm = ia64_is_imm8 (ins->inst_imm - 1);
1633 else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1634 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1636 imm = ia64_is_imm8 (ins->inst_imm);
1639 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1640 ins->sreg2 = ins->sreg1;
1643 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1645 if (ins->inst_imm == 0)
1646 ins->sreg2 = IA64_R0;
1648 NEW_INS (cfg, temp, OP_I8CONST);
1649 temp->inst_c0 = ins->inst_imm;
1650 temp->dreg = mono_alloc_ireg (cfg);
1651 ins->sreg2 = temp->dreg;
1655 if (MONO_IS_COND_BRANCH_OP (next)) {
1656 next->opcode = OP_IA64_BR_COND;
1657 next->inst_target_bb = next->inst_true_bb;
1658 } else if (MONO_IS_COND_EXC (next)) {
1659 next->opcode = OP_IA64_COND_EXC;
1660 } else if (MONO_IS_SETCC (next)) {
1661 next->opcode = OP_IA64_CSET;
1663 printf ("%s\n", mono_inst_name (next->opcode));
1673 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1677 /* Branch opts can eliminate the branch */
1678 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1683 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1685 if (MONO_IS_COND_BRANCH_OP (next)) {
1686 next->opcode = OP_IA64_BR_COND;
1687 next->inst_target_bb = next->inst_true_bb;
1688 } else if (MONO_IS_COND_EXC (next)) {
1689 next->opcode = OP_IA64_COND_EXC;
1690 } else if (MONO_IS_SETCC (next)) {
1691 next->opcode = OP_IA64_CSET;
1693 printf ("%s\n", mono_inst_name (next->opcode));
1704 /* The front end removes the fcompare, so introduce it again */
1705 NEW_INS (cfg, temp, opcode_to_ia64_cmp (ins->opcode, OP_FCOMPARE));
1706 temp->sreg1 = ins->sreg1;
1707 temp->sreg2 = ins->sreg2;
1709 ins->opcode = OP_IA64_CSET;
1710 MONO_INST_NULLIFY_SREGS (ins);
1716 gboolean found = FALSE;
1717 int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1719 /* First the easy cases */
1720 if (ins->inst_imm == 1) {
1721 ins->opcode = OP_MOVE;
1724 for (i = 1; i < 64; ++i)
1725 if (ins->inst_imm == (((gint64)1) << i)) {
1726 ins->opcode = shl_op;
1732 /* This could be optimized */
1735 for (i = 0; i < 64; ++i) {
1736 if (ins->inst_imm & (((gint64)1) << i)) {
1737 NEW_INS (cfg, temp, shl_op);
1738 temp->dreg = mono_alloc_ireg (cfg);
1739 temp->sreg1 = ins->sreg1;
1743 sum_reg = temp->dreg;
1745 NEW_INS (cfg, temp2, OP_LADD);
1746 temp2->dreg = mono_alloc_ireg (cfg);
1747 temp2->sreg1 = sum_reg;
1748 temp2->sreg2 = temp->dreg;
1749 sum_reg = temp2->dreg;
1753 ins->opcode = OP_MOVE;
1754 ins->sreg1 = sum_reg;
1758 case OP_LCONV_TO_OVF_U4:
1759 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1760 temp->sreg1 = ins->sreg1;
1761 temp->sreg2 = IA64_R0;
1763 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1764 temp->inst_p1 = (char*)"OverflowException";
1766 ins->opcode = OP_MOVE;
1768 case OP_LCONV_TO_OVF_I4_UN:
1769 NEW_INS (cfg, temp, OP_ICONST);
1770 temp->inst_c0 = 0x7fffffff;
1771 temp->dreg = mono_alloc_ireg (cfg);
1773 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1774 temp2->sreg1 = ins->sreg1;
1775 temp2->sreg2 = temp->dreg;
1777 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1778 temp->inst_p1 = (char*)"OverflowException";
1780 ins->opcode = OP_MOVE;
1782 case OP_FCONV_TO_I4:
1783 case OP_FCONV_TO_I2:
1784 case OP_FCONV_TO_U2:
1785 case OP_FCONV_TO_I1:
1786 case OP_FCONV_TO_U1:
1787 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1788 temp->sreg1 = ins->sreg1;
1789 temp->dreg = ins->dreg;
1791 switch (ins->opcode) {
1792 case OP_FCONV_TO_I4:
1793 ins->opcode = OP_SEXT_I4;
1795 case OP_FCONV_TO_I2:
1796 ins->opcode = OP_SEXT_I2;
1798 case OP_FCONV_TO_U2:
1799 ins->opcode = OP_ZEXT_I4;
1801 case OP_FCONV_TO_I1:
1802 ins->opcode = OP_SEXT_I1;
1804 case OP_FCONV_TO_U1:
1805 ins->opcode = OP_ZEXT_I1;
1808 g_assert_not_reached ();
1810 ins->sreg1 = ins->dreg;
1818 bb->last_ins = last_ins;
1820 bb->max_vreg = cfg->next_vreg;
1824 * emit_load_volatile_arguments:
1826 * Load volatile arguments from the stack to the original input registers.
1827 * Required before a tail call.
1829 static Ia64CodegenState
1830 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1832 MonoMethod *method = cfg->method;
1833 MonoMethodSignature *sig;
1838 /* FIXME: Generate intermediate code instead */
1840 sig = mono_method_signature (method);
1842 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
1844 /* This is the opposite of the code in emit_prolog */
1845 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1846 ArgInfo *ainfo = cinfo->args + i;
1847 gint32 stack_offset;
1850 ins = cfg->args [i];
1852 if (sig->hasthis && (i == 0))
1853 arg_type = &mono_defaults.object_class->byval_arg;
1855 arg_type = sig->params [i - sig->hasthis];
1857 arg_type = mini_get_underlying_type (arg_type);
1859 stack_offset = ainfo->offset + ARGS_OFFSET;
1861 /* Save volatile arguments to the stack */
1862 if (ins->opcode != OP_REGVAR) {
1863 switch (ainfo->storage) {
1866 /* FIXME: big offsets */
1867 g_assert (ins->opcode == OP_REGOFFSET);
1868 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1869 if (arg_type->byref)
1870 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1872 switch (arg_type->type) {
1874 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1877 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1880 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1892 if (ins->opcode == OP_REGVAR) {
1893 /* Argument allocated to (non-volatile) register */
1894 switch (ainfo->storage) {
1896 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1897 ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1900 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1901 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1912 static Ia64CodegenState
1913 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1918 /* Move return value to the target register */
1919 switch (ins->opcode) {
1921 case OP_VOIDCALL_REG:
1922 case OP_VOIDCALL_MEMBASE:
1926 case OP_CALL_MEMBASE:
1929 case OP_LCALL_MEMBASE:
1930 g_assert (ins->dreg == IA64_R8);
1934 case OP_FCALL_MEMBASE:
1935 g_assert (ins->dreg == 8);
1936 if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4)
1937 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
1941 case OP_VCALL_MEMBASE:
1944 case OP_VCALL2_MEMBASE: {
1947 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
1948 storage = cinfo->ret.storage;
1950 if (storage == ArgAggregate) {
1951 MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
1953 /* Load address of stack space allocated for the return value */
1954 ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
1955 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
1956 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
1958 for (i = 0; i < cinfo->ret.nregs; ++i) {
1959 switch (cinfo->ret.atype) {
1960 case AggregateNormal:
1961 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1963 case AggregateSingleHFA:
1964 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
1966 case AggregateDoubleHFA:
1967 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1970 g_assert_not_reached ();
1977 g_assert_not_reached ();
1983 #define add_patch_info(cfg,code,patch_type,data) do { \
1984 mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
1987 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
1988 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1990 add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
1992 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
1993 ia64_br_cond_pred (code, (predicate), 0); \
1996 static Ia64CodegenState
1997 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
1999 add_patch_info (cfg, code, patch_type, data);
2001 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2003 /* mono_arch_patch_callsite will patch this */
2004 ia64_movl (code, GP_SCRATCH_REG, 0);
2005 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2006 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2007 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2008 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2011 /* Can't use a direct call since the displacement might be too small */
2012 /* mono_arch_patch_callsite will patch this */
2013 ia64_movl (code, GP_SCRATCH_REG, 0);
2014 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2015 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2021 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2024 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2029 Ia64CodegenState code;
2030 guint8 *code_start = cfg->native_code + cfg->code_len;
2031 MonoInst *last_ins = NULL;
2032 guint last_offset = 0;
2035 if (cfg->opt & MONO_OPT_LOOP) {
2039 if (cfg->verbose_level > 2)
2040 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2042 cpos = bb->max_offset;
2044 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2048 offset = code_start - cfg->native_code;
2050 ia64_codegen_init (code, code_start);
2053 if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2057 MONO_BB_FOR_EACH_INS (bb, ins) {
2058 offset = code.buf - cfg->native_code;
2060 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2062 while (offset + max_len + 16 > cfg->code_size) {
2063 ia64_codegen_close (code);
2065 offset = code.buf - cfg->native_code;
2067 cfg->code_size *= 2;
2068 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2069 code_start = cfg->native_code + offset;
2070 cfg->stat_code_reallocs++;
2072 ia64_codegen_init (code, code_start);
2075 mono_debug_record_line_number (cfg, ins, offset);
2077 switch (ins->opcode) {
2080 if (ia64_is_imm14 (ins->inst_c0))
2081 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2083 ia64_movl (code, ins->dreg, ins->inst_c0);
2086 add_patch_info (cfg, code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2087 ia64_movl (code, ins->dreg, 0);
2090 ia64_mov (code, ins->dreg, ins->sreg1);
2093 case OP_IA64_BR_COND: {
2095 if (ins->opcode == OP_IA64_BR_COND)
2097 if (ins->inst_target_bb->native_offset) {
2098 guint8 *pos = code.buf + code.nins;
2100 ia64_br_cond_pred (code, pred, 0);
2101 ia64_begin_bundle (code);
2102 ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2104 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2105 ia64_br_cond_pred (code, pred, 0);
2110 ia64_begin_bundle (code);
2111 ins->inst_c0 = code.buf - cfg->native_code;
2114 case OP_RELAXED_NOP:
2116 case OP_DUMMY_STORE:
2117 case OP_NOT_REACHED:
2121 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2122 ia64_br_cond_reg (code, IA64_B6);
2126 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2130 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2134 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2138 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2142 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2146 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2150 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2154 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2157 ia64_sxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2158 ia64_shr (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2161 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2164 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2165 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2168 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2171 /* p6 and p7 is set if there is signed/unsigned overflow */
2173 /* Set p8-p9 == (sreg2 > 0) */
2174 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2176 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2178 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2179 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2180 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2181 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2183 /* res <u sreg1 => unsigned overflow */
2184 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2186 /* FIXME: Predicate this since this is a side effect */
2187 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2190 /* p6 and p7 is set if there is signed/unsigned overflow */
2192 /* Set p8-p9 == (sreg2 > 0) */
2193 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2195 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2197 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2198 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2199 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2200 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2202 /* sreg1 <u sreg2 => unsigned overflow */
2203 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2205 /* FIXME: Predicate this since this is a side effect */
2206 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2209 /* Same as OP_IADDCC */
2210 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2212 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2214 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2215 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2217 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2219 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2222 /* Same as OP_ISUBCC */
2224 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2226 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2228 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2229 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2231 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2233 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2238 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2243 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2247 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2251 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2256 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2260 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2263 g_assert (ins->inst_imm <= 64);
2264 ia64_extr (code, ins->dreg, ins->sreg1, ins->inst_imm, 32 - ins->inst_imm);
2266 case OP_ISHR_UN_IMM:
2267 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2268 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2270 case OP_LSHR_UN_IMM:
2271 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2274 /* Based on gcc code */
2275 ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2276 ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2277 ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2278 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2281 case OP_STOREI1_MEMBASE_REG:
2282 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2284 case OP_STOREI2_MEMBASE_REG:
2285 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2287 case OP_STOREI4_MEMBASE_REG:
2288 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2290 case OP_STOREI8_MEMBASE_REG:
2291 case OP_STORE_MEMBASE_REG:
2292 if (ins->inst_offset != 0) {
2293 /* This is generated by local regalloc */
2294 if (ia64_is_imm14 (ins->inst_offset)) {
2295 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2297 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2298 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2300 ins->inst_destbasereg = GP_SCRATCH_REG;
2302 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2305 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2306 ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2308 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2309 ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2311 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2312 ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2314 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2315 ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2318 case OP_LOADU1_MEMBASE:
2319 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2321 case OP_LOADU2_MEMBASE:
2322 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2324 case OP_LOADU4_MEMBASE:
2325 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2327 case OP_LOADI1_MEMBASE:
2328 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2329 ia64_sxt1 (code, ins->dreg, ins->dreg);
2331 case OP_LOADI2_MEMBASE:
2332 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2333 ia64_sxt2 (code, ins->dreg, ins->dreg);
2335 case OP_LOADI4_MEMBASE:
2336 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2337 ia64_sxt4 (code, ins->dreg, ins->dreg);
2339 case OP_LOAD_MEMBASE:
2340 case OP_LOADI8_MEMBASE:
2341 if (ins->inst_offset != 0) {
2342 /* This is generated by local regalloc */
2343 if (ia64_is_imm14 (ins->inst_offset)) {
2344 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2346 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2347 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2349 ins->inst_basereg = GP_SCRATCH_REG;
2351 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2354 case OP_IA64_LOADU1_MEMBASE_INC:
2355 ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2357 case OP_IA64_LOADU2_MEMBASE_INC:
2358 ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2360 case OP_IA64_LOADU4_MEMBASE_INC:
2361 ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2363 case OP_IA64_LOADI8_MEMBASE_INC:
2364 ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2368 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2371 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2374 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2377 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2380 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2383 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2386 /* Compare opcodes */
2387 case OP_IA64_CMP4_EQ:
2388 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2390 case OP_IA64_CMP4_NE:
2391 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2393 case OP_IA64_CMP4_LE:
2394 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2396 case OP_IA64_CMP4_LT:
2397 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2399 case OP_IA64_CMP4_GE:
2400 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2402 case OP_IA64_CMP4_GT:
2403 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2405 case OP_IA64_CMP4_LT_UN:
2406 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2408 case OP_IA64_CMP4_LE_UN:
2409 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2411 case OP_IA64_CMP4_GT_UN:
2412 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2414 case OP_IA64_CMP4_GE_UN:
2415 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2417 case OP_IA64_CMP_EQ:
2418 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2420 case OP_IA64_CMP_NE:
2421 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2423 case OP_IA64_CMP_LE:
2424 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2426 case OP_IA64_CMP_LT:
2427 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2429 case OP_IA64_CMP_GE:
2430 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2432 case OP_IA64_CMP_GT:
2433 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2435 case OP_IA64_CMP_GT_UN:
2436 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2438 case OP_IA64_CMP_LT_UN:
2439 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2441 case OP_IA64_CMP_GE_UN:
2442 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2444 case OP_IA64_CMP_LE_UN:
2445 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2447 case OP_IA64_CMP4_EQ_IMM:
2448 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2450 case OP_IA64_CMP4_NE_IMM:
2451 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2453 case OP_IA64_CMP4_LE_IMM:
2454 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2456 case OP_IA64_CMP4_LT_IMM:
2457 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2459 case OP_IA64_CMP4_GE_IMM:
2460 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2462 case OP_IA64_CMP4_GT_IMM:
2463 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2465 case OP_IA64_CMP4_LT_UN_IMM:
2466 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2468 case OP_IA64_CMP4_LE_UN_IMM:
2469 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2471 case OP_IA64_CMP4_GT_UN_IMM:
2472 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2474 case OP_IA64_CMP4_GE_UN_IMM:
2475 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2477 case OP_IA64_CMP_EQ_IMM:
2478 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2480 case OP_IA64_CMP_NE_IMM:
2481 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2483 case OP_IA64_CMP_LE_IMM:
2484 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2486 case OP_IA64_CMP_LT_IMM:
2487 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2489 case OP_IA64_CMP_GE_IMM:
2490 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2492 case OP_IA64_CMP_GT_IMM:
2493 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2495 case OP_IA64_CMP_GT_UN_IMM:
2496 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2498 case OP_IA64_CMP_LT_UN_IMM:
2499 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2501 case OP_IA64_CMP_GE_UN_IMM:
2502 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2504 case OP_IA64_CMP_LE_UN_IMM:
2505 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2507 case OP_IA64_FCMP_EQ:
2508 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2510 case OP_IA64_FCMP_NE:
2511 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2513 case OP_IA64_FCMP_LT:
2514 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2516 case OP_IA64_FCMP_GT:
2517 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2519 case OP_IA64_FCMP_LE:
2520 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2522 case OP_IA64_FCMP_GE:
2523 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2525 case OP_IA64_FCMP_GT_UN:
2526 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2527 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2529 case OP_IA64_FCMP_LT_UN:
2530 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2531 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2533 case OP_IA64_FCMP_GE_UN:
2534 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2535 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2537 case OP_IA64_FCMP_LE_UN:
2538 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2539 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2542 case OP_COND_EXC_IOV:
2543 case OP_COND_EXC_OV:
2544 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2546 case OP_COND_EXC_IC:
2548 emit_cond_system_exception (cfg, code, "OverflowException", 7);
2550 case OP_IA64_COND_EXC:
2551 emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2554 ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2555 ia64_no_stop (code);
2556 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2558 case OP_ICONV_TO_I1:
2559 case OP_LCONV_TO_I1:
2560 /* FIXME: Is this needed ? */
2561 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2563 case OP_ICONV_TO_I2:
2564 case OP_LCONV_TO_I2:
2565 /* FIXME: Is this needed ? */
2566 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2568 case OP_LCONV_TO_I4:
2569 /* FIXME: Is this needed ? */
2570 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2572 case OP_ICONV_TO_U1:
2573 case OP_LCONV_TO_U1:
2574 /* FIXME: Is this needed */
2575 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2577 case OP_ICONV_TO_U2:
2578 case OP_LCONV_TO_U2:
2579 /* FIXME: Is this needed */
2580 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2582 case OP_LCONV_TO_U4:
2583 /* FIXME: Is this needed */
2584 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2586 case OP_ICONV_TO_I8:
2588 case OP_LCONV_TO_I8:
2590 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2592 case OP_LCONV_TO_U8:
2594 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2601 double d = *(double *)ins->inst_p0;
2603 if ((d == 0.0) && (mono_signbit (d) == 0))
2604 ia64_fmov (code, ins->dreg, 0);
2606 ia64_fmov (code, ins->dreg, 1);
2608 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2609 ia64_movl (code, GP_SCRATCH_REG, 0);
2610 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2615 float f = *(float *)ins->inst_p0;
2617 if ((f == 0.0) && (mono_signbit (f) == 0))
2618 ia64_fmov (code, ins->dreg, 0);
2620 ia64_fmov (code, ins->dreg, 1);
2622 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2623 ia64_movl (code, GP_SCRATCH_REG, 0);
2624 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2629 ia64_fmov (code, ins->dreg, ins->sreg1);
2631 case OP_STORER8_MEMBASE_REG:
2632 if (ins->inst_offset != 0) {
2633 /* This is generated by local regalloc */
2634 if (ia64_is_imm14 (ins->inst_offset)) {
2635 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_destbasereg);
2637 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2638 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2640 ins->inst_destbasereg = GP_SCRATCH_REG;
2642 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2644 case OP_STORER4_MEMBASE_REG:
2645 ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2646 ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2648 case OP_LOADR8_MEMBASE:
2649 if (ins->inst_offset != 0) {
2650 /* This is generated by local regalloc */
2651 if (ia64_is_imm14 (ins->inst_offset)) {
2652 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
2654 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2655 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2657 ins->inst_basereg = GP_SCRATCH_REG;
2659 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2661 case OP_LOADR4_MEMBASE:
2662 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2663 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2665 case OP_ICONV_TO_R4:
2666 case OP_LCONV_TO_R4:
2667 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2668 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2669 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2671 case OP_ICONV_TO_R8:
2672 case OP_LCONV_TO_R8:
2673 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2674 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2675 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2677 case OP_FCONV_TO_R4:
2678 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2680 case OP_FCONV_TO_I8:
2682 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2683 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2686 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2689 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2692 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2695 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2699 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2700 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2702 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2703 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2704 /* Positive infinity */
2705 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2706 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2707 /* Negative infinity */
2708 ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2709 emit_cond_system_exception (cfg, code, "OverflowException", 6);
2714 /* ensure ins->sreg1 is not NULL */
2715 /* Can't use ld8 as this could be a vtype address */
2716 ia64_ld1 (code, GP_SCRATCH_REG, ins->sreg1);
2719 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2720 ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2728 call = (MonoCallInst*)ins;
2730 if (ins->flags & MONO_INST_HAS_METHOD)
2731 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2733 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2735 code = emit_move_return_value (cfg, ins, code);
2743 case OP_VOIDCALL_REG: {
2744 MonoCallInst *call = (MonoCallInst*)ins;
2749 * mono_arch_get_this_arg_from_call () needs to find the this argument in a global
2752 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2753 out_reg = cfg->arch.reg_out0;
2754 ia64_mov (code, IA64_R10, out_reg);
2757 ia64_mov (code, IA64_R8, ins->sreg1);
2758 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2759 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2760 ia64_ld8 (code, IA64_GP, IA64_R8);
2761 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2763 code = emit_move_return_value (cfg, ins, code);
2766 case OP_FCALL_MEMBASE:
2767 case OP_LCALL_MEMBASE:
2768 case OP_VCALL_MEMBASE:
2769 case OP_VCALL2_MEMBASE:
2770 case OP_VOIDCALL_MEMBASE:
2771 case OP_CALL_MEMBASE: {
2772 MonoCallInst *call = (MonoCallInst*)ins;
2776 ia64_mov (code, IA64_R11, ins->sreg1);
2777 if (ia64_is_imm14 (ins->inst_offset))
2778 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2780 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2781 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2784 if (call->method && ins->inst_offset < 0) {
2786 * This is a possible IMT call so save the IMT method in a global
2787 * register where mono_arch_find_imt_method () and its friends can
2790 ia64_movl (code, IA64_R9, call->method);
2794 * mono_arch_find_this_arg () needs to find the this argument in a global
2797 cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2798 out_reg = cfg->arch.reg_out0;
2799 ia64_mov (code, IA64_R10, out_reg);
2801 ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2803 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2805 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2807 code = emit_move_return_value (cfg, ins, code);
2812 * Keep in sync with the code in emit_epilog.
2815 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2818 g_assert (!cfg->method->save_lmf);
2820 /* Load arguments into their original registers */
2821 code = emit_load_volatile_arguments (cfg, code);
2823 if (cfg->arch.stack_alloc_size) {
2824 if (cfg->arch.omit_fp) {
2825 if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2826 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2828 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2829 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2833 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2835 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2836 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2838 add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2839 ia64_movl (code, GP_SCRATCH_REG, 0);
2840 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2841 ia64_br_cond_reg (code, IA64_B6);
2846 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
2852 /* FIXME: Sigaltstack support */
2854 /* keep alignment */
2855 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2856 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2857 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2859 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2861 ia64_mov (code, ins->dreg, IA64_SP);
2863 /* An area at sp is reserved by the ABI for parameter passing */
2864 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2865 if (ia64_is_adds_imm (abi_offset))
2866 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2868 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2869 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2872 if (ins->flags & MONO_INST_INIT) {
2874 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2876 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2879 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2880 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2881 ia64_br_cond_pred (code, 8, -2);
2883 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2885 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2890 case OP_LOCALLOC_IMM: {
2893 /* FIXME: Sigaltstack support */
2895 gssize size = ins->inst_imm;
2896 size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
2898 if (ia64_is_adds_imm (size))
2899 ia64_adds_imm (code, GP_SCRATCH_REG, size, IA64_R0);
2901 ia64_movl (code, GP_SCRATCH_REG, size);
2903 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2904 ia64_mov (code, ins->dreg, IA64_SP);
2906 /* An area at sp is reserved by the ABI for parameter passing */
2907 abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_FRAME_ALIGNMENT);
2908 if (ia64_is_adds_imm (abi_offset))
2909 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2911 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2912 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2915 if (ins->flags & MONO_INST_INIT) {
2917 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2919 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2922 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2923 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2924 ia64_br_cond_pred (code, 8, -2);
2926 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2928 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2933 /* Synchronization */
2934 case OP_MEMORY_BARRIER:
2937 case OP_ATOMIC_ADD_IMM_I4:
2938 g_assert (ins->inst_offset == 0);
2939 ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2940 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2942 case OP_ATOMIC_ADD_IMM_I8:
2943 g_assert (ins->inst_offset == 0);
2944 ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2945 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2947 case OP_ATOMIC_EXCHANGE_I4:
2948 ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2949 ia64_sxt4 (code, ins->dreg, ins->dreg);
2951 case OP_ATOMIC_EXCHANGE_I8:
2952 ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2954 case OP_ATOMIC_ADD_I4: {
2955 guint8 *label, *buf;
2957 /* From libatomic_ops */
2960 ia64_begin_bundle (code);
2961 label = code.buf + code.nins;
2962 ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2963 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2964 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2965 ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2966 ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2967 buf = code.buf + code.nins;
2968 ia64_br_cond_pred (code, 7, 0);
2969 ia64_begin_bundle (code);
2970 ia64_patch (buf, label);
2971 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2974 case OP_ATOMIC_ADD_I8: {
2975 guint8 *label, *buf;
2977 /* From libatomic_ops */
2980 ia64_begin_bundle (code);
2981 label = code.buf + code.nins;
2982 ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2983 ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2984 ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2985 ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2986 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2987 buf = code.buf + code.nins;
2988 ia64_br_cond_pred (code, 7, 0);
2989 ia64_begin_bundle (code);
2990 ia64_patch (buf, label);
2991 ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2995 /* Exception handling */
2996 case OP_CALL_HANDLER:
2998 * Using a call instruction would mess up the register stack, so
2999 * save the return address to a register and use a
3002 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3003 ia64_mov (code, IA64_R15, IA64_R0);
3004 ia64_mov_from_ip (code, GP_SCRATCH_REG);
3005 /* Add the length of OP_CALL_HANDLER */
3006 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3007 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3008 ia64_movl (code, GP_SCRATCH_REG2, 0);
3009 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3010 ia64_br_cond_reg (code, IA64_B6);
3012 //mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3013 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3015 case OP_START_HANDLER: {
3017 * We receive the return address in GP_SCRATCH_REG.
3019 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3022 * R15 determines our caller. It is used since it is writable using
3024 * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3025 * R15 != 0 means we are called by call_filter ().
3027 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3028 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3030 ia64_br_cond_pred (code, 6, 6);
3033 * Called by call_filter:
3034 * Allocate a new stack frame, and set the fp register from the
3035 * value passed in by the caller.
3036 * We allocate a similar frame as is done by the prolog, so
3037 * if an exception is thrown while executing the filter, the
3038 * unwinder can unwind through the filter frame using the unwind
3039 * info for the prolog.
3041 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);
3042 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3043 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3044 ia64_mov (code, cfg->frame_reg, IA64_R15);
3045 /* Signal to endfilter that we are called by call_filter */
3046 ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3048 /* Branch target: */
3049 if (ia64_is_imm14 (spvar->inst_offset))
3050 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3052 ia64_movl (code, GP_SCRATCH_REG2, spvar->inst_offset);
3053 ia64_add (code, GP_SCRATCH_REG2, cfg->frame_reg, GP_SCRATCH_REG2);
3056 /* Save the return address */
3057 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3058 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3063 case OP_ENDFILTER: {
3064 /* FIXME: Return the value in ENDFILTER */
3065 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3067 /* Load the return address */
3068 if (ia64_is_imm14 (spvar->inst_offset)) {
3069 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3071 ia64_movl (code, GP_SCRATCH_REG, spvar->inst_offset);
3072 ia64_add (code, GP_SCRATCH_REG, cfg->frame_reg, GP_SCRATCH_REG);
3074 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3077 ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3078 ia64_br_cond_pred (code, 7, 4);
3080 /* Called by call_filter */
3082 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3083 ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3084 ia64_br_ret_reg (code, IA64_B0);
3086 /* Called by CALL_HANDLER */
3087 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3088 ia64_br_cond_reg (code, IA64_B6);
3092 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3093 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3094 (gpointer)"mono_arch_throw_exception");
3097 * This might be the last instruction in the method, so add a dummy
3098 * instruction so the unwinder will work.
3100 ia64_break_i (code, 0);
3103 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3104 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3105 (gpointer)"mono_arch_rethrow_exception");
3107 ia64_break_i (code, 0);
3109 case OP_GC_SAFE_POINT:
3113 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3114 g_assert_not_reached ();
3117 if ((code.buf - cfg->native_code - offset) > max_len) {
3118 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3119 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3120 g_assert_not_reached ();
3126 last_offset = offset;
3129 ia64_codegen_close (code);
3131 cfg->code_len = code.buf - cfg->native_code;
3135 mono_arch_register_lowlevel_calls (void)
3139 static Ia64InsType ins_types_in_template [32][3] = {
3140 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3141 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3142 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3143 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3144 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3145 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3148 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3149 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3150 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3151 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3152 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3153 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3154 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3155 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3156 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3157 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3158 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3159 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3162 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3163 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3164 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3165 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3168 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3169 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3174 static gboolean stops_in_template [32][3] = {
3175 { FALSE, FALSE, FALSE },
3176 { FALSE, FALSE, TRUE },
3177 { FALSE, TRUE, FALSE },
3178 { FALSE, TRUE, TRUE },
3179 { FALSE, FALSE, FALSE },
3180 { FALSE, FALSE, TRUE },
3181 { FALSE, FALSE, FALSE },
3182 { FALSE, FALSE, FALSE },
3184 { FALSE, FALSE, FALSE },
3185 { FALSE, FALSE, TRUE },
3186 { TRUE, FALSE, FALSE },
3187 { TRUE, FALSE, TRUE },
3188 { FALSE, FALSE, FALSE },
3189 { FALSE, FALSE, TRUE },
3190 { FALSE, FALSE, FALSE },
3191 { FALSE, FALSE, TRUE },
3193 { FALSE, FALSE, FALSE },
3194 { FALSE, FALSE, TRUE },
3195 { FALSE, FALSE, FALSE },
3196 { FALSE, FALSE, TRUE },
3197 { FALSE, FALSE, FALSE },
3198 { FALSE, FALSE, FALSE },
3199 { FALSE, FALSE, FALSE },
3200 { FALSE, FALSE, TRUE },
3202 { FALSE, FALSE, FALSE },
3203 { FALSE, FALSE, TRUE },
3204 { FALSE, FALSE, FALSE },
3205 { FALSE, FALSE, FALSE },
3206 { FALSE, FALSE, FALSE },
3207 { FALSE, FALSE, TRUE },
3208 { FALSE, FALSE, FALSE },
3209 { FALSE, FALSE, FALSE }
3212 static int last_stop_in_template [32] = {
3213 -1, 2, 1, 2, -1, 2, -1, -1,
3214 -1, 2, 0, 2, -1, 2, -1, 2,
3215 -1, 2, -1, 2, -1, -1, -1, 2,
3216 -1, 2, -1, -1, -1, 2, -1, -1
3219 static guint64 nops_for_ins_types [6] = {
3228 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3235 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3237 #define DEBUG_INS_SCHED(a)
3241 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3243 int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3244 guint8 *deps = code->dep_info;
3245 gboolean need_stop, no_stop;
3247 for (i = 0; i < code->nins; ++i)
3251 current_deps_start = 0;
3252 current_ins_start = 0;
3253 deps_start [ins_index] = current_ins_start;
3256 DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3257 while (pos < code->dep_info_pos) {
3259 switch (deps [pos]) {
3260 case IA64_END_OF_INS:
3262 current_ins_start = pos + 2;
3263 deps_start [ins_index] = current_ins_start;
3265 DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3270 reg = deps [pos + 1];
3272 DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3273 for (i = current_deps_start; i < current_ins_start; i += 2)
3274 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3278 reg = code->dep_info [pos + 1];
3280 DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3281 for (i = current_deps_start; i < current_ins_start; i += 2)
3282 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3286 reg = deps [pos + 1];
3288 DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3289 for (i = current_deps_start; i < current_ins_start; i += 2)
3290 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3293 case IA64_READ_PR_BRANCH:
3294 reg = deps [pos + 1];
3296 /* Writes to prs by non-float instructions are visible to branches */
3297 DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3298 for (i = current_deps_start; i < current_ins_start; i += 2)
3299 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3303 reg = code->dep_info [pos + 1];
3305 DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3306 for (i = current_deps_start; i < current_ins_start; i += 2)
3307 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3310 case IA64_WRITE_PR_FLOAT:
3311 reg = code->dep_info [pos + 1];
3313 DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3314 for (i = current_deps_start; i < current_ins_start; i += 2)
3315 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3319 reg = deps [pos + 1];
3321 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3322 for (i = current_deps_start; i < current_ins_start; i += 2)
3323 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3327 reg = code->dep_info [pos + 1];
3329 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3330 for (i = current_deps_start; i < current_ins_start; i += 2)
3331 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3334 case IA64_READ_BR_BRANCH:
3335 reg = deps [pos + 1];
3337 /* Writes to brs are visible to branches */
3338 DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3341 reg = deps [pos + 1];
3343 DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3344 for (i = current_deps_start; i < current_ins_start; i += 2)
3345 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3349 reg = code->dep_info [pos + 1];
3351 DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3352 for (i = current_deps_start; i < current_ins_start; i += 2)
3353 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3357 reg = deps [pos + 1];
3359 DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3360 for (i = current_deps_start; i < current_ins_start; i += 2)
3361 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3365 reg = code->dep_info [pos + 1];
3367 DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3368 for (i = current_deps_start; i < current_ins_start; i += 2)
3369 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3374 * Explicitly indicate that a stop is not required. Useful for
3375 * example when two predicated instructions with negated predicates
3376 * write the same registers.
3381 g_assert_not_reached ();
3385 if (need_stop && !no_stop) {
3386 g_assert (ins_index > 0);
3387 stops [ins_index - 1] = 1;
3389 DEBUG_INS_SCHED (printf ("STOP\n"));
3390 current_deps_start = current_ins_start;
3392 /* Skip remaining deps for this instruction */
3393 while (deps [pos] != IA64_END_OF_INS)
3398 if (code->nins > 0) {
3399 /* No dependency info for the last instruction */
3400 stops [code->nins - 1] = 1;
3403 deps_start [code->nins] = code->dep_info_pos;
3407 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3409 int stop_pos, i, deps_to_shift, dep_shift;
3411 g_assert (n <= code->nins);
3413 // if (n > 1) printf ("FOUND: %ld.\n", template);
3415 ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3417 stop_pos = last_stop_in_template [template] + 1;
3421 /* Compute the number of 'real' instructions before the stop */
3422 deps_to_shift = stop_pos;
3423 if (stop_pos >= 3 && (nops & (1 << 2)))
3425 if (stop_pos >= 2 && (nops & (1 << 1)))
3427 if (stop_pos >= 1 && (nops & (1 << 0)))
3431 * We have to keep some dependencies whose instructions have been shifted
3432 * out of the buffer. So nullify the end_of_ins markers in the dependency
3435 for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3436 if (code->dep_info [i] == IA64_END_OF_INS)
3437 code->dep_info [i] = IA64_NONE;
3439 g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3440 memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3441 code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3443 dep_shift = deps_start [deps_to_shift];
3444 for (i = 0; i < code->nins + 1 - n; ++i)
3445 deps_start [i] = deps_start [n + i] - dep_shift;
3447 /* Determine the exact positions of instructions with unwind ops */
3448 if (code->unw_op_count) {
3450 int curr_ins, curr_ins_pos;
3453 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3454 for (i = 0; i < 3; ++i) {
3455 if (! (nops & (1 << i))) {
3456 ins_pos [curr_ins] = curr_ins_pos + i;
3461 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3462 if (code->unw_ops_pos [i] < n) {
3463 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3464 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3467 if (code->unw_op_pos < code->unw_op_count)
3468 code->unw_op_pos += n;
3471 if (n == code->nins) {
3476 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3477 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3478 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3484 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3486 int i, ins_type, template, nins_to_emit;
3487 int deps_start [16];
3492 * We implement a simple scheduler which tries to put three instructions
3493 * per bundle, then two, then one.
3495 ia64_analyze_deps (code, deps_start, stops);
3497 if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3498 /* Find a suitable template */
3499 for (template = 0; template < 32; ++template) {
3500 if (stops_in_template [template][0] != stops [0] ||
3501 stops_in_template [template][1] != stops [1] ||
3502 stops_in_template [template][2] != stops [2])
3506 for (i = 0; i < 3; ++i) {
3507 ins_type = ins_types_in_template [template][i];
3508 switch (code->itypes [i]) {
3509 case IA64_INS_TYPE_A:
3510 found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3513 found &= (ins_type == code->itypes [i]);
3519 found = debug_ins_sched ();
3522 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3528 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3529 /* Wait for more instructions */
3532 /* If it didn't work out, try putting two instructions into one bundle */
3533 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3534 /* Try a nop at the end */
3535 for (template = 0; template < 32; ++template) {
3536 if (stops_in_template [template][0] != stops [0] ||
3537 ((stops_in_template [template][1] != stops [1]) &&
3538 (stops_in_template [template][2] != stops [1])))
3542 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3543 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3546 if (!debug_ins_sched ())
3549 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);
3554 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3555 /* Wait for more instructions */
3558 if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3559 /* Try a nop in the middle */
3560 for (template = 0; template < 32; ++template) {
3561 if (((stops_in_template [template][0] != stops [0]) &&
3562 (stops_in_template [template][1] != stops [0])) ||
3563 stops_in_template [template][2] != stops [1])
3566 if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3567 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3570 if (!debug_ins_sched ())
3573 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);
3578 if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3579 /* Try a nop at the beginning */
3580 for (template = 0; template < 32; ++template) {
3581 if ((stops_in_template [template][1] != stops [0]) ||
3582 (stops_in_template [template][2] != stops [1]))
3585 if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3586 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3589 if (!debug_ins_sched ())
3592 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);
3597 if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3598 /* Wait for more instructions */
3602 nins_to_emit = code->nins;
3606 while (nins_to_emit > 0) {
3607 if (!debug_ins_sched ())
3609 switch (code->itypes [0]) {
3610 case IA64_INS_TYPE_A:
3612 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3614 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3616 case IA64_INS_TYPE_I:
3618 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3620 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3622 case IA64_INS_TYPE_M:
3624 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3626 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3628 case IA64_INS_TYPE_B:
3630 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3632 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3634 case IA64_INS_TYPE_F:
3636 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3638 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3640 case IA64_INS_TYPE_LX:
3641 if (stops [0] || stops [1])
3642 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3644 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3648 g_assert_not_reached ();
3654 unw_dyn_region_info_t*
3655 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3657 unw_dyn_region_info_t *r;
3659 g_assert (code->nins == 0);
3660 r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3661 memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3662 r->op_count = code->unw_op_count;
3663 r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3664 code->unw_op_count = 0;
3665 code->unw_op_pos = 0;
3666 code->region_start = code->buf;
3672 ia64_patch (unsigned char* code, gpointer target)
3675 guint64 instructions [3];
3676 guint8 gen_buf [16];
3677 Ia64CodegenState gen;
3682 * code encodes both the position inside the buffer and code.nins when
3683 * the instruction was emitted.
3685 ins_to_skip = (guint64)code % 16;
3686 code = (unsigned char*)((guint64)code & ~15);
3689 * Search for the first instruction which is 'patchable', skipping
3690 * ins_to_skip instructions.
3695 template = ia64_bundle_template (code);
3696 instructions [0] = ia64_bundle_ins1 (code);
3697 instructions [1] = ia64_bundle_ins2 (code);
3698 instructions [2] = ia64_bundle_ins3 (code);
3700 ia64_codegen_init (gen, gen_buf);
3703 for (i = 0; i < 3; ++i) {
3704 guint64 ins = instructions [i];
3705 int opcode = ia64_ins_opcode (ins);
3707 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3715 switch (ins_types_in_template [template][i]) {
3716 case IA64_INS_TYPE_A:
3717 case IA64_INS_TYPE_M:
3718 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3720 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3721 instructions [i] = gen.instructions [0];
3727 case IA64_INS_TYPE_B:
3728 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3730 gint64 disp = ((guint8*)target - code) >> 4;
3733 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3735 instructions [i] = gen.instructions [0];
3738 else if (opcode == 5) {
3740 gint64 disp = ((guint8*)target - code) >> 4;
3743 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3744 instructions [i] = gen.instructions [0];
3750 case IA64_INS_TYPE_LX:
3754 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3756 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3757 instructions [1] = gen.instructions [0];
3758 instructions [2] = gen.instructions [1];
3771 ia64_codegen_init (gen, code);
3772 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3782 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
3784 MonoJumpInfo *patch_info;
3788 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3789 unsigned char *ip = patch_info->ip.i + code;
3790 const unsigned char *target;
3792 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
3793 return_if_nok (error);
3795 if (patch_info->type == MONO_PATCH_INFO_NONE)
3797 if (mono_compile_aot) {
3801 ia64_patch (ip, (gpointer)target);
3806 mono_arch_emit_prolog (MonoCompile *cfg)
3808 MonoMethod *method = cfg->method;
3809 MonoMethodSignature *sig;
3811 int alloc_size, pos, i;
3812 Ia64CodegenState code;
3815 sig = mono_method_signature (method);
3818 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
3820 cfg->code_size = MAX (cfg->header->code_size * 4, 512);
3822 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3823 cfg->code_size += 1024;
3824 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3825 cfg->code_size += 1024;
3827 cfg->native_code = g_malloc (cfg->code_size);
3829 ia64_codegen_init (code, cfg->native_code);
3831 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3832 if (cfg->param_area)
3833 alloc_size += cfg->param_area;
3837 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3839 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3840 /* Force sp to be saved/restored */
3841 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3843 cfg->arch.stack_alloc_size = alloc_size;
3847 if (method->save_lmf) {
3848 /* No LMF on IA64 */
3853 ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3854 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);
3855 ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3856 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3858 if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3859 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3860 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3861 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3862 ia64_mov (code, cfg->frame_reg, IA64_SP);
3866 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3867 int pagesize = getpagesize ();
3869 if (alloc_size >= pagesize) {
3870 gint32 remaining_size = alloc_size;
3872 /* Generate stack touching code */
3873 ia64_mov (code, GP_SCRATCH_REG, IA64_SP);
3874 while (remaining_size >= pagesize) {
3875 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3876 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3877 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3878 remaining_size -= pagesize;
3882 if (ia64_is_imm14 (-alloc_size)) {
3883 if (cfg->arch.omit_fp)
3884 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3885 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3888 ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3889 if (cfg->arch.omit_fp)
3890 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3891 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3895 ia64_begin_bundle (code);
3897 /* Initialize unwind info */
3898 cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3900 if (sig->ret->type != MONO_TYPE_VOID) {
3901 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3902 /* Save volatile arguments to the stack */
3907 /* Keep this in sync with emit_load_volatile_arguments */
3908 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3909 ArgInfo *ainfo = cinfo->args + i;
3910 gint32 stack_offset;
3913 inst = cfg->args [i];
3915 if (sig->hasthis && (i == 0))
3916 arg_type = &mono_defaults.object_class->byval_arg;
3918 arg_type = sig->params [i - sig->hasthis];
3920 arg_type = mini_get_underlying_type (arg_type);
3922 stack_offset = ainfo->offset + ARGS_OFFSET;
3925 * FIXME: Native code might pass non register sized integers
3926 * without initializing the upper bits.
3928 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED && !arg_type->byref && ainfo->storage == ArgInIReg) {
3929 int reg = cfg->arch.reg_in0 + ainfo->reg;
3931 switch (mono_type_to_load_membase (cfg, arg_type)) {
3932 case OP_LOADI1_MEMBASE:
3933 ia64_sxt1 (code, reg, reg);
3935 case OP_LOADU1_MEMBASE:
3936 ia64_zxt1 (code, reg, reg);
3938 case OP_LOADI2_MEMBASE:
3939 ia64_sxt2 (code, reg, reg);
3941 case OP_LOADU2_MEMBASE:
3942 ia64_zxt2 (code, reg, reg);
3949 /* Save volatile arguments to the stack */
3950 if (inst->opcode != OP_REGVAR) {
3951 switch (ainfo->storage) {
3954 case ArgInFloatRegR4:
3955 g_assert (inst->opcode == OP_REGOFFSET);
3956 if (ia64_is_adds_imm (inst->inst_offset))
3957 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3959 ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3960 ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3962 if (arg_type->byref)
3963 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3965 switch (arg_type->type) {
3967 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3970 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3973 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3981 if (ainfo->nslots != ainfo->nregs)
3984 g_assert (inst->opcode == OP_REGOFFSET);
3985 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3986 for (i = 0; i < ainfo->nregs; ++i) {
3987 switch (ainfo->atype) {
3988 case AggregateNormal:
3989 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3991 case AggregateSingleHFA:
3992 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3994 case AggregateDoubleHFA:
3995 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
4003 g_assert_not_reached ();
4007 if (inst->opcode == OP_REGVAR) {
4008 /* Argument allocated to (non-volatile) register */
4009 switch (ainfo->storage) {
4011 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4012 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4015 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4016 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4024 if (method->save_lmf) {
4025 /* No LMF on IA64 */
4028 ia64_codegen_close (code);
4030 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4031 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4033 cfg->code_len = code.buf - cfg->native_code;
4035 g_assert (cfg->code_len < cfg->code_size);
4037 cfg->arch.prolog_end_offset = cfg->code_len;
4043 mono_arch_emit_epilog (MonoCompile *cfg)
4045 MonoMethod *method = cfg->method;
4047 int max_epilog_size = 16 * 4;
4048 Ia64CodegenState code;
4053 if (mono_jit_trace_calls != NULL)
4054 max_epilog_size += 1024;
4056 cfg->arch.epilog_begin_offset = cfg->code_len;
4058 while (cfg->code_len + max_epilog_size > cfg->code_size) {
4059 cfg->code_size *= 2;
4060 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4061 cfg->stat_code_reallocs++;
4064 /* FIXME: Emit unwind info */
4066 buf = cfg->native_code + cfg->code_len;
4068 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4069 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4071 ia64_codegen_init (code, buf);
4073 /* the code restoring the registers must be kept in sync with OP_JMP */
4076 if (method->save_lmf) {
4077 /* No LMF on IA64 */
4080 /* Load returned vtypes into registers if needed */
4081 cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4082 ainfo = &cinfo->ret;
4083 switch (ainfo->storage) {
4085 if (ainfo->nslots != ainfo->nregs)
4088 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4089 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4090 for (i = 0; i < ainfo->nregs; ++i) {
4091 switch (ainfo->atype) {
4092 case AggregateNormal:
4093 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4095 case AggregateSingleHFA:
4096 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4098 case AggregateDoubleHFA:
4099 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4102 g_assert_not_reached ();
4110 ia64_begin_bundle (code);
4112 code.region_start = cfg->native_code;
4114 /* Label the unwind state at the start of the exception throwing region */
4115 //ia64_unw_label_state (code, 1234);
4117 if (cfg->arch.stack_alloc_size) {
4118 if (cfg->arch.omit_fp) {
4119 if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4120 ia64_unw_pop_frames (code, 1);
4121 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4123 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4124 ia64_unw_pop_frames (code, 1);
4125 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4129 ia64_unw_pop_frames (code, 1);
4130 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4133 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4134 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4135 ia64_br_ret_reg (code, IA64_B0);
4137 ia64_codegen_close (code);
4139 cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4140 cfg->arch.r_pro->next = cfg->arch.r_epilog;
4142 cfg->code_len = code.buf - cfg->native_code;
4144 g_assert (cfg->code_len < cfg->code_size);
4148 mono_arch_emit_exceptions (MonoCompile *cfg)
4150 MonoJumpInfo *patch_info;
4152 Ia64CodegenState code;
4153 gboolean empty = TRUE;
4154 //unw_dyn_region_info_t *r_exceptions;
4155 MonoClass *exc_classes [16];
4156 guint8 *exc_throw_start [16], *exc_throw_end [16];
4157 guint32 code_size = 0;
4159 /* Compute needed space */
4160 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4161 if (patch_info->type == MONO_PATCH_INFO_EXC)
4163 if (patch_info->type == MONO_PATCH_INFO_R8)
4164 code_size += 8 + 7; /* sizeof (double) + alignment */
4165 if (patch_info->type == MONO_PATCH_INFO_R4)
4166 code_size += 4 + 7; /* sizeof (float) + alignment */
4172 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4173 cfg->code_size *= 2;
4174 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4175 cfg->stat_code_reallocs++;
4178 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4180 /* The unwind state here is the same as before the epilog */
4181 //ia64_unw_copy_state (code, 1234);
4183 /* add code to raise exceptions */
4184 /* FIXME: Optimize this */
4186 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4187 switch (patch_info->type) {
4188 case MONO_PATCH_INFO_EXC: {
4189 MonoClass *exc_class;
4192 guint64 exc_token_index;
4194 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4195 exc_token_index = mono_metadata_token_index (exc_class->type_token);
4196 throw_ip = cfg->native_code + patch_info->ip.i;
4198 ia64_begin_bundle (code);
4200 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4202 /* Find a throw sequence for the same exception class */
4203 for (i = 0; i < nthrows; ++i)
4204 if (exc_classes [i] == exc_class)
4208 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4210 if (ia64_is_adds_imm (offset))
4211 ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4213 ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4215 buf = code.buf + code.nins;
4216 ia64_br_cond_pred (code, 0, 0);
4217 ia64_begin_bundle (code);
4218 ia64_patch (buf, exc_throw_start [i]);
4220 patch_info->type = MONO_PATCH_INFO_NONE;
4225 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4227 ia64_begin_bundle (code);
4230 exc_classes [nthrows] = exc_class;
4231 exc_throw_start [nthrows] = code.buf;
4235 if (ia64_is_adds_imm (exc_token_index))
4236 ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4238 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4240 patch_info->data.name = "mono_arch_throw_corlib_exception";
4241 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4242 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4245 ia64_movl (code, GP_SCRATCH_REG, 0);
4246 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4247 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4248 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4250 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4252 /* Patch up the throw offset */
4253 ia64_begin_bundle (code);
4255 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4258 exc_throw_end [nthrows] = code.buf;
4272 /* The unwinder needs this to work */
4273 ia64_break_i (code, 0);
4275 ia64_codegen_close (code);
4278 //r_exceptions = mono_ia64_create_unwind_region (&code);
4279 //cfg->arch.r_epilog = r_exceptions;
4281 cfg->code_len = code.buf - cfg->native_code;
4283 g_assert (cfg->code_len < cfg->code_size);
4287 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4289 Ia64CodegenState code;
4290 CallInfo *cinfo = NULL;
4291 MonoMethodSignature *sig;
4293 int i, n, stack_area = 0;
4295 ia64_codegen_init (code, p);
4297 /* Keep this in sync with mono_arch_get_argument_info */
4299 if (enable_arguments) {
4300 /* Allocate a new area on the stack and save arguments there */
4301 sig = mono_method_signature (cfg->method);
4303 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4305 n = sig->param_count + sig->hasthis;
4307 stack_area = ALIGN_TO (n * 8, 16);
4310 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4312 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4314 /* FIXME: Allocate out registers */
4316 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4318 /* Required by the ABI */
4319 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4321 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4322 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4324 /* Save arguments to the stack */
4325 for (i = 0; i < n; ++i) {
4326 ins = cfg->args [i];
4328 if (ins->opcode == OP_REGVAR) {
4329 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4330 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4331 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4334 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4335 ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4336 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4337 ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4338 ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4339 ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4344 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4347 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4349 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4350 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4352 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4354 if (enable_arguments && stack_area) {
4355 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4357 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4359 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4362 ia64_codegen_close (code);
4368 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
4370 Ia64CodegenState code;
4371 CallInfo *cinfo = NULL;
4372 MonoMethod *method = cfg->method;
4373 MonoMethodSignature *sig = mono_method_signature (cfg->method);
4375 ia64_codegen_init (code, p);
4377 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4379 /* Save return value + pass it to func */
4380 switch (cinfo->ret.storage) {
4384 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4385 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4388 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4389 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4390 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4391 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4393 case ArgValuetypeAddrInIReg:
4394 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4403 add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4404 ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4405 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4407 /* Restore return value */
4408 switch (cinfo->ret.storage) {
4412 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4415 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4416 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4418 case ArgValuetypeAddrInIReg:
4426 ia64_codegen_close (code);
4432 mono_arch_save_unwind_info (MonoCompile *cfg)
4436 /* FIXME: Unregister this for dynamic methods */
4438 di = g_malloc0 (sizeof (unw_dyn_info_t));
4439 di->start_ip = (unw_word_t) cfg->native_code;
4440 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4442 di->format = UNW_INFO_FORMAT_DYNAMIC;
4443 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4444 di->u.pi.regions = cfg->arch.r_pro;
4446 _U_dyn_register (di);
4450 unw_dyn_region_info_t *region = di->u.pi.regions;
4452 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4454 printf (" [Region: %d]\n", region->insn_count);
4455 region = region->next;
4462 mono_arch_flush_icache (guint8 *code, gint size)
4464 guint8* p = (guint8*)((guint64)code & ~(0x3f));
4465 guint8* end = (guint8*)((guint64)code + size);
4467 #ifdef __INTEL_COMPILER
4468 /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4475 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4476 /* FIXME: This could be increased to 128 on some cpus */
4483 mono_arch_flush_register_windows (void)
4485 /* Not needed because of libunwind */
4489 mono_arch_is_inst_imm (gint64 imm)
4491 /* The lowering pass will take care of it */
4497 * Determine whenever the trap whose info is in SIGINFO is caused by
4501 mono_arch_is_int_overflow (void *sigctx, void *info)
4503 /* Division is emulated with explicit overflow checks */
4508 mono_arch_get_patch_offset (guint8 *code)
4516 mono_arch_get_delegate_method_ptr_addr (guint8* code, mgreg_t *regs)
4524 mono_arch_finish_init (void)
4529 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4534 * LOCKING: called with the domain lock held
4537 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4538 gpointer fail_tramp)
4542 guint8 *start, *buf;
4543 Ia64CodegenState code;
4546 buf = g_malloc0 (size);
4547 ia64_codegen_init (code, buf);
4549 /* IA64_R9 contains the IMT method */
4551 for (i = 0; i < count; ++i) {
4552 MonoIMTCheckItem *item = imt_entries [i];
4553 ia64_begin_bundle (code);
4554 item->code_target = (guint8*)code.buf + code.nins;
4555 if (item->is_equals) {
4556 gboolean fail_case = !item->check_target_idx && fail_tramp;
4558 if (item->check_target_idx || fail_case) {
4559 if (!item->compare_done || fail_case) {
4560 ia64_movl (code, GP_SCRATCH_REG, item->key);
4561 ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4563 item->jmp_code = (guint8*)code.buf + code.nins;
4564 ia64_br_cond_pred (code, 7, 0);
4566 if (item->has_target_code) {
4567 ia64_movl (code, GP_SCRATCH_REG, item->value.target_code);
4569 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4570 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4572 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4573 ia64_br_cond_reg (code, IA64_B6);
4576 ia64_begin_bundle (code);
4577 ia64_patch (item->jmp_code, (guint8*)code.buf + code.nins);
4578 ia64_movl (code, GP_SCRATCH_REG, fail_tramp);
4579 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4580 ia64_br_cond_reg (code, IA64_B6);
4581 item->jmp_code = NULL;
4584 /* enable the commented code to assert on wrong method */
4585 #if ENABLE_WRONG_METHOD_CHECK
4586 g_assert_not_reached ();
4588 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4589 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4590 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4591 ia64_br_cond_reg (code, IA64_B6);
4592 #if ENABLE_WRONG_METHOD_CHECK
4593 g_assert_not_reached ();
4597 ia64_movl (code, GP_SCRATCH_REG, item->key);
4598 ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4599 item->jmp_code = (guint8*)code.buf + code.nins;
4600 ia64_br_cond_pred (code, 6, 0);
4603 /* patch the branches to get to the target items */
4604 for (i = 0; i < count; ++i) {
4605 MonoIMTCheckItem *item = imt_entries [i];
4606 if (item->jmp_code) {
4607 if (item->check_target_idx) {
4608 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4613 ia64_codegen_close (code);
4614 g_assert (code.buf - buf <= size);
4616 size = code.buf - buf;
4618 start = mono_method_alloc_generic_virtual_trampoline (domain, size + 16);
4619 start = (gpointer)ALIGN_TO (start, 16);
4621 start = mono_domain_code_reserve (domain, size);
4623 memcpy (start, buf, size);
4625 mono_arch_flush_icache (start, size);
4627 mono_stats.imt_thunks_size += size;
4629 mono_tramp_info_register (mono_tramp_info_create (NULL, start, size, NULL, NULL), domain);
4635 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
4637 return (MonoMethod*)regs [IA64_R9];
4641 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
4643 return (gpointer)regs [IA64_R10];
4647 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
4653 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
4659 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4661 MonoInst *ins = NULL;
4663 if (cmethod->klass->image == mono_defaults.corlib &&
4664 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4665 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4668 * We don't use the generic version in mini_emit_inst_for_method () since we
4669 * ia64 has atomic_add_imm opcodes.
4671 if (strcmp (cmethod->name, "Increment") == 0) {
4674 if (fsig->params [0]->type == MONO_TYPE_I4)
4675 opcode = OP_ATOMIC_ADD_IMM_I4;
4676 else if (fsig->params [0]->type == MONO_TYPE_I8)
4677 opcode = OP_ATOMIC_ADD_IMM_I8;
4679 g_assert_not_reached ();
4680 MONO_INST_NEW (cfg, ins, opcode);
4681 ins->dreg = mono_alloc_preg (cfg);
4683 ins->inst_basereg = args [0]->dreg;
4684 ins->inst_offset = 0;
4685 MONO_ADD_INS (cfg->cbb, ins);
4686 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4689 if (fsig->params [0]->type == MONO_TYPE_I4)
4690 opcode = OP_ATOMIC_ADD_IMM_I4;
4691 else if (fsig->params [0]->type == MONO_TYPE_I8)
4692 opcode = OP_ATOMIC_ADD_IMM_I8;
4694 g_assert_not_reached ();
4695 MONO_INST_NEW (cfg, ins, opcode);
4696 ins->dreg = mono_alloc_preg (cfg);
4698 ins->inst_basereg = args [0]->dreg;
4699 ins->inst_offset = 0;
4700 MONO_ADD_INS (cfg->cbb, ins);
4701 } else if (strcmp (cmethod->name, "Add") == 0) {
4703 gboolean is_imm = FALSE;
4706 if ((args [1]->opcode == OP_ICONST) || (args [1]->opcode == OP_I8CONST)) {
4707 imm = (args [1]->opcode == OP_ICONST) ? args [1]->inst_c0 : args [1]->inst_l;
4709 is_imm = (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
4713 if (fsig->params [0]->type == MONO_TYPE_I4)
4714 opcode = OP_ATOMIC_ADD_IMM_I4;
4715 else if (fsig->params [0]->type == MONO_TYPE_I8)
4716 opcode = OP_ATOMIC_ADD_IMM_I8;
4718 g_assert_not_reached ();
4720 MONO_INST_NEW (cfg, ins, opcode);
4721 ins->dreg = mono_alloc_ireg (cfg);
4722 ins->inst_basereg = args [0]->dreg;
4723 ins->inst_offset = 0;
4724 ins->inst_imm = imm;
4725 ins->type = (opcode == OP_ATOMIC_ADD_IMM_I4) ? STACK_I4 : STACK_I8;
4727 if (fsig->params [0]->type == MONO_TYPE_I4)
4728 opcode = OP_ATOMIC_ADD_I4;
4729 else if (fsig->params [0]->type == MONO_TYPE_I8)
4730 opcode = OP_ATOMIC_ADD_I8;
4732 g_assert_not_reached ();
4734 MONO_INST_NEW (cfg, ins, opcode);
4735 ins->dreg = mono_alloc_ireg (cfg);
4736 ins->inst_basereg = args [0]->dreg;
4737 ins->inst_offset = 0;
4738 ins->sreg2 = args [1]->dreg;
4739 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
4741 MONO_ADD_INS (cfg->cbb, ins);
4749 mono_arch_print_tree (MonoInst *tree, int arity)
4755 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4757 /* FIXME: implement */
4758 g_assert_not_reached ();
4762 mono_arch_opcode_supported (int opcode)
4765 case OP_ATOMIC_ADD_I4:
4766 case OP_ATOMIC_ADD_I8:
4767 case OP_ATOMIC_EXCHANGE_I4:
4768 case OP_ATOMIC_EXCHANGE_I8: