2 * mini-ia64.c: IA64 backend for the Mono code generator
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2003 Ximian, Inc.
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/metadata/threads.h>
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/utils/mono-math.h>
22 #include "mini-ia64.h"
26 static gint lmf_tls_offset = -1;
27 static gint appdomain_tls_offset = -1;
28 static gint thread_tls_offset = -1;
30 const char * const ia64_desc [OP_LAST];
31 static const char*const * ins_spec = ia64_desc;
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
47 #define SIGNAL_STACK_SIZE (64 * 1024)
49 #define ARGS_OFFSET 16
51 #define GP_SCRATCH_REG 31
52 #define GP_SCRATCH_REG2 30
53 #define FP_SCRATCH_REG 32
55 #define LOOP_ALIGNMENT 8
56 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
58 #define NOT_IMPLEMENTED g_assert_not_reached ()
60 static const char* gregs [] = {
61 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
62 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
63 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
64 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
65 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
66 "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
67 "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
68 "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
69 "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
70 "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
71 "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
72 "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
73 "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
77 mono_arch_regname (int reg)
85 static const char* fregs [] = {
86 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
87 "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
88 "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
89 "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
90 "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
91 "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
92 "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
93 "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
94 "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
95 "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
96 "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
97 "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
98 "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
102 mono_arch_fregname (int reg)
114 ArgValuetypeAddrInIReg,
116 ArgNone /* only in pair_storage */
124 /* Only if storage == ArgValuetypeInReg */
125 ArgStorage pair_storage [2];
134 gboolean need_stack_align;
140 #define DEBUG(a) if (cfg->verbose_level > 1) a
142 #define NEW_ICONST(cfg,dest,val) do { \
143 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
144 (dest)->opcode = OP_ICONST; \
145 (dest)->inst_c0 = (val); \
146 (dest)->type = STACK_I4; \
152 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
154 ainfo->offset = *stack_size;
156 if (*gr >= PARAM_REGS) {
157 ainfo->storage = ArgOnStack;
158 (*stack_size) += sizeof (gpointer);
161 ainfo->storage = ArgInIReg;
167 #define FLOAT_PARAM_REGS 8
170 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
172 ainfo->offset = *stack_size;
174 if (*gr >= PARAM_REGS) {
175 ainfo->storage = ArgOnStack;
176 (*stack_size) += sizeof (gpointer);
179 ainfo->storage = ArgInFloatReg;
180 ainfo->reg = 8 + *fr;
187 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
189 guint32 *gr, guint32 *fr, guint32 *stack_size)
194 klass = mono_class_from_mono_type (type);
196 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
198 size = mono_type_stack_size (&klass->byval_arg, NULL);
200 if (!sig->pinvoke || (size == 0)) {
201 /* Allways pass in memory */
202 ainfo->offset = *stack_size;
203 *stack_size += ALIGN_TO (size, 8);
204 ainfo->storage = ArgOnStack;
215 * Obtain information about a call according to the calling convention.
216 * For IA64, see the "Itanium Software Conventions and Runtime Architecture
217 * Gude" document for more information.
220 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
224 int n = sig->hasthis + sig->param_count;
225 guint32 stack_size = 0;
228 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
235 ret_type = mono_type_get_underlying_type (sig->ret);
236 switch (ret_type->type) {
237 case MONO_TYPE_BOOLEAN:
248 case MONO_TYPE_FNPTR:
249 case MONO_TYPE_CLASS:
250 case MONO_TYPE_OBJECT:
251 case MONO_TYPE_SZARRAY:
252 case MONO_TYPE_ARRAY:
253 case MONO_TYPE_STRING:
254 cinfo->ret.storage = ArgInIReg;
255 cinfo->ret.reg = IA64_R8;
259 cinfo->ret.storage = ArgInIReg;
260 cinfo->ret.reg = IA64_R8;
264 cinfo->ret.storage = ArgInFloatReg;
267 case MONO_TYPE_VALUETYPE: {
268 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
270 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
271 if (cinfo->ret.storage == ArgOnStack)
272 /* The caller passes the address where the value is stored */
273 add_general (&gr, &stack_size, &cinfo->ret);
274 if (cinfo->ret.storage == ArgInIReg)
275 cinfo->ret.storage = ArgValuetypeAddrInIReg;
278 case MONO_TYPE_TYPEDBYREF:
279 /* Same as a valuetype with size 24 */
280 add_general (&gr, &stack_size, &cinfo->ret);
281 if (cinfo->ret.storage == ArgInIReg)
282 cinfo->ret.storage = ArgValuetypeAddrInIReg;
287 g_error ("Can't handle as return value 0x%x", sig->ret->type);
293 add_general (&gr, &stack_size, cinfo->args + 0);
295 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
297 fr = FLOAT_PARAM_REGS;
299 /* Emit the signature cookie just before the implicit arguments */
300 add_general (&gr, &stack_size, &cinfo->sig_cookie);
303 for (i = 0; i < sig->param_count; ++i) {
304 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
307 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
308 /* We allways pass the sig cookie on the stack for simplicity */
310 * Prevent implicit arguments + the sig cookie from being passed
314 fr = FLOAT_PARAM_REGS;
316 /* Emit the signature cookie just before the implicit arguments */
317 add_general (&gr, &stack_size, &cinfo->sig_cookie);
320 if (sig->params [i]->byref) {
321 add_general (&gr, &stack_size, ainfo);
324 ptype = mono_type_get_underlying_type (sig->params [i]);
325 switch (ptype->type) {
326 case MONO_TYPE_BOOLEAN:
329 add_general (&gr, &stack_size, ainfo);
334 add_general (&gr, &stack_size, ainfo);
338 add_general (&gr, &stack_size, ainfo);
343 case MONO_TYPE_FNPTR:
344 case MONO_TYPE_CLASS:
345 case MONO_TYPE_OBJECT:
346 case MONO_TYPE_STRING:
347 case MONO_TYPE_SZARRAY:
348 case MONO_TYPE_ARRAY:
349 add_general (&gr, &stack_size, ainfo);
351 case MONO_TYPE_VALUETYPE:
353 /* We allways pass valuetypes on the stack */
354 add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
356 case MONO_TYPE_TYPEDBYREF:
357 stack_size += sizeof (MonoTypedRef);
358 ainfo->storage = ArgOnStack;
362 add_general (&gr, &stack_size, ainfo);
365 add_float (&gr, &fr, &stack_size, ainfo, FALSE);
368 add_float (&gr, &fr, &stack_size, ainfo, TRUE);
371 g_assert_not_reached ();
375 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
377 fr = FLOAT_PARAM_REGS;
379 /* Emit the signature cookie just before the implicit arguments */
380 add_general (&gr, &stack_size, &cinfo->sig_cookie);
383 cinfo->stack_usage = stack_size;
384 cinfo->reg_usage = gr;
385 cinfo->freg_usage = fr;
390 * mono_arch_get_argument_info:
391 * @csig: a method signature
392 * @param_count: the number of parameters to consider
393 * @arg_info: an array to store the result infos
395 * Gathers information on parameters such as size, alignment and
396 * padding. arg_info should be large enought to hold param_count + 1 entries.
398 * Returns the size of the argument area on the stack.
401 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
403 g_assert_not_reached ();
409 * Initialize the cpu to execute managed code.
412 mono_arch_cpu_init (void)
417 * This function returns the optimizations supported on this cpu.
420 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
428 is_regsize_var (MonoType *t) {
431 t = mono_type_get_underlying_type (t);
442 case MONO_TYPE_FNPTR:
444 case MONO_TYPE_OBJECT:
445 case MONO_TYPE_STRING:
446 case MONO_TYPE_CLASS:
447 case MONO_TYPE_SZARRAY:
448 case MONO_TYPE_ARRAY:
450 case MONO_TYPE_VALUETYPE:
457 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
462 for (i = 0; i < cfg->num_varinfo; i++) {
463 MonoInst *ins = cfg->varinfo [i];
464 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
467 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
470 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
471 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
474 if (is_regsize_var (ins->inst_vtype)) {
475 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
476 g_assert (i == vmv->idx);
477 vars = g_list_prepend (vars, vmv);
481 vars = mono_varlist_sort (cfg, vars, 0);
487 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
491 if (cfg->arch.reg_local0 > 0)
495 cinfo = get_call_info (mono_method_signature (cfg->method), FALSE);
497 /* Three registers are reserved for use by the prolog/epilog */
498 cfg->arch.reg_in0 = 32;
499 cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + 3;
500 cfg->arch.reg_out0 = cfg->arch.reg_local0 + 8;
502 cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
503 cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
504 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 3;
507 * Need to allocate at least 2 out register for use by CEE_THROW / the system
508 * exception throwing code.
510 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
516 mono_arch_get_global_int_regs (MonoCompile *cfg)
521 mono_ia64_alloc_stacked_registers (cfg);
523 for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
526 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
533 * mono_arch_regalloc_cost:
535 * Return the cost, in number of memory references, of the action of
536 * allocating the variable VMV into a register during global register
540 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
542 /* FIXME: Increase costs linearly to avoid using all local registers */
548 mono_arch_allocate_vars (MonoCompile *m)
550 MonoMethodSignature *sig;
551 MonoMethodHeader *header;
554 guint32 locals_stack_size, locals_stack_align;
558 mono_ia64_alloc_stacked_registers (m);
560 header = mono_method_get_header (m->method);
562 sig = mono_method_signature (m->method);
564 cinfo = get_call_info (sig, FALSE);
567 * We use the ABI calling conventions for managed code as well.
568 * Exception: valuetypes are never passed or returned in registers.
571 /* Locals are allocated backwards from %fp */
572 m->frame_reg = m->arch.reg_saved_sp;
575 if (m->method->save_lmf) {
578 /* Reserve stack space for saving LMF + argument regs */
579 offset += sizeof (MonoLMF);
580 m->arch.lmf_offset = offset;
584 if (sig->ret->type != MONO_TYPE_VOID) {
585 switch (cinfo->ret.storage) {
587 m->ret->opcode = OP_REGVAR;
588 m->ret->inst_c0 = cinfo->ret.reg;
591 m->ret->opcode = OP_REGVAR;
592 m->ret->inst_c0 = cinfo->ret.reg;
594 case ArgValuetypeAddrInIReg:
595 m->ret->opcode = OP_REGVAR;
596 m->ret->inst_c0 = m->arch.reg_in0 + cinfo->ret.reg;
599 g_assert_not_reached ();
601 m->ret->dreg = m->ret->inst_c0;
604 /* Allocate locals */
605 offsets = mono_allocate_stack_slots (m, &locals_stack_size, &locals_stack_align);
606 if (locals_stack_align) {
607 offset += (locals_stack_align - 1);
608 offset &= ~(locals_stack_align - 1);
610 for (i = m->locals_start; i < m->num_varinfo; i++) {
611 if (offsets [i] != -1) {
612 MonoInst *inst = m->varinfo [i];
613 inst->opcode = OP_REGOFFSET;
614 inst->inst_basereg = m->frame_reg;
615 inst->inst_offset = - (offset + offsets [i]);
616 // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
620 offset += locals_stack_size;
622 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
623 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
624 m->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
627 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
628 inst = m->varinfo [i];
629 if (inst->opcode != OP_REGVAR) {
630 ArgInfo *ainfo = &cinfo->args [i];
631 gboolean inreg = TRUE;
634 if (sig->hasthis && (i == 0))
635 arg_type = &mono_defaults.object_class->byval_arg;
637 arg_type = sig->params [i - sig->hasthis];
639 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
642 inst->opcode = OP_REGOFFSET;
644 switch (ainfo->storage) {
646 inst->opcode = OP_REGVAR;
647 inst->dreg = m->arch.reg_in0 + ainfo->reg;
651 * Since float regs are volatile, we save the arguments to
652 * the stack in the prolog.
657 inst->opcode = OP_REGOFFSET;
658 inst->inst_basereg = m->frame_reg;
659 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
661 case ArgValuetypeInReg:
667 if (!inreg && (ainfo->storage != ArgOnStack)) {
668 inst->opcode = OP_REGOFFSET;
669 inst->inst_basereg = m->frame_reg;
670 /* These arguments are saved to the stack in the prolog */
671 if (ainfo->storage == ArgValuetypeInReg) {
673 offset += 2 * sizeof (gpointer);
676 offset += sizeof (gpointer);
677 inst->inst_offset = - offset;
682 m->stack_offset = offset;
688 mono_arch_create_vars (MonoCompile *cfg)
690 g_assert_not_reached ();
694 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
698 arg->opcode = OP_OUTARG_REG;
699 arg->inst_left = tree;
700 arg->inst_right = (MonoInst*)call;
702 call->used_iregs |= 1 << reg;
705 arg->opcode = OP_OUTARG_FREG;
706 arg->inst_left = tree;
707 arg->inst_right = (MonoInst*)call;
709 call->used_fregs |= 1 << reg;
712 g_assert_not_reached ();
717 * take the arguments and generate the arch-specific
718 * instructions to properly call the function in call.
719 * This includes pushing, moving arguments to the right register
721 * Issue: who does the spilling if needed, and when?
724 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
727 MonoMethodSignature *sig;
728 int i, n, stack_size;
734 mono_ia64_alloc_stacked_registers (cfg);
736 sig = call->signature;
737 n = sig->param_count + sig->hasthis;
739 cinfo = get_call_info (sig, sig->pinvoke);
741 for (i = 0; i < n; ++i) {
742 ainfo = cinfo->args + i;
744 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
745 MonoMethodSignature *tmp_sig;
749 /* Emit the signature cookie just before the implicit arguments */
751 /* FIXME: Add support for signature tokens to AOT */
752 cfg->disable_aot = TRUE;
754 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
757 * mono_ArgIterator_Setup assumes the signature cookie is
758 * passed first and all the arguments which were before it are
759 * passed on the stack after the signature. So compensate by
760 * passing a different signature.
762 tmp_sig = mono_metadata_signature_dup (call->signature);
763 tmp_sig->param_count -= call->signature->sentinelpos;
764 tmp_sig->sentinelpos = 0;
765 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
767 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
768 sig_arg->inst_p0 = tmp_sig;
770 MONO_INST_NEW (cfg, arg, OP_OUTARG);
771 arg->inst_left = sig_arg;
772 arg->type = STACK_PTR;
774 /* prepend, so they get reversed */
775 arg->next = call->out_args;
776 call->out_args = arg;
779 if (is_virtual && i == 0) {
780 /* the argument will be attached to the call instruction */
785 MONO_INST_NEW (cfg, arg, OP_OUTARG);
787 arg->cil_code = in->cil_code;
789 arg->type = in->type;
790 /* prepend, so they get reversed */
791 arg->next = call->out_args;
792 call->out_args = arg;
794 if (sig->hasthis && (i == 0))
795 arg_type = &mono_defaults.object_class->byval_arg;
797 arg_type = sig->params [i - sig->hasthis];
799 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
800 MonoInst *stack_addr;
804 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
805 size = sizeof (MonoTypedRef);
806 align = sizeof (gpointer);
810 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
812 size = mono_type_stack_size (&in->klass->byval_arg, &align);
813 if (ainfo->storage == ArgValuetypeInReg) {
817 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
818 stack_addr->inst_basereg = IA64_SP;
819 stack_addr->inst_offset = 16 + ainfo->offset;
820 stack_addr->inst_imm = size;
822 arg->opcode = OP_OUTARG_VT;
823 arg->inst_right = stack_addr;
826 switch (ainfo->storage) {
828 add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
831 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
834 if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
835 arg->opcode = OP_OUTARG_R4;
838 arg->opcode = OP_OUTARG;
839 arg->inst_imm = 16 + ainfo->offset;
842 g_assert_not_reached ();
848 call->stack_usage = cinfo->stack_usage;
849 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
850 cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
851 cfg->flags |= MONO_CFG_HAS_CALLS;
859 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
861 MonoInst *ins, *last_ins = NULL;
865 switch (ins->opcode) {
874 if (ins->dreg == ins->sreg1) {
876 last_ins->next = ins->next;
886 if (last_ins && last_ins->opcode == OP_MOVE &&
887 ins->sreg1 == last_ins->dreg &&
888 ins->dreg == last_ins->sreg1) {
889 last_ins->next = ins->next;
895 /* remove unnecessary multiplication with 1 */
896 if (ins->inst_imm == 1) {
897 if (ins->dreg != ins->sreg1) {
898 ins->opcode = OP_MOVE;
900 last_ins->next = ins->next;
911 bb->last_ins = last_ins;
934 opcode_to_cond (int opcode)
946 case OP_COND_EXC_NE_UN:
976 case OP_COND_EXC_LE_UN:
990 case OP_COND_EXC_LT_UN:
993 case OP_COND_EXC_GT_UN:
1001 printf ("%s\n", mono_inst_name (opcode));
1007 opcode_to_type (int opcode)
1009 if ((opcode >= CEE_BEQ) && (opcode <= CEE_BLT_UN))
1011 else if ((opcode >= OP_CEQ) && (opcode <= OP_CLT_UN))
1013 else if ((opcode >= OP_COND_EXC_EQ) && (opcode <= OP_COND_EXC_LT_UN))
1015 else if ((opcode >= OP_IBEQ) && (opcode <= OP_IBLE_UN))
1017 else if ((opcode >= OP_ICEQ) && (opcode <= OP_ICLT_UN))
1019 else if ((opcode >= OP_FBEQ) && (opcode <= OP_FBLE_UN))
1021 else if ((opcode >= OP_FCEQ) && (opcode <= OP_FCLT_UN))
1024 g_error ("Unknown opcode '%s' in opcode_to_type", mono_inst_name (opcode));
1029 int cond_to_ia64_cmp [][3] = {
1030 {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1031 {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1032 {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1033 {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1034 {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1035 {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1036 {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1037 {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1038 {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1039 {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1043 opcode_to_ia64_cmp (int opcode)
1045 return cond_to_ia64_cmp [opcode_to_cond (opcode)][opcode_to_type (opcode)];
1048 int cond_to_ia64_cmp_imm [][3] = {
1049 {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1050 {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1051 {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1052 {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1053 {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1054 {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1055 {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1056 {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1057 {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1058 {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1062 opcode_to_ia64_cmp_imm (int opcode)
1064 /* The condition needs to be reversed */
1065 return cond_to_ia64_cmp_imm [opcode_to_cond (opcode)][opcode_to_type (opcode)];
1069 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1073 bb->code = to_insert;
1074 to_insert->next = ins;
1077 to_insert->next = ins->next;
1078 ins->next = to_insert;
1082 #define NEW_INS(cfg,dest,op) do { \
1083 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1084 (dest)->opcode = (op); \
1085 insert_after_ins (bb, last_ins, (dest)); \
1086 last_ins = (dest); \
1090 * mono_arch_lowering_pass:
1092 * Converts complex opcodes into simpler ones so that each IR instruction
1093 * corresponds to one machine instruction.
1096 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1098 MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1101 if (bb->max_ireg > cfg->rs->next_vireg)
1102 cfg->rs->next_vireg = bb->max_ireg;
1103 if (bb->max_freg > cfg->rs->next_vfreg)
1104 cfg->rs->next_vfreg = bb->max_freg;
1107 switch (ins->opcode) {
1108 case OP_STOREI1_MEMBASE_IMM:
1109 case OP_STOREI2_MEMBASE_IMM:
1110 case OP_STOREI4_MEMBASE_IMM:
1111 case OP_STOREI8_MEMBASE_IMM:
1112 case OP_STORE_MEMBASE_IMM:
1113 /* There are no store_membase instructions on ia64 */
1114 NEW_INS (cfg, temp, OP_I8CONST);
1115 temp->inst_c0 = ins->inst_offset;
1116 temp->dreg = mono_regstate_next_int (cfg->rs);
1117 NEW_INS (cfg, temp2, CEE_ADD);
1118 temp2->sreg1 = ins->inst_destbasereg;
1119 temp2->sreg2 = temp->dreg;
1120 temp2->dreg = mono_regstate_next_int (cfg->rs);
1122 switch (ins->opcode) {
1123 case OP_STOREI1_MEMBASE_IMM:
1124 ins->opcode = OP_STOREI1_MEMBASE_REG;
1126 case OP_STOREI2_MEMBASE_IMM:
1127 ins->opcode = OP_STOREI2_MEMBASE_REG;
1129 case OP_STOREI4_MEMBASE_IMM:
1130 ins->opcode = OP_STOREI4_MEMBASE_REG;
1132 case OP_STOREI8_MEMBASE_IMM:
1133 case OP_STORE_MEMBASE_IMM:
1134 ins->opcode = OP_STOREI8_MEMBASE_REG;
1137 g_assert_not_reached ();
1140 if (ins->inst_imm == 0)
1141 ins->sreg1 = IA64_R0;
1143 NEW_INS (cfg, temp3, OP_I8CONST);
1144 temp3->inst_c0 = ins->inst_imm;
1145 temp3->dreg = mono_regstate_next_int (cfg->rs);
1146 ins->sreg1 = temp3->dreg;
1149 ins->inst_offset = 0;
1150 ins->inst_destbasereg = temp2->dreg;
1152 case OP_STOREI1_MEMBASE_REG:
1153 case OP_STOREI2_MEMBASE_REG:
1154 case OP_STOREI4_MEMBASE_REG:
1155 case OP_STOREI8_MEMBASE_REG:
1156 case OP_STORER4_MEMBASE_REG:
1157 case OP_STORER8_MEMBASE_REG:
1158 case OP_STORE_MEMBASE_REG:
1159 /* There are no store_membase instructions on ia64 */
1160 if (ia64_is_imm14 (ins->inst_offset)) {
1161 NEW_INS (cfg, temp2, OP_ADD_IMM);
1162 temp2->sreg1 = ins->inst_destbasereg;
1163 temp2->inst_imm = ins->inst_offset;
1164 temp2->dreg = mono_regstate_next_int (cfg->rs);
1167 NEW_INS (cfg, temp, OP_I8CONST);
1168 temp->inst_c0 = ins->inst_offset;
1169 temp->dreg = mono_regstate_next_int (cfg->rs);
1170 NEW_INS (cfg, temp2, CEE_ADD);
1171 temp2->sreg1 = ins->inst_destbasereg;
1172 temp2->sreg2 = temp->dreg;
1173 temp2->dreg = mono_regstate_next_int (cfg->rs);
1176 ins->inst_offset = 0;
1177 ins->inst_destbasereg = temp2->dreg;
1179 case OP_LOADI1_MEMBASE:
1180 case OP_LOADU1_MEMBASE:
1181 case OP_LOADI2_MEMBASE:
1182 case OP_LOADU2_MEMBASE:
1183 case OP_LOADI4_MEMBASE:
1184 case OP_LOADU4_MEMBASE:
1185 case OP_LOADI8_MEMBASE:
1186 case OP_LOAD_MEMBASE:
1187 case OP_LOADR4_MEMBASE:
1188 case OP_LOADR8_MEMBASE:
1189 /* There are no load_membase instructions on ia64 */
1190 if (ia64_is_imm14 (ins->inst_offset)) {
1191 NEW_INS (cfg, temp2, OP_ADD_IMM);
1192 temp2->sreg1 = ins->inst_basereg;
1193 temp2->inst_imm = ins->inst_offset;
1194 temp2->dreg = mono_regstate_next_int (cfg->rs);
1197 NEW_INS (cfg, temp, OP_I8CONST);
1198 temp->inst_c0 = ins->inst_offset;
1199 temp->dreg = mono_regstate_next_int (cfg->rs);
1200 NEW_INS (cfg, temp2, CEE_ADD);
1201 temp2->sreg1 = ins->inst_basereg;
1202 temp2->sreg2 = temp->dreg;
1203 temp2->dreg = mono_regstate_next_int (cfg->rs);
1206 ins->inst_offset = 0;
1207 ins->inst_basereg = temp2->dreg;
1209 case OP_FCALL_MEMBASE:
1210 case OP_LCALL_MEMBASE:
1211 case OP_VCALL_MEMBASE:
1212 case OP_VOIDCALL_MEMBASE:
1213 case OP_CALL_MEMBASE:
1214 /* There are no membase instructions on ia64 */
1215 if (ia64_is_imm14 (ins->inst_offset)) {
1216 NEW_INS (cfg, temp2, OP_ADD_IMM);
1217 temp2->sreg1 = ins->sreg1;
1218 temp2->inst_imm = ins->inst_offset;
1219 temp2->dreg = mono_regstate_next_int (cfg->rs);
1222 NEW_INS (cfg, temp, OP_I8CONST);
1223 temp->inst_c0 = ins->inst_offset;
1224 temp->dreg = mono_regstate_next_int (cfg->rs);
1225 NEW_INS (cfg, temp2, CEE_ADD);
1226 temp2->sreg1 = ins->sreg1;
1227 temp2->sreg2 = temp->dreg;
1228 temp2->dreg = mono_regstate_next_int (cfg->rs);
1231 NEW_INS (cfg, temp, OP_LOADI8_MEMBASE);
1232 temp->sreg1 = temp2->dreg;
1233 temp->dreg = mono_regstate_next_int (cfg->rs);
1235 ins->sreg1 = temp->dreg;
1237 switch (ins->opcode) {
1238 case OP_FCALL_MEMBASE:
1239 ins->opcode = OP_FCALL_REG;
1241 case OP_LCALL_MEMBASE:
1242 ins->opcode = OP_LCALL_REG;
1244 case OP_VCALL_MEMBASE:
1245 ins->opcode = OP_VCALL_REG;
1247 case OP_VOIDCALL_MEMBASE:
1248 ins->opcode = OP_VOIDCALL_REG;
1250 case OP_CALL_MEMBASE:
1251 ins->opcode = OP_CALL_REG;
1254 g_assert_not_reached ();
1269 case OP_ISHR_UN_IMM:
1270 case OP_LSHR_UN_IMM: {
1271 gboolean is_imm = FALSE;
1272 gboolean switched = FALSE;
1274 switch (ins->opcode) {
1277 is_imm = ia64_is_imm14 (ins->inst_imm);
1281 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1283 /* A = B - IMM -> A = B + (-IMM) */
1284 ins->inst_imm = - ins->inst_imm;
1285 ins->opcode = OP_IADD_IMM;
1293 is_imm = ia64_is_imm8 (ins->inst_imm);
1301 case OP_ISHR_UN_IMM:
1302 case OP_LSHR_UN_IMM:
1303 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1311 ins->sreg2 = ins->sreg1;
1315 switch (ins->opcode) {
1317 ins->opcode = CEE_ADD;
1320 ins->opcode = OP_IADD;
1323 ins->opcode = OP_ISUB;
1326 ins->opcode = OP_IAND;
1329 ins->opcode = OP_IOR;
1332 ins->opcode = OP_IXOR;
1335 ins->opcode = OP_ISHL;
1338 ins->opcode = OP_ISHR;
1340 case OP_ISHR_UN_IMM:
1341 ins->opcode = OP_ISHR_UN;
1344 ins->opcode = CEE_AND;
1347 ins->opcode = OP_LSHL;
1350 ins->opcode = OP_LSHL;
1353 ins->opcode = OP_LSHR;
1355 case OP_LSHR_UN_IMM:
1356 ins->opcode = OP_LSHR_UN;
1359 g_assert_not_reached ();
1362 if (ins->inst_imm == 0)
1363 ins->sreg2 = IA64_R0;
1365 NEW_INS (cfg, temp, OP_I8CONST);
1366 temp->inst_c0 = ins->inst_imm;
1367 temp->dreg = mono_regstate_next_int (cfg->rs);
1368 ins->sreg2 = temp->dreg;
1372 case OP_COMPARE_IMM:
1373 case OP_ICOMPARE_IMM: {
1374 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1378 * The compare_imm instructions have switched up arguments, and
1379 * some of them take an imm between -127 and 128.
1382 switch (next->opcode) {
1387 case OP_COND_EXC_LT:
1392 imm = ia64_is_imm8 (ins->inst_imm - 1);
1395 imm = ia64_is_imm8 (ins->inst_imm);
1400 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode);
1401 ins->sreg2 = ins->sreg1;
1404 ins->opcode = opcode_to_ia64_cmp (next->opcode);
1406 if (ins->inst_imm == 0)
1407 ins->sreg2 = IA64_R0;
1409 NEW_INS (cfg, temp, OP_I8CONST);
1410 temp->inst_c0 = ins->inst_imm;
1411 temp->dreg = mono_regstate_next_int (cfg->rs);
1412 ins->sreg2 = temp->dreg;
1416 switch (next->opcode) {
1437 next->opcode = OP_IA64_BR_COND;
1438 if (! (next->flags & MONO_INST_BRLABEL))
1439 next->inst_target_bb = next->inst_true_bb;
1441 case OP_COND_EXC_EQ:
1442 case OP_COND_EXC_GT:
1443 case OP_COND_EXC_LT:
1444 case OP_COND_EXC_GT_UN:
1445 case OP_COND_EXC_LE_UN:
1446 case OP_COND_EXC_NE_UN:
1447 case OP_COND_EXC_LT_UN:
1448 next->opcode = OP_IA64_COND_EXC;
1460 next->opcode = OP_IA64_CSET;
1463 printf ("%s\n", mono_inst_name (next->opcode));
1473 /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1477 ins->opcode = opcode_to_ia64_cmp (next->opcode);
1478 switch (next->opcode) {
1509 next->opcode = OP_IA64_BR_COND;
1510 if (! (next->flags & MONO_INST_BRLABEL))
1511 next->inst_target_bb = next->inst_true_bb;
1513 case OP_COND_EXC_LT:
1514 case OP_COND_EXC_GT:
1515 case OP_COND_EXC_GT_UN:
1516 case OP_COND_EXC_LE_UN:
1517 next->opcode = OP_IA64_COND_EXC;
1534 next->opcode = OP_IA64_CSET;
1537 printf ("%s\n", mono_inst_name (next->opcode));
1543 /* This should be emulated, but rules in inssel.brg generate it */
1546 /* First the easy cases */
1547 if (ins->inst_imm == 1) {
1548 ins->opcode = OP_MOVE;
1551 for (i = 1; i < 64; ++i)
1552 if (ins->inst_imm == (((gint64)1) << i)) {
1553 ins->opcode = OP_SHL_IMM;
1558 /* This could be optimized */
1559 if (ins->opcode == OP_MUL_IMM) {
1561 for (i = 0; i < 64; ++i) {
1562 if (ins->inst_imm & (((gint64)1) << i)) {
1563 NEW_INS (cfg, temp, OP_SHL_IMM);
1564 temp->dreg = mono_regstate_next_int (cfg->rs);
1565 temp->sreg1 = ins->sreg1;
1569 sum_reg = temp->dreg;
1571 NEW_INS (cfg, temp2, CEE_ADD);
1572 temp2->dreg = mono_regstate_next_int (cfg->rs);
1573 temp2->sreg1 = sum_reg;
1574 temp2->sreg2 = temp->dreg;
1575 sum_reg = temp2->dreg;
1579 ins->opcode = OP_MOVE;
1580 ins->sreg1 = sum_reg;
1584 case CEE_CONV_OVF_U4:
1585 NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1586 temp->sreg1 = ins->sreg1;
1587 temp->sreg2 = IA64_R0;
1589 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1590 temp->inst_p1 = (char*)"OverflowException";
1592 ins->opcode = OP_MOVE;
1594 case CEE_CONV_OVF_I4_UN:
1595 NEW_INS (cfg, temp, OP_ICONST);
1596 temp->inst_c0 = 0x7fffffff;
1597 temp->dreg = mono_regstate_next_int (cfg->rs);
1599 NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1600 temp2->sreg1 = ins->sreg1;
1601 temp2->sreg2 = temp->dreg;
1603 NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1604 temp->inst_p1 = (char*)"OverflowException";
1606 ins->opcode = OP_MOVE;
1608 case OP_FCONV_TO_I4:
1609 case OP_FCONV_TO_I2:
1610 case OP_FCONV_TO_U2:
1611 case OP_FCONV_TO_U1:
1612 NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1613 temp->sreg1 = ins->sreg1;
1614 temp->dreg = ins->dreg;
1616 switch (ins->opcode) {
1617 case OP_FCONV_TO_I4:
1618 ins->opcode = OP_SEXT_I4;
1620 case OP_FCONV_TO_I2:
1621 ins->opcode = OP_SEXT_I2;
1623 case OP_FCONV_TO_U2:
1624 ins->opcode = OP_ZEXT_I4;
1626 case OP_FCONV_TO_U1:
1627 ins->opcode = OP_ZEXT_I1;
1630 g_assert_not_reached ();
1632 ins->sreg1 = ins->dreg;
1640 bb->last_ins = last_ins;
1642 bb->max_ireg = cfg->rs->next_vireg;
1643 bb->max_freg = cfg->rs->next_vfreg;
1647 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1652 mono_arch_lowering_pass (cfg, bb);
1654 mono_local_regalloc (cfg, bb);
1657 static Ia64CodegenState
1658 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1662 /* Move return value to the target register */
1663 /* FIXME: do this in the local reg allocator */
1664 switch (ins->opcode) {
1666 case OP_VOIDCALL_REG:
1667 case OP_VOIDCALL_MEMBASE:
1671 case OP_CALL_MEMBASE:
1674 case OP_LCALL_MEMBASE:
1675 g_assert (ins->dreg == IA64_R8);
1679 case OP_FCALL_MEMBASE:
1680 g_assert (ins->dreg == 8);
1684 case OP_VCALL_MEMBASE:
1685 cinfo = get_call_info (((MonoCallInst*)ins)->signature, FALSE);
1686 if (cinfo->ret.storage == ArgValuetypeInReg) {
1692 g_assert_not_reached ();
1698 static Ia64CodegenState
1699 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
1701 mono_add_patch_info (cfg, code.buf - cfg->native_code, patch_type, data);
1703 if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
1705 ia64_movl (code, GP_SCRATCH_REG, 0);
1706 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
1707 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
1708 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
1709 ia64_br_call_reg (code, IA64_B0, IA64_B6);
1712 ia64_br_call (code, IA64_B0, 0);
1717 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
1720 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1725 Ia64CodegenState code;
1726 guint8 *code_start = cfg->native_code + cfg->code_len;
1727 MonoInst *last_ins = NULL;
1728 guint last_offset = 0;
1731 if (cfg->opt & MONO_OPT_PEEPHOLE)
1732 peephole_pass (cfg, bb);
1734 if (cfg->opt & MONO_OPT_LOOP) {
1738 if (cfg->verbose_level > 2)
1739 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1741 cpos = bb->max_offset;
1743 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1747 offset = code_start - cfg->native_code;
1749 ia64_codegen_init (code, code_start);
1753 offset = code.buf - cfg->native_code;
1755 max_len = ((int)(((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN])) + 128;
1757 while (offset + max_len + 16 > cfg->code_size) {
1758 ia64_codegen_close (code);
1760 offset = code.buf - cfg->native_code;
1762 cfg->code_size *= 2;
1763 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1764 code_start = cfg->native_code + offset;
1765 mono_jit_stats.code_reallocs++;
1767 ia64_codegen_init (code, code_start);
1770 mono_debug_record_line_number (cfg, ins, offset);
1772 switch (ins->opcode) {
1775 if (ia64_is_imm14 (ins->inst_c0))
1776 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
1778 ia64_movl (code, ins->dreg, ins->inst_c0);
1781 ia64_mov (code, ins->dreg, ins->sreg1);
1784 case OP_IA64_BR_COND: {
1786 if (ins->opcode == OP_IA64_BR_COND)
1788 if (ins->flags & MONO_INST_BRLABEL) {
1789 if (ins->inst_i0->inst_c0) {
1792 ia64_begin_bundle (code);
1793 mono_add_patch_info (cfg, code.buf - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
1794 ia64_br_cond_pred (code, pred, 0);
1797 if (ins->inst_target_bb->native_offset) {
1798 gint64 disp = ((gint64)ins->inst_target_bb->native_offset - offset) >> 4;
1799 ia64_br_cond_pred (code, pred, disp);
1801 ia64_begin_bundle (code);
1802 mono_add_patch_info (cfg, code.buf - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
1803 ia64_br_cond_pred (code, pred, 0);
1809 ia64_begin_bundle (code);
1810 ins->inst_c0 = code.buf - cfg->native_code;
1815 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
1816 ia64_br_cond_reg (code, IA64_B6);
1820 ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
1824 ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
1828 ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
1832 ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
1836 ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
1840 ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
1843 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
1847 ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
1850 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
1851 ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
1855 ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
1858 ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
1862 ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
1865 /* p6 and p7 is set if there is signed/unsigned overflow */
1867 /* Set p8-p9 == (sreg2 > 0) */
1868 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
1870 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
1872 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
1873 ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
1874 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
1875 ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
1877 /* res <u sreg1 => unsigned overflow */
1878 ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
1880 /* FIXME: Predicate this since this is a side effect */
1881 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
1884 /* p6 and p7 is set if there is signed/unsigned overflow */
1886 /* Set p8-p9 == (sreg2 > 0) */
1887 ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
1889 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
1891 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
1892 ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
1893 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
1894 ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
1896 /* sreg1 <u sreg2 => unsigned overflow */
1897 ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
1899 /* FIXME: Predicate this since this is a side effect */
1900 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
1903 /* Same as OP_IADDCC */
1904 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
1906 ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
1908 ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
1909 ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
1911 ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
1913 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
1916 /* Same as OP_ISUBCC */
1918 ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
1920 ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
1922 ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
1923 ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
1925 ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
1927 ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
1931 ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
1935 ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
1938 ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
1941 ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
1946 ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
1949 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
1952 ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
1954 case OP_ISHR_UN_IMM:
1955 ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
1956 ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
1958 case OP_LSHR_UN_IMM:
1959 ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
1962 case OP_STOREI1_MEMBASE_REG:
1963 ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
1965 case OP_STOREI2_MEMBASE_REG:
1966 ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
1968 case OP_STOREI4_MEMBASE_REG:
1969 ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
1971 case OP_STOREI8_MEMBASE_REG:
1972 case OP_STORE_MEMBASE_REG:
1973 ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
1975 case OP_LOADU1_MEMBASE:
1976 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
1978 case OP_LOADU2_MEMBASE:
1979 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
1981 case OP_LOADU4_MEMBASE:
1982 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
1984 case OP_LOADI1_MEMBASE:
1985 ia64_ld1 (code, ins->dreg, ins->inst_basereg);
1986 ia64_sxt1 (code, ins->dreg, ins->dreg);
1988 case OP_LOADI2_MEMBASE:
1989 ia64_ld2 (code, ins->dreg, ins->inst_basereg);
1990 ia64_sxt2 (code, ins->dreg, ins->dreg);
1992 case OP_LOADI4_MEMBASE:
1993 ia64_ld4 (code, ins->dreg, ins->inst_basereg);
1994 ia64_sxt4 (code, ins->dreg, ins->dreg);
1996 case OP_LOAD_MEMBASE:
1997 case OP_LOADI8_MEMBASE:
1998 ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2001 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2004 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2007 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2010 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2013 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2016 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2019 /* Compare opcodes */
2020 case OP_IA64_CMP4_EQ:
2021 ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2023 case OP_IA64_CMP4_NE:
2024 ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2026 case OP_IA64_CMP4_LE:
2027 ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2029 case OP_IA64_CMP4_LT:
2030 ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2032 case OP_IA64_CMP4_GE:
2033 ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2035 case OP_IA64_CMP4_GT:
2036 ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2038 case OP_IA64_CMP4_LT_UN:
2039 ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2041 case OP_IA64_CMP4_LE_UN:
2042 ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2044 case OP_IA64_CMP4_GT_UN:
2045 ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2047 case OP_IA64_CMP4_GE_UN:
2048 ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2050 case OP_IA64_CMP_EQ:
2051 ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2053 case OP_IA64_CMP_NE:
2054 ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2056 case OP_IA64_CMP_LE:
2057 ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2059 case OP_IA64_CMP_LT:
2060 ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2062 case OP_IA64_CMP_GE:
2063 ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2065 case OP_IA64_CMP_GT:
2066 ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2068 case OP_IA64_CMP_GT_UN:
2069 ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2071 case OP_IA64_CMP_LT_UN:
2072 ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2074 case OP_IA64_CMP_GE_UN:
2075 ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2077 case OP_IA64_CMP_LE_UN:
2078 ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2080 case OP_IA64_CMP4_EQ_IMM:
2081 ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2083 case OP_IA64_CMP4_NE_IMM:
2084 ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2086 case OP_IA64_CMP4_LE_IMM:
2087 ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2089 case OP_IA64_CMP4_LT_IMM:
2090 ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2092 case OP_IA64_CMP4_GE_IMM:
2093 ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2095 case OP_IA64_CMP4_GT_IMM:
2096 ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2098 case OP_IA64_CMP4_LT_UN_IMM:
2099 ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2101 case OP_IA64_CMP4_LE_UN_IMM:
2102 ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2104 case OP_IA64_CMP4_GT_UN_IMM:
2105 ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2107 case OP_IA64_CMP4_GE_UN_IMM:
2108 ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2110 case OP_IA64_CMP_EQ_IMM:
2111 ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2113 case OP_IA64_CMP_NE_IMM:
2114 ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2116 case OP_IA64_CMP_LE_IMM:
2117 ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2119 case OP_IA64_CMP_LT_IMM:
2120 ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2122 case OP_IA64_CMP_GE_IMM:
2123 ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2125 case OP_IA64_CMP_GT_IMM:
2126 ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2128 case OP_IA64_CMP_GT_UN_IMM:
2129 ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2131 case OP_IA64_CMP_LT_UN_IMM:
2132 ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2134 case OP_IA64_CMP_GE_UN_IMM:
2135 ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2137 case OP_IA64_CMP_LE_UN_IMM:
2138 ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2140 case OP_IA64_FCMP_EQ:
2141 ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2143 case OP_IA64_FCMP_NE:
2144 ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2146 case OP_IA64_FCMP_LT:
2147 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2149 case OP_IA64_FCMP_GT:
2150 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2152 case OP_IA64_FCMP_LE:
2153 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2155 case OP_IA64_FCMP_GE:
2156 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2158 case OP_IA64_FCMP_GT_UN:
2159 ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2160 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2162 case OP_IA64_FCMP_LT_UN:
2163 ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2164 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2166 case OP_IA64_FCMP_GE_UN:
2167 ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2168 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2170 case OP_IA64_FCMP_LE_UN:
2171 ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2172 ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2175 case OP_COND_EXC_IOV:
2176 case OP_COND_EXC_OV:
2177 mono_add_patch_info (cfg, code.buf - cfg->native_code,
2178 MONO_PATCH_INFO_EXC, "OverflowException");
2179 ia64_br_cond_pred (code, 6, 0);
2181 case OP_COND_EXC_IC:
2183 mono_add_patch_info (cfg, code.buf - cfg->native_code,
2184 MONO_PATCH_INFO_EXC, "OverflowException");
2185 ia64_br_cond_pred (code, 7, 0);
2187 case OP_IA64_COND_EXC:
2188 mono_add_patch_info (cfg, code.buf - cfg->native_code,
2189 MONO_PATCH_INFO_EXC, ins->inst_p1);
2190 ia64_br_cond_pred (code, 6, 0);
2193 /* FIXME: Do this with one instruction ? */
2194 ia64_mov (code, ins->dreg, IA64_R0);
2195 ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2198 /* FIXME: Is this needed ? */
2199 ia64_sxt1 (code, ins->dreg, ins->sreg1);
2202 /* FIXME: Is this needed ? */
2203 ia64_sxt2 (code, ins->dreg, ins->sreg1);
2206 /* FIXME: Is this needed ? */
2207 ia64_sxt4 (code, ins->dreg, ins->sreg1);
2210 /* FIXME: Is this needed */
2211 ia64_zxt1 (code, ins->dreg, ins->sreg1);
2214 /* FIXME: Is this needed */
2215 ia64_zxt2 (code, ins->dreg, ins->sreg1);
2219 /* FIXME: Sign extend ? */
2220 ia64_mov (code, ins->dreg, ins->sreg1);
2224 ia64_zxt4 (code, ins->dreg, ins->sreg1);
2231 double d = *(double *)ins->inst_p0;
2233 if ((d == 0.0) && (mono_signbit (d) == 0))
2234 ia64_fmov (code, ins->dreg, 0);
2236 ia64_fmov (code, ins->dreg, 1);
2238 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
2239 ia64_movl (code, GP_SCRATCH_REG, 0);
2240 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2245 float f = *(float *)ins->inst_p0;
2247 if ((f == 0.0) && (mono_signbit (f) == 0))
2248 ia64_fmov (code, ins->dreg, 0);
2250 ia64_fmov (code, ins->dreg, 1);
2252 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
2253 ia64_movl (code, GP_SCRATCH_REG, 0);
2254 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2259 ia64_fmov (code, ins->dreg, ins->sreg1);
2261 case OP_STORER8_MEMBASE_REG:
2262 ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2264 case OP_STORER4_MEMBASE_REG:
2265 ia64_stfs_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2267 case OP_LOADR8_MEMBASE:
2268 ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2270 case OP_LOADR4_MEMBASE:
2271 ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2274 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2275 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2276 ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2279 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2280 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2281 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2283 case OP_LCONV_TO_R8:
2284 /* FIXME: Difference with CEE_CONV_R8 ? */
2285 ia64_setf_sig (code, ins->dreg, ins->sreg1);
2286 ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2287 ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2289 case OP_FCONV_TO_R4:
2290 ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2292 case OP_FCONV_TO_I8:
2293 ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2294 ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2297 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2300 ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2303 ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2306 ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2311 /* ensure ins->sreg1 is not NULL */
2312 ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2320 call = (MonoCallInst*)ins;
2322 if (ins->flags & MONO_INST_HAS_METHOD)
2323 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2325 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2327 code = emit_move_return_value (cfg, ins, code);
2334 case OP_VOIDCALL_REG:
2335 call = (MonoCallInst*)ins;
2337 if (call->virtual) {
2338 /* Keep this in synch with get_vcall_slot_addr */
2340 /* This is a virtual call */
2341 ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2344 * This nop will tell get_vcall_slot_addr that this is a virtual
2347 ia64_nop_i (code, 0x12345);
2351 ia64_mov (code, GP_SCRATCH_REG, ins->sreg1);
2352 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2353 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2354 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2356 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2358 code = emit_move_return_value (cfg, ins, code);
2362 /* keep alignment */
2363 ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->sreg1);
2364 ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_FRAME_ALIGNMENT - 1));
2365 ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2367 ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2369 /* The first 16 bytes at sp are reserved by the ABI */
2370 ia64_adds_imm (code, ins->dreg, 16, IA64_SP);
2372 if (ins->flags & MONO_INST_INIT) {
2374 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2377 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2378 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2379 ia64_br_cond_pred (code, 8, -2);
2381 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2386 /* Exception handling */
2387 case OP_CALL_HANDLER:
2389 * Using a call instruction would mess up the register stack, so
2390 * save the return address to a register and use a
2393 ia64_mov (code, IA64_R15, IA64_R0);
2394 ia64_mov_from_ip (code, GP_SCRATCH_REG);
2395 /* Add the length of OP_CALL_HANDLER */
2396 ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
2397 mono_add_patch_info (cfg, code.buf - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2398 ia64_movl (code, GP_SCRATCH_REG2, 0);
2399 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2400 ia64_br_cond_reg (code, IA64_B6);
2402 case OP_START_HANDLER: {
2404 * We receive the return address in GP_SCRATCH_REG.
2406 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2409 * We might be called by the exception handling code, in which case the
2410 * the register stack is not set up correctly. So do it now.
2412 ia64_alloc (code, GP_SCRATCH_REG2, cfg->arch.reg_local0 - cfg->arch.reg_in0, cfg->arch.reg_out0 - cfg->arch.reg_local0, cfg->arch.n_out_regs, 0);
2414 /* Set the fp register from the value passed in by the caller */
2415 /* R15 is used since it is writable using libunwind */
2416 /* R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context () */
2417 ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
2418 ia64_add_pred (code, 7, cfg->frame_reg, IA64_R0, IA64_R15);
2420 ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
2421 ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
2425 case CEE_ENDFINALLY: {
2426 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2427 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
2428 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
2429 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2430 ia64_br_cond_reg (code, IA64_B6);
2433 case OP_ENDFILTER: {
2434 /* FIXME: Return the value */
2435 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2436 ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
2437 ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
2438 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2439 ia64_br_cond_reg (code, IA64_B6);
2443 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
2444 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
2445 (gpointer)"mono_arch_throw_exception");
2448 ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
2449 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
2450 (gpointer)"mono_arch_rethrow_exception");
2454 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2455 g_assert_not_reached ();
2458 if ((code.buf - cfg->native_code - offset) > max_len) {
2459 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
2460 mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
2461 g_assert_not_reached ();
2467 last_offset = offset;
2472 ia64_codegen_close (code);
2474 cfg->code_len = code.buf - cfg->native_code;
2478 mono_arch_register_lowlevel_calls (void)
2482 static Ia64InsType ins_types_in_template [32][3] = {
2483 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
2484 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
2485 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
2486 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
2487 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
2488 {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
2491 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
2492 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
2493 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
2494 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
2495 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
2496 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
2497 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
2498 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
2499 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
2500 {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
2501 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
2502 {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
2505 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
2506 {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
2507 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
2508 {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
2511 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
2512 {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
2517 static gboolean stops_in_template [32][3] = {
2518 { FALSE, FALSE, FALSE },
2519 { FALSE, FALSE, TRUE },
2520 { FALSE, TRUE, FALSE },
2521 { FALSE, TRUE, TRUE },
2522 { FALSE, FALSE, FALSE },
2523 { FALSE, FALSE, TRUE },
2524 { FALSE, FALSE, FALSE },
2525 { FALSE, FALSE, FALSE },
2527 { FALSE, FALSE, FALSE },
2528 { FALSE, FALSE, TRUE },
2529 { TRUE, FALSE, FALSE },
2530 { TRUE, FALSE, TRUE },
2531 { FALSE, FALSE, FALSE },
2532 { FALSE, FALSE, TRUE },
2533 { FALSE, FALSE, FALSE },
2534 { FALSE, FALSE, TRUE },
2536 { FALSE, FALSE, FALSE },
2537 { FALSE, FALSE, TRUE },
2538 { FALSE, FALSE, FALSE },
2539 { FALSE, FALSE, TRUE },
2540 { FALSE, FALSE, FALSE },
2541 { FALSE, FALSE, FALSE },
2542 { FALSE, FALSE, FALSE },
2543 { FALSE, FALSE, TRUE },
2545 { FALSE, FALSE, FALSE },
2546 { FALSE, FALSE, TRUE },
2547 { FALSE, FALSE, FALSE },
2548 { FALSE, FALSE, FALSE },
2549 { FALSE, FALSE, FALSE },
2550 { FALSE, FALSE, TRUE },
2551 { FALSE, FALSE, FALSE },
2552 { FALSE, FALSE, FALSE }
2556 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
2558 int i, j, ins_type, template;
2560 if (!code->automatic) {
2561 if (code->nins == 0)
2564 g_assert (code->nins == 3);
2566 /* Verify template is correct */
2567 template = code->template;
2568 for (j = 0; j < 3; ++j) {
2569 if (code->stops [j])
2570 g_assert (stops_in_template [template]);
2572 ins_type = ins_types_in_template [template][j];
2573 switch (code->itypes [j]) {
2574 case IA64_INS_TYPE_A:
2575 g_assert ((ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M));
2577 case IA64_INS_TYPE_LX:
2579 g_assert (ins_type == IA64_INS_TYPE_LX);
2583 g_assert (ins_type == code->itypes [j]);
2587 ia64_emit_bundle_template (code, template, code->instructions [0], code->instructions [1], code->instructions [2]);
2593 for (i = 0; i < code->nins; ++i) {
2594 switch (code->itypes [i]) {
2595 case IA64_INS_TYPE_A:
2596 ia64_emit_bundle_template (code, IA64_TEMPLATE_MIIS, code->instructions [i], IA64_NOP_I, IA64_NOP_I);
2598 case IA64_INS_TYPE_I:
2599 ia64_emit_bundle_template (code, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [i], IA64_NOP_I);
2601 case IA64_INS_TYPE_M:
2602 ia64_emit_bundle_template (code, IA64_TEMPLATE_MIIS, code->instructions [i], IA64_NOP_I, IA64_NOP_I);
2604 case IA64_INS_TYPE_B:
2605 ia64_emit_bundle_template (code, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [i]);
2607 case IA64_INS_TYPE_F:
2608 ia64_emit_bundle_template (code, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [i], IA64_NOP_I);
2610 case IA64_INS_TYPE_LX:
2611 ia64_emit_bundle_template (code, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [i], code->instructions [i + 1]);
2615 g_assert_not_reached ();
2623 ia64_patch (unsigned char* code, gpointer target)
2626 guint64 instructions [3];
2627 guint8 gen_buf [16];
2628 Ia64CodegenState gen;
2630 template = ia64_bundle_template (code);
2631 instructions [0] = ia64_bundle_ins1 (code);
2632 instructions [1] = ia64_bundle_ins2 (code);
2633 instructions [2] = ia64_bundle_ins3 (code);
2635 ia64_codegen_init (gen, gen_buf);
2637 for (i = 0; i < 3; ++i) {
2638 guint64 ins = instructions [i];
2639 int opcode = ia64_ins_opcode (ins);
2642 gboolean nop = FALSE;
2643 switch (ins_types_in_template [template][i]) {
2644 case IA64_INS_TYPE_I:
2645 nop = (ins == IA64_NOP_I);
2647 case IA64_INS_TYPE_M:
2648 nop = (ins == IA64_NOP_M);
2650 case IA64_INS_TYPE_LX:
2659 switch (ins_types_in_template [template][i]) {
2660 case IA64_INS_TYPE_A:
2661 case IA64_INS_TYPE_M:
2662 if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
2664 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
2665 instructions [i] = gen.instructions [0];
2670 case IA64_INS_TYPE_B:
2671 if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
2673 gint64 disp = ((guint8*)target - code) >> 4;
2676 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
2678 instructions [i] = gen.instructions [0];
2680 else if (opcode == 5) {
2682 gint64 disp = ((guint8*)target - code) >> 4;
2685 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
2686 instructions [i] = gen.instructions [0];
2691 case IA64_INS_TYPE_LX:
2695 if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
2697 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
2698 instructions [1] = gen.instructions [0];
2699 instructions [2] = gen.instructions [1];
2711 ia64_codegen_init (gen, code);
2712 ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
2716 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
2718 MonoJumpInfo *patch_info;
2720 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
2721 unsigned char *ip = patch_info->ip.i + code;
2722 const unsigned char *target;
2724 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
2726 if (mono_compile_aot) {
2730 ia64_patch (ip, (gpointer)target);
2735 mono_arch_emit_prolog (MonoCompile *cfg)
2737 MonoMethod *method = cfg->method;
2739 MonoMethodSignature *sig;
2741 int alloc_size, pos, max_offset, i;
2742 Ia64CodegenState code;
2744 unw_dyn_region_info_t *r_pro;
2747 sig = mono_method_signature (method);
2750 cinfo = get_call_info (sig, FALSE);
2752 cfg->code_size = MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
2753 cfg->native_code = g_malloc (cfg->code_size);
2755 ia64_codegen_init (code, cfg->native_code);
2756 ia64_codegen_set_automatic (code, FALSE);
2758 alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
2759 if (cfg->param_area)
2760 alloc_size += cfg->param_area;
2764 alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
2766 cfg->arch.stack_alloc_size = alloc_size;
2770 if (method->save_lmf) {
2776 /* Initialize unwind info */
2777 r_pro = g_malloc0 (_U_dyn_region_info_size (3));
2780 ia64_begin_bundle_template (code, IA64_TEMPLATE_MIIS);
2781 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);
2782 ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
2784 _U_dyn_op_save_reg (&r_pro->op[unw_op_count++], _U_QP_TRUE, /* when=*/ 0,
2785 /* reg=*/ UNW_IA64_AR_PFS, /* dst=*/ UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
2786 _U_dyn_op_save_reg (&r_pro->op[unw_op_count++], _U_QP_TRUE, /* when=*/ 1,
2787 /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + cfg->arch.reg_saved_b0);
2789 if (alloc_size || cinfo->stack_usage) {
2790 ia64_mov (code, cfg->frame_reg, IA64_SP);
2791 _U_dyn_op_save_reg (&r_pro->op[unw_op_count++], _U_QP_TRUE, /* when=*/ 2,
2792 /* reg=*/ UNW_IA64_SP, /* dst=*/ UNW_IA64_GR + cfg->frame_reg);
2795 ia64_nop_i (code, 0);
2797 ia64_end_bundle (code);
2799 /* Finish unwind info */
2800 r_pro->op_count = unw_op_count;
2801 r_pro->insn_count = (code.buf - cfg->native_code) >> 4;
2803 cfg->arch.r_pro = r_pro;
2806 /* See mono_emit_stack_alloc */
2807 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
2811 if (ia64_is_imm14 (-alloc_size)) {
2812 ia64_begin_bundle_template (code, IA64_TEMPLATE_MISI);
2813 ia64_nop_m (code, 0);
2814 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP); ia64_stop (code);
2815 ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
2816 ia64_end_bundle (code);
2819 ia64_begin_bundle_template (code, IA64_TEMPLATE_MLXS);
2820 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
2821 ia64_movl (code, GP_SCRATCH_REG, -alloc_size); ia64_stop (code);
2822 ia64_begin_bundle_template (code, IA64_TEMPLATE_MIIS);
2823 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2824 ia64_nop_i (code, 0);
2825 ia64_nop_i (code, 0); ia64_stop (code);
2826 ia64_end_bundle (code);
2830 ia64_codegen_set_automatic (code, TRUE);
2832 if (sig->ret->type != MONO_TYPE_VOID) {
2833 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
2834 /* Save volatile arguments to the stack */
2839 /* Keep this in sync with emit_load_volatile_arguments */
2840 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2841 ArgInfo *ainfo = cinfo->args + i;
2842 gint32 stack_offset;
2844 inst = cfg->varinfo [i];
2846 if (sig->hasthis && (i == 0))
2847 arg_type = &mono_defaults.object_class->byval_arg;
2849 arg_type = sig->params [i - sig->hasthis];
2851 arg_type = mono_type_get_underlying_type (arg_type);
2853 stack_offset = ainfo->offset + ARGS_OFFSET;
2855 /* Save volatile arguments to the stack */
2856 if (inst->opcode != OP_REGVAR) {
2857 switch (ainfo->storage) {
2860 /* FIXME: big offsets */
2861 g_assert (inst->opcode == OP_REGOFFSET);
2862 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
2863 if (arg_type->byref)
2864 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
2866 switch (arg_type->type) {
2868 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
2871 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
2874 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
2886 if (inst->opcode == OP_REGVAR) {
2887 /* Argument allocated to (non-volatile) register */
2888 switch (ainfo->storage) {
2890 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
2891 ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
2899 if (method->save_lmf) {
2903 ia64_codegen_close (code);
2907 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
2908 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
2910 cfg->code_len = code.buf - cfg->native_code;
2912 g_assert (cfg->code_len < cfg->code_size);
2918 mono_arch_emit_epilog (MonoCompile *cfg)
2920 MonoMethod *method = cfg->method;
2922 int max_epilog_size = 16 * 4;
2923 Ia64CodegenState code;
2927 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
2928 cfg->code_size *= 2;
2929 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2930 mono_jit_stats.code_reallocs++;
2933 /* FIXME: Emit unwind info */
2935 buf = cfg->native_code + cfg->code_len;
2937 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
2938 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
2940 ia64_codegen_init (code, buf);
2942 /* the code restoring the registers must be kept in sync with CEE_JMP */
2945 if (method->save_lmf) {
2949 /* Load returned vtypes into registers if needed */
2950 cinfo = get_call_info (mono_method_signature (method), FALSE);
2951 if (cinfo->ret.storage == ArgValuetypeInReg) {
2956 ia64_end_bundle (code);
2957 ia64_codegen_set_automatic (code, FALSE);
2959 ia64_begin_bundle_template (code, IA64_TEMPLATE_MIIS);
2960 if (cfg->arch.stack_alloc_size)
2961 ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2963 ia64_nop_m (code, 0);
2964 ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2965 ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0); ia64_stop (code);
2966 ia64_end_bundle (code);
2968 ia64_begin_bundle_template (code, IA64_TEMPLATE_BBBS);
2969 ia64_br_ret_reg (code, IA64_B0);
2970 ia64_nop_b (code, 0);
2971 ia64_nop_b (code, 0); ia64_stop (code);
2972 ia64_end_bundle (code);
2974 ia64_codegen_set_automatic (code, TRUE);
2975 ia64_codegen_close (code);
2977 cfg->code_len = code.buf - cfg->native_code;
2979 g_assert (cfg->code_len < cfg->code_size);
2983 mono_arch_emit_exceptions (MonoCompile *cfg)
2985 MonoJumpInfo *patch_info;
2987 Ia64CodegenState code;
2989 MonoClass *exc_classes [16];
2990 guint8 *exc_throw_start [16], *exc_throw_end [16];
2992 guint32 code_size = 0;
2994 /* Compute needed space */
2995 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2996 if (patch_info->type == MONO_PATCH_INFO_EXC)
2998 if (patch_info->type == MONO_PATCH_INFO_R8)
2999 code_size += 8 + 7; /* sizeof (double) + alignment */
3000 if (patch_info->type == MONO_PATCH_INFO_R4)
3001 code_size += 4 + 7; /* sizeof (float) + alignment */
3004 while (cfg->code_len + code_size > (cfg->code_size - 16)) {
3005 cfg->code_size *= 2;
3006 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3007 mono_jit_stats.code_reallocs++;
3010 ia64_codegen_init (code, cfg->native_code + cfg->code_len);
3012 /* add code to raise exceptions */
3013 /* FIXME: Optimize this */
3015 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3016 switch (patch_info->type) {
3017 case MONO_PATCH_INFO_EXC: {
3018 MonoClass *exc_class;
3022 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
3023 g_assert (exc_class);
3024 throw_ip = cfg->native_code + patch_info->ip.i;
3026 ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
3028 ia64_movl (code, cfg->arch.reg_out0 + 0, exc_class->type_token);
3030 ia64_begin_bundle (code);
3032 patch_info->data.name = "mono_arch_throw_corlib_exception";
3033 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3034 patch_info->ip.i = code.buf - cfg->native_code;
3037 ia64_movl (code, GP_SCRATCH_REG, 0);
3038 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
3039 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3040 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
3042 /* Compute the offset */
3043 buf = code.buf + 32;
3044 ia64_movl (code, cfg->arch.reg_out0 + 1, buf - throw_ip);
3046 ia64_br_call_reg (code, IA64_B0, IA64_B6);
3054 ia64_codegen_close (code);
3056 cfg->code_len = code.buf - cfg->native_code;
3058 g_assert (cfg->code_len < cfg->code_size);
3062 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3070 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3078 mono_arch_save_unwind_info (MonoCompile *cfg)
3082 /* FIXME: Unregister this for dynamic methods */
3084 di = g_malloc0 (sizeof (unw_dyn_info_t));
3085 di->start_ip = (unw_word_t) cfg->native_code;
3086 di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
3088 di->format = UNW_INFO_FORMAT_DYNAMIC;
3089 di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
3090 di->u.pi.regions = cfg->arch.r_pro;
3092 _U_dyn_register (di);
3096 mono_arch_flush_icache (guint8 *code, gint size)
3098 guint8* p = (guint8*)((guint64)code & ~(0x3f));
3099 guint8* end = (guint8*)((guint64)code + size);
3102 __asm__ __volatile__ ("fc.i %0"::"r"(p));
3108 mono_arch_flush_register_windows (void)
3110 /* Not needed because of libunwind */
3114 mono_arch_is_inst_imm (gint64 imm)
3116 /* The lowering pass will take care of it */
3122 * Determine whenever the trap whose info is in SIGINFO is caused by
3126 mono_arch_is_int_overflow (void *sigctx, void *info)
3128 /* Division is emulated with explicit overflow checks */
3133 mono_arch_get_patch_offset (guint8 *code)
3141 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
3143 guint8 *bundle1 = code - 48;
3144 guint8 *bundle2 = code - 32;
3145 guint8 *bundle3 = code - 16;
3146 guint64 ins11 = ia64_bundle_ins1 (bundle1);
3147 guint64 ins12 = ia64_bundle_ins2 (bundle1);
3148 guint64 ins13 = ia64_bundle_ins3 (bundle1);
3149 guint64 ins21 = ia64_bundle_ins1 (bundle2);
3150 guint64 ins22 = ia64_bundle_ins2 (bundle2);
3151 guint64 ins23 = ia64_bundle_ins3 (bundle2);
3152 guint64 ins31 = ia64_bundle_ins1 (bundle3);
3153 guint64 ins32 = ia64_bundle_ins2 (bundle3);
3154 guint64 ins33 = ia64_bundle_ins3 (bundle3);
3158 * Virtual calls are made with:
3160 * mov.sptk b6=r8,0x2000000000f32a80
3167 * br.call.sptk.few b0=b6;;
3170 if ((ia64_bundle_template (bundle2) == IA64_TEMPLATE_MIIS) &&
3171 (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIBS) &&
3172 (ins21 == IA64_NOP_M) &&
3173 (ia64_ins_opcode (ins22) == 0) && (ia64_ins_x3 (ins22) == 0) && (ia64_ins_x6 (ins22) == 0x1) && (ia64_ins_y (ins22) == 0) &&
3174 (ins23 == IA64_NOP_I) &&
3175 (ins31 == IA64_NOP_M) &&
3176 (ins32 == IA64_NOP_I) &&
3177 (ia64_ins_opcode (ins33) == 1) && (ia64_ins_b1 (ins33) == 0) && (ia64_ins_b2 (ins33) == 6) &&
3178 ((ins22 >> 6) & 0xfffff) == 0x12345) {
3179 g_assert (ins11 == IA64_NOP_M);
3180 g_assert (ins13 == IA64_NOP_I);
3181 g_assert (ia64_ins_opcode (ins12) == 0);
3182 g_assert (ia64_ins_x3 (ins12) == 7);
3183 g_assert (ia64_ins_x (ins12) == 0);
3184 g_assert (ia64_ins_b1 (ins12) == IA64_B6);
3186 reg = ia64_ins_r2 (ins12);
3189 * Must be a scratch register, since only those are saved by the trampoline
3191 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
3193 g_assert (regs [reg]);
3202 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
3209 static gboolean tls_offset_inited = FALSE;
3211 /* code should be simply return <tls var>; */
3213 read_tls_offset_from_method (void* method)
3220 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3223 setup_stack (MonoJitTlsData *tls)
3231 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3233 if (!tls_offset_inited) {
3234 tls_offset_inited = TRUE;
3238 lmf_tls_offset = read_tls_offset_from_method (mono_get_lmf_addr);
3239 appdomain_tls_offset = read_tls_offset_from_method (mono_domain_get);
3240 thread_tls_offset = read_tls_offset_from_method (mono_thread_current);
3244 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3250 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3252 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3253 struct sigaltstack sa;
3255 sa.ss_sp = tls->signal_stack;
3256 sa.ss_size = SIGNAL_STACK_SIZE;
3257 sa.ss_flags = SS_DISABLE;
3258 sigaltstack (&sa, NULL);
3260 if (tls->signal_stack)
3261 munmap (tls->signal_stack, SIGNAL_STACK_SIZE);
3266 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3268 MonoCallInst *call = (MonoCallInst*)inst;
3269 int out_reg = cfg->arch.reg_out0;
3272 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
3275 if (cinfo->ret.storage == ArgValuetypeInReg) {
3279 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
3280 vtarg->sreg1 = vt_reg;
3281 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3282 mono_bblock_add_inst (cfg->cbb, vtarg);
3284 mono_call_inst_add_outarg_reg (call, vtarg->dreg, out_reg, FALSE);
3292 /* add the this argument */
3293 if (this_reg != -1) {
3295 MONO_INST_NEW (cfg, this, OP_MOVE);
3296 this->type = this_type;
3297 this->sreg1 = this_reg;
3298 this->dreg = mono_regstate_next_int (cfg->rs);
3299 mono_bblock_add_inst (cfg->cbb, this);
3301 mono_call_inst_add_outarg_reg (call, this->dreg, out_reg, FALSE);
3306 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3308 MonoInst *ins = NULL;
3313 if (cmethod->klass == mono_defaults.math_class) {
3314 if (strcmp (cmethod->name, "Sin") == 0) {
3315 MONO_INST_NEW (cfg, ins, OP_SIN);
3316 ins->inst_i0 = args [0];
3317 } else if (strcmp (cmethod->name, "Cos") == 0) {
3318 MONO_INST_NEW (cfg, ins, OP_COS);
3319 ins->inst_i0 = args [0];
3320 } else if (strcmp (cmethod->name, "Tan") == 0) {
3322 MONO_INST_NEW (cfg, ins, OP_TAN);
3323 ins->inst_i0 = args [0];
3324 } else if (strcmp (cmethod->name, "Atan") == 0) {
3326 MONO_INST_NEW (cfg, ins, OP_ATAN);
3327 ins->inst_i0 = args [0];
3328 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
3329 MONO_INST_NEW (cfg, ins, OP_SQRT);
3330 ins->inst_i0 = args [0];
3331 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
3332 MONO_INST_NEW (cfg, ins, OP_ABS);
3333 ins->inst_i0 = args [0];
3336 /* OP_FREM is not IEEE compatible */
3337 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
3338 MONO_INST_NEW (cfg, ins, OP_FREM);
3339 ins->inst_i0 = args [0];
3340 ins->inst_i1 = args [1];
3343 } else if(cmethod->klass->image == mono_defaults.corlib &&
3344 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
3345 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
3347 if (strcmp (cmethod->name, "Increment") == 0) {
3348 MonoInst *ins_iconst;
3351 if (fsig->params [0]->type == MONO_TYPE_I4)
3352 opcode = OP_ATOMIC_ADD_NEW_I4;
3353 else if (fsig->params [0]->type == MONO_TYPE_I8)
3354 opcode = OP_ATOMIC_ADD_NEW_I8;
3356 g_assert_not_reached ();
3357 MONO_INST_NEW (cfg, ins, opcode);
3358 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3359 ins_iconst->inst_c0 = 1;
3361 ins->inst_i0 = args [0];
3362 ins->inst_i1 = ins_iconst;
3363 } else if (strcmp (cmethod->name, "Decrement") == 0) {
3364 MonoInst *ins_iconst;
3367 if (fsig->params [0]->type == MONO_TYPE_I4)
3368 opcode = OP_ATOMIC_ADD_NEW_I4;
3369 else if (fsig->params [0]->type == MONO_TYPE_I8)
3370 opcode = OP_ATOMIC_ADD_NEW_I8;
3372 g_assert_not_reached ();
3373 MONO_INST_NEW (cfg, ins, opcode);
3374 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3375 ins_iconst->inst_c0 = -1;
3377 ins->inst_i0 = args [0];
3378 ins->inst_i1 = ins_iconst;
3379 } else if (strcmp (cmethod->name, "Add") == 0) {
3382 if (fsig->params [0]->type == MONO_TYPE_I4)
3383 opcode = OP_ATOMIC_ADD_I4;
3384 else if (fsig->params [0]->type == MONO_TYPE_I8)
3385 opcode = OP_ATOMIC_ADD_I8;
3387 g_assert_not_reached ();
3389 MONO_INST_NEW (cfg, ins, opcode);
3391 ins->inst_i0 = args [0];
3392 ins->inst_i1 = args [1];
3393 } else if (strcmp (cmethod->name, "Exchange") == 0) {
3396 if (fsig->params [0]->type == MONO_TYPE_I4)
3397 opcode = OP_ATOMIC_EXCHANGE_I4;
3398 else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
3399 (fsig->params [0]->type == MONO_TYPE_I) ||
3400 (fsig->params [0]->type == MONO_TYPE_OBJECT))
3401 opcode = OP_ATOMIC_EXCHANGE_I8;
3405 MONO_INST_NEW (cfg, ins, opcode);
3407 ins->inst_i0 = args [0];
3408 ins->inst_i1 = args [1];
3409 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
3410 /* 64 bit reads are already atomic */
3411 MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
3412 ins->inst_i0 = args [0];
3416 * Can't implement CompareExchange methods this way since they have
3425 mono_arch_print_tree (MonoInst *tree, int arity)
3430 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3434 if (appdomain_tls_offset == -1)
3437 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3438 ins->inst_offset = appdomain_tls_offset;
3442 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3446 if (thread_tls_offset == -1)
3449 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3450 ins->inst_offset = thread_tls_offset;