[docs] Enable documentation for mini.
[mono.git] / mono / mini / mini-ia64.c
1 /**
2  * \file
3  * IA64 backend for the Mono code generator
4  *
5  * Authors:
6  *   Zoltan Varga (vargaz@gmail.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  */
10 #include "mini.h"
11 #include <string.h>
12 #include <math.h>
13 #include <unistd.h>
14 #include <sys/mman.h>
15
16 #ifdef __INTEL_COMPILER
17 #include <ia64intrin.h>
18 #endif
19
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>
26
27 #include "trace.h"
28 #include "mini-ia64.h"
29 #include "cpu-ia64.h"
30 #include "jit-icalls.h"
31 #include "ir-emit.h"
32
33 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
34
35 #define IS_IMM32(val) ((((guint64)val) >> 32) == 0)
36
37 /*
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
45  */
46
47 /*
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.
52  */
53
54 #define ARGS_OFFSET 16
55
56 #define GP_SCRATCH_REG 31
57 #define GP_SCRATCH_REG2 30
58 #define FP_SCRATCH_REG 32
59 #define FP_SCRATCH_REG2 33
60
61 #define LOOP_ALIGNMENT 8
62 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
63
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"
78 };
79
80 const char*
81 mono_arch_regname (int reg)
82 {
83         if (reg < 128)
84                 return gregs [reg];
85         else
86                 return "unknown";
87 }
88
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"
103 };
104
105 const char*
106 mono_arch_fregname (int reg)
107 {
108         if (reg < 128)
109                 return fregs [reg];
110         else
111                 return "unknown";
112 }
113
114 static gboolean
115 debug_ins_sched (void)
116 {
117 #if 0
118         return mono_debug_count ();
119 #else
120         return TRUE;
121 #endif
122 }
123
124 static gboolean
125 debug_omit_fp (void)
126 {
127 #if 0
128         return mono_debug_count ();
129 #else
130         return TRUE;
131 #endif
132 }
133
134 static void 
135 ia64_patch (unsigned char* code, gpointer target);
136
137 typedef enum {
138         ArgInIReg,
139         ArgInFloatReg,
140         ArgInFloatRegR4,
141         ArgOnStack,
142         ArgValuetypeAddrInIReg,
143         ArgAggregate,
144         ArgSingleHFA,
145         ArgDoubleHFA,
146         ArgNone
147 } ArgStorage;
148
149 typedef enum {
150         AggregateNormal,
151         AggregateSingleHFA,
152         AggregateDoubleHFA
153 } AggregateType;
154
155 typedef struct {
156         gint16 offset;
157         gint8  reg;
158         ArgStorage storage;
159
160         /* Only if storage == ArgAggregate */
161         int nregs, nslots;
162         AggregateType atype;
163 } ArgInfo;
164
165 typedef struct {
166         int nargs;
167         guint32 stack_usage;
168         guint32 reg_usage;
169         guint32 freg_usage;
170         gboolean need_stack_align;
171         gboolean vtype_retaddr;
172         /* The index of the vret arg in the argument list */
173         int vret_arg_index;
174         ArgInfo ret;
175         ArgInfo sig_cookie;
176         ArgInfo args [1];
177 } CallInfo;
178
179 #define DEBUG(a) if (cfg->verbose_level > 1) a
180
181 #define PARAM_REGS 8
182
183 static void inline
184 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
185 {
186     ainfo->offset = *stack_size;
187
188     if (*gr >= PARAM_REGS) {
189                 ainfo->storage = ArgOnStack;
190                 (*stack_size) += sizeof (gpointer);
191     }
192     else {
193                 ainfo->storage = ArgInIReg;
194                 ainfo->reg = *gr;
195                 *(gr) += 1;
196     }
197 }
198
199 #define FLOAT_PARAM_REGS 8
200
201 static void inline
202 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
203 {
204     ainfo->offset = *stack_size;
205
206     if (*gr >= PARAM_REGS) {
207                 ainfo->storage = ArgOnStack;
208                 (*stack_size) += sizeof (gpointer);
209     }
210     else {
211                 ainfo->storage = is_double ? ArgInFloatReg : ArgInFloatRegR4;
212                 ainfo->reg = 8 + *fr;
213                 (*fr) += 1;
214                 (*gr) += 1;
215     }
216 }
217
218 static void
219 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
220                gboolean is_return,
221                guint32 *gr, guint32 *fr, guint32 *stack_size)
222 {
223         guint32 size, i;
224         MonoClass *klass;
225         MonoMarshalType *info;
226         gboolean is_hfa = TRUE;
227         guint32 hfa_type = 0;
228
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);
234         else 
235                 size = mini_type_stack_size (&klass->byval_arg, NULL);
236
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;
242
243                 return;
244         }
245
246         /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
247         info = mono_marshal_load_type_info (klass);
248         g_assert (info);
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))) {
253                         if (hfa_type == 0)
254                                 hfa_type = ftype;
255                         else if (hfa_type != ftype)
256                                 is_hfa = FALSE;
257                 }
258                 else
259                         is_hfa = FALSE;
260         }
261         if (hfa_type == 0)
262                 is_hfa = FALSE;
263
264         ainfo->storage = ArgAggregate;
265         ainfo->atype = AggregateNormal;
266
267         if (is_hfa) {
268                 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
269                 if (is_return) {
270                         if (info->num_fields <= 8) {
271                                 ainfo->reg = 8;
272                                 ainfo->nregs = info->num_fields;
273                                 ainfo->nslots = ainfo->nregs;
274                                 return;
275                         }
276                         /* Fall through */
277                 }
278                 else {
279                         if ((*fr) + info->num_fields > 8)
280                                 NOT_IMPLEMENTED;
281
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) {
287                                 /*
288                                  * FIXME: Have to keep track of the parameter slot number, which is
289                                  * not the same as *gr.
290                                  */
291                                 (*gr) += ALIGN_TO (info->num_fields, 2) / 2;
292                         } else {
293                                 (*gr) += info->num_fields;
294                         }
295                         return;
296                 }
297         }
298
299         /* This also handles returning of TypedByRef used by some icalls */
300         if (is_return) {
301                 if (size <= 32) {
302                         ainfo->reg = IA64_R8;
303                         ainfo->nregs = (size + 7) / 8;
304                         ainfo->nslots = ainfo->nregs;
305                         return;
306                 }
307                 NOT_IMPLEMENTED;
308         }
309
310         ainfo->reg = (*gr);
311         ainfo->offset = *stack_size;
312         ainfo->nslots = (size + 7) / 8;
313
314         if (((*gr) + ainfo->nslots) <= 8) {
315                 /* Fits entirely in registers */
316                 ainfo->nregs = ainfo->nslots;
317                 (*gr) += ainfo->nregs;
318                 return;
319         }
320
321         ainfo->nregs = 8 - (*gr);
322         (*gr) = 8;
323         (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
324 }
325
326 /*
327  * get_call_info:
328  *
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.
332  */
333 static CallInfo*
334 get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
335 {
336         guint32 i, gr, fr, pstart;
337         MonoType *ret_type;
338         int n = sig->hasthis + sig->param_count;
339         guint32 stack_size = 0;
340         CallInfo *cinfo;
341
342         if (mp)
343                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
344         else
345                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
346
347         gr = 0;
348         fr = 0;
349
350         /* return value */
351         {
352                 ret_type = mini_get_underlying_type (sig->ret);
353                 switch (ret_type->type) {
354                 case MONO_TYPE_BOOLEAN:
355                 case MONO_TYPE_I1:
356                 case MONO_TYPE_U1:
357                 case MONO_TYPE_I2:
358                 case MONO_TYPE_U2:
359                 case MONO_TYPE_CHAR:
360                 case MONO_TYPE_I4:
361                 case MONO_TYPE_U4:
362                 case MONO_TYPE_I:
363                 case MONO_TYPE_U:
364                 case MONO_TYPE_PTR:
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;
373                         break;
374                 case MONO_TYPE_U8:
375                 case MONO_TYPE_I8:
376                         cinfo->ret.storage = ArgInIReg;
377                         cinfo->ret.reg = IA64_R8;
378                         break;
379                 case MONO_TYPE_R4:
380                 case MONO_TYPE_R8:
381                         cinfo->ret.storage = ArgInFloatReg;
382                         cinfo->ret.reg = 8;
383                         break;
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;
388                                 break;
389                         }
390                         /* Fall through */
391                 case MONO_TYPE_VALUETYPE:
392                 case MONO_TYPE_TYPEDBYREF: {
393                         guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
394
395                         if (sig->ret->byref) {
396                                 /* This seems to happen with ldfld wrappers */
397                                 cinfo->ret.storage = ArgInIReg;
398                         } else {
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;
403                                 }
404                         }
405                         break;
406                 }
407                 case MONO_TYPE_VOID:
408                         cinfo->ret.storage = ArgNone;
409                         break;
410                 default:
411                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
412                 }
413         }
414
415         pstart = 0;
416         /*
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
421          * invoke wrappers.
422          */
423         if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
424                 if (sig->hasthis) {
425                         add_general (&gr, &stack_size, cinfo->args + 0);
426                 } else {
427                         add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
428                         pstart = 1;
429                 }
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;
434         } else {
435                 /* this */
436                 if (sig->hasthis)
437                         add_general (&gr, &stack_size, cinfo->args + 0);
438
439                 if (cinfo->vtype_retaddr) {
440                         add_general (&gr, &stack_size, &cinfo->ret);
441                         if (cinfo->ret.storage == ArgInIReg)
442                                 cinfo->ret.storage = ArgValuetypeAddrInIReg;
443                 }
444         }
445
446         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
447                 gr = PARAM_REGS;
448                 fr = FLOAT_PARAM_REGS;
449                 
450                 /* Emit the signature cookie just before the implicit arguments */
451                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
452         }
453
454         for (i = pstart; i < sig->param_count; ++i) {
455                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
456                 MonoType *ptype;
457
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 */
460                         /* 
461                          * Prevent implicit arguments + the sig cookie from being passed 
462                          * in registers.
463                          */
464                         gr = PARAM_REGS;
465                         fr = FLOAT_PARAM_REGS;
466
467                         /* Emit the signature cookie just before the implicit arguments */
468                         add_general (&gr, &stack_size, &cinfo->sig_cookie);
469                 }
470
471                 if (sig->params [i]->byref) {
472                         add_general (&gr, &stack_size, ainfo);
473                         continue;
474                 }
475                 ptype = mini_get_underlying_type (sig->params [i]);
476                 switch (ptype->type) {
477                 case MONO_TYPE_BOOLEAN:
478                 case MONO_TYPE_I1:
479                 case MONO_TYPE_U1:
480                         add_general (&gr, &stack_size, ainfo);
481                         break;
482                 case MONO_TYPE_I2:
483                 case MONO_TYPE_U2:
484                 case MONO_TYPE_CHAR:
485                         add_general (&gr, &stack_size, ainfo);
486                         break;
487                 case MONO_TYPE_I4:
488                 case MONO_TYPE_U4:
489                         add_general (&gr, &stack_size, ainfo);
490                         break;
491                 case MONO_TYPE_I:
492                 case MONO_TYPE_U:
493                 case MONO_TYPE_PTR:
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);
501                         break;
502                 case MONO_TYPE_GENERICINST:
503                         if (!mono_type_generic_inst_is_valuetype (ptype)) {
504                                 add_general (&gr, &stack_size, ainfo);
505                                 break;
506                         }
507                         /* Fall through */
508                 case MONO_TYPE_VALUETYPE:
509                 case MONO_TYPE_TYPEDBYREF:
510                         /* FIXME: */
511                         /* We allways pass valuetypes on the stack */
512                         add_valuetype (sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
513                         break;
514                 case MONO_TYPE_U8:
515                 case MONO_TYPE_I8:
516                         add_general (&gr, &stack_size, ainfo);
517                         break;
518                 case MONO_TYPE_R4:
519                         add_float (&gr, &fr, &stack_size, ainfo, FALSE);
520                         break;
521                 case MONO_TYPE_R8:
522                         add_float (&gr, &fr, &stack_size, ainfo, TRUE);
523                         break;
524                 default:
525                         g_assert_not_reached ();
526                 }
527         }
528
529         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
530                 gr = PARAM_REGS;
531                 fr = FLOAT_PARAM_REGS;
532                 
533                 /* Emit the signature cookie just before the implicit arguments */
534                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
535         }
536
537         cinfo->stack_usage = stack_size;
538         cinfo->reg_usage = gr;
539         cinfo->freg_usage = fr;
540         return cinfo;
541 }
542
543 /*
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
548  *
549  * Gathers information on parameters such as size, alignment and
550  * padding. arg_info should be large enought to hold param_count + 1 entries. 
551  *
552  * Returns the size of the argument area on the stack.
553  */
554 int
555 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
556 {
557         int k;
558         CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
559         guint32 args_size = cinfo->stack_usage;
560
561         /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
562         if (csig->hasthis) {
563                 arg_info [0].offset = 0;
564         }
565
566         for (k = 0; k < param_count; k++) {
567                 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
568                 /* FIXME: */
569                 arg_info [k + 1].size = 0;
570         }
571
572         g_free (cinfo);
573
574         return args_size;
575 }
576
577 /*
578  * Initialize the cpu to execute managed code.
579  */
580 void
581 mono_arch_cpu_init (void)
582 {
583 }
584
585 /*
586  * Initialize architecture specific code.
587  */
588 void
589 mono_arch_init (void)
590 {
591 }
592
593 /*
594  * Cleanup architecture specific code.
595  */
596 void
597 mono_arch_cleanup (void)
598 {
599 }
600
601 gboolean
602 mono_arch_have_fast_tls (void)
603 {
604         return FALSE;
605 }
606
607 /*
608  * This function returns the optimizations supported on this cpu.
609  */
610 guint32
611 mono_arch_cpu_optimizations (guint32 *exclude_mask)
612 {
613         *exclude_mask = 0;
614
615         return 0;
616 }
617
618 /*
619  * This function test for all SIMD functions supported.
620  *
621  * Returns a bitmask corresponding to all supported versions.
622  *
623  */
624 guint32
625 mono_arch_cpu_enumerate_simd_versions (void)
626 {
627         /* SIMD is currently unimplemented */
628         return 0;
629 }
630
631 GList *
632 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
633 {
634         GList *vars = NULL;
635         int i;
636         MonoMethodSignature *sig;
637         MonoMethodHeader *header;
638         CallInfo *cinfo;
639
640         header = cfg->header;
641
642         sig = mono_method_signature (cfg->method);
643
644         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
645
646         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
647                 MonoInst *ins = cfg->args [i];
648
649                 ArgInfo *ainfo = &cinfo->args [i];
650
651                 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
652                         continue;
653
654                 if (ainfo->storage == ArgInIReg) {
655                         /* The input registers are non-volatile */
656                         ins->opcode = OP_REGVAR;
657                         ins->dreg = 32 + ainfo->reg;
658                 }
659         }
660
661         for (i = 0; i < cfg->num_varinfo; i++) {
662                 MonoInst *ins = cfg->varinfo [i];
663                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
664
665                 /* unused vars */
666                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
667                         continue;
668
669                 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || 
670                     (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
671                         continue;
672
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);
677                 }
678         }
679
680         vars = mono_varlist_sort (cfg, vars, 0);
681
682         return vars;
683 }
684
685 static void
686 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
687 {
688         CallInfo *cinfo;
689         guint32 reserved_regs;
690         MonoMethodHeader *header;
691
692         if (cfg->arch.reg_local0 > 0)
693                 /* Already done */
694                 return;
695
696         cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
697
698         header = cfg->header;
699         
700         /* Some registers are reserved for use by the prolog/epilog */
701         reserved_regs = header->num_clauses ? 4 : 3;
702
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 */
706                 reserved_regs ++;
707                 if (cinfo->reg_usage < 2)
708                         /* Number of arguments passed to function call in instrument_prolog */
709                         cinfo->reg_usage = 2;
710         }
711
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;
715
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;
719
720         /* 
721          * Frames without handlers save sp to fp, frames with handlers save it into
722          * a dedicated register.
723          */
724         if (header->num_clauses)
725                 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
726         else
727                 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
728
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;
732         }
733
734         /* 
735          * Need to allocate at least 2 out register for use by OP_THROW / the system
736          * exception throwing code.
737          */
738         cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
739 }
740
741 GList *
742 mono_arch_get_global_int_regs (MonoCompile *cfg)
743 {
744         GList *regs = NULL;
745         int i;
746
747         mono_ia64_alloc_stacked_registers (cfg);
748
749         for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
750                 /* FIXME: regmask */
751                 g_assert (i < 64);
752                 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
753         }
754
755         return regs;
756 }
757
758 /*
759  * mono_arch_regalloc_cost:
760  *
761  *  Return the cost, in number of memory references, of the action of 
762  * allocating the variable VMV into a register during global register
763  * allocation.
764  */
765 guint32
766 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
767 {
768         /* FIXME: Increase costs linearly to avoid using all local registers */
769
770         return 0;
771 }
772  
773 void
774 mono_arch_allocate_vars (MonoCompile *cfg)
775 {
776         MonoMethodSignature *sig;
777         MonoMethodHeader *header;
778         MonoInst *inst;
779         int i, offset;
780         guint32 locals_stack_size, locals_stack_align;
781         gint32 *offsets;
782         CallInfo *cinfo;
783
784         header = cfg->header;
785
786         sig = mono_method_signature (cfg->method);
787
788         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
789
790         /*
791          * Determine whenever the frame pointer can be eliminated.
792          * FIXME: Remove some of the restrictions.
793          */
794         cfg->arch.omit_fp = TRUE;
795
796         if (!debug_omit_fp ())
797                 cfg->arch.omit_fp = FALSE;
798
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;
803         if (cfg->param_area)
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];
811
812                 if (ainfo->storage == ArgOnStack) {
813                         /* 
814                          * The stack offset can only be determined when the frame
815                          * size is known.
816                          */
817                         cfg->arch.omit_fp = FALSE;
818                 }
819         }
820
821         mono_ia64_alloc_stacked_registers (cfg);
822
823         /*
824          * We use the ABI calling conventions for managed code as well.
825          * Exception: valuetypes are never passed or returned in registers.
826          */
827
828         if (cfg->arch.omit_fp) {
829                 cfg->flags |= MONO_CFG_HAS_SPILLUP;
830                 cfg->frame_reg = IA64_SP;
831                 offset = ARGS_OFFSET;
832         }
833         else {
834                 /* Locals are allocated backwards from %fp */
835                 cfg->frame_reg = cfg->arch.reg_fp;
836                 offset = 0;
837         }
838
839         if (cfg->method->save_lmf) {
840                 /* No LMF on IA64 */
841         }
842
843         if (sig->ret->type != MONO_TYPE_VOID) {
844                 switch (cinfo->ret.storage) {
845                 case ArgInIReg:
846                         cfg->ret->opcode = OP_REGVAR;
847                         cfg->ret->inst_c0 = cinfo->ret.reg;
848                         break;
849                 case ArgInFloatReg:
850                         cfg->ret->opcode = OP_REGVAR;
851                         cfg->ret->inst_c0 = cinfo->ret.reg;
852                         break;
853                 case ArgValuetypeAddrInIReg:
854                         cfg->vret_addr->opcode = OP_REGVAR;
855                         cfg->vret_addr->dreg = cfg->arch.reg_in0 + cinfo->ret.reg;
856                         break;
857                 case ArgAggregate:
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;
866                         break;
867                 default:
868                         g_assert_not_reached ();
869                 }
870                 cfg->ret->dreg = cfg->ret->inst_c0;
871         }
872
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);
877         }
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]);
885                         else
886                                 inst->inst_offset = - (offset + offsets [i]);
887                         // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
888                 }
889         }
890         offset += locals_stack_size;
891
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;
897         }
898
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;
904                         MonoType *arg_type;
905
906                         if (sig->hasthis && (i == 0))
907                                 arg_type = &mono_defaults.object_class->byval_arg;
908                         else
909                                 arg_type = sig->params [i - sig->hasthis];
910
911                         /* FIXME: VOLATILE is only set if the liveness pass runs */
912                         if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
913                                 inreg = FALSE;
914
915                         inst->opcode = OP_REGOFFSET;
916
917                         switch (ainfo->storage) {
918                         case ArgInIReg:
919                                 inst->opcode = OP_REGVAR;
920                                 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
921                                 break;
922                         case ArgInFloatReg:
923                         case ArgInFloatRegR4:
924                                 /* 
925                                  * Since float regs are volatile, we save the arguments to
926                                  * the stack in the prolog.
927                                  */
928                                 inreg = FALSE;
929                                 break;
930                         case ArgOnStack:
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;
936                                 break;
937                         case ArgAggregate:
938                                 inreg = FALSE;
939                                 break;
940                         default:
941                                 NOT_IMPLEMENTED;
942                         }
943
944                         if (!inreg && (ainfo->storage != ArgOnStack)) {
945                                 guint32 size = 0;
946
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) {
951                                 case ArgAggregate:
952                                         if (ainfo->atype == AggregateSingleHFA)
953                                                 size = ainfo->nslots * 4;
954                                         else
955                                                 size = ainfo->nslots * 8;
956                                         break;
957                                 default:
958                                         size = sizeof (gpointer);
959                                         break;
960                                 }
961
962                                 offset = ALIGN_TO (offset, sizeof (gpointer));
963
964                                 if (cfg->arch.omit_fp) {
965                                         inst->inst_offset = offset;
966                                         offset += size;
967                                 } else {
968                                         offset += size;
969                                         inst->inst_offset = - offset;
970                                 }
971                         }
972                 }
973         }
974
975         /* 
976          * FIXME: This doesn't work because some variables are allocated during local
977          * regalloc.
978          */
979         /*
980         if (cfg->arch.omit_fp && offset == 16)
981                 offset = 0;
982         */
983
984         cfg->stack_offset = offset;
985 }
986
987 void
988 mono_arch_create_vars (MonoCompile *cfg)
989 {
990         MonoMethodSignature *sig;
991         CallInfo *cinfo;
992
993         sig = mono_method_signature (cfg->method);
994
995         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
996
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);
1004                 }
1005         }
1006 }
1007
1008 static void
1009 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree)
1010 {
1011         MonoInst *arg;
1012
1013         MONO_INST_NEW (cfg, arg, OP_NOP);
1014         arg->sreg1 = tree->dreg;
1015
1016         switch (storage) {
1017         case ArgInIReg:
1018                 arg->opcode = OP_MOVE;
1019                 arg->dreg = mono_alloc_ireg (cfg);
1020
1021                 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, FALSE);
1022                 break;
1023         case ArgInFloatReg:
1024                 arg->opcode = OP_FMOVE;
1025                 arg->dreg = mono_alloc_freg (cfg);
1026
1027                 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1028                 break;
1029         case ArgInFloatRegR4:
1030                 arg->opcode = OP_FCONV_TO_R4;
1031                 arg->dreg = mono_alloc_freg (cfg);
1032
1033                 mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, reg, TRUE);
1034                 break;
1035         default:
1036                 g_assert_not_reached ();
1037         }
1038
1039         MONO_ADD_INS (cfg->cbb, arg);
1040 }
1041
1042 static void
1043 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1044 {
1045         MonoMethodSignature *tmp_sig;
1046
1047         /* Emit the signature cookie just before the implicit arguments */
1048         MonoInst *sig_arg;
1049         /* FIXME: Add support for signature tokens to AOT */
1050         cfg->disable_aot = TRUE;
1051
1052         g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1053
1054         /*
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.
1059          */
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*));
1064
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);
1069
1070         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + cinfo->sig_cookie.offset, sig_arg->dreg);
1071 }
1072
1073 void
1074 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1075 {
1076         MonoInst *in;
1077         MonoMethodSignature *sig;
1078         int i, n, stack_size;
1079         CallInfo *cinfo;
1080         ArgInfo *ainfo;
1081
1082         stack_size = 0;
1083
1084         mono_ia64_alloc_stacked_registers (cfg);
1085
1086         sig = call->signature;
1087         n = sig->param_count + sig->hasthis;
1088
1089         cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1090
1091         if (cinfo->ret.storage == ArgAggregate) {
1092                 MonoInst *vtarg;
1093                 MonoInst *local;
1094
1095                 /* 
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.
1099                  */
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;
1103
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);
1108         }
1109
1110         if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
1111                 add_outarg_reg (cfg, call, ArgInIReg, cfg->arch.reg_out0 + cinfo->ret.reg, call->vret_var);
1112         }
1113
1114         for (i = 0; i < n; ++i) {
1115                 MonoType *arg_type;
1116
1117                 ainfo = cinfo->args + i;
1118
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);
1122                 }
1123
1124                 in = call->args [i];
1125
1126                 if (sig->hasthis && (i == 0))
1127                         arg_type = &mono_defaults.object_class->byval_arg;
1128                 else
1129                         arg_type = sig->params [i - sig->hasthis];
1130
1131                 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1132                         guint32 align;
1133                         guint32 size;
1134
1135                         if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1136                                 size = sizeof (MonoTypedRef);
1137                                 align = sizeof (gpointer);
1138                         }
1139                         else if (sig->pinvoke)
1140                                 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1141                         else {
1142                                 /* 
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.
1147                                  */
1148                                 size = mono_class_value_size (in->klass, &align);
1149                         }
1150
1151                         if (size > 0) {
1152                                 MonoInst *arg;
1153
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));
1161
1162                                 MONO_ADD_INS (cfg->cbb, arg);
1163                         }
1164                 }
1165                 else {
1166                         switch (ainfo->storage) {
1167                         case ArgInIReg:
1168                                 add_outarg_reg (cfg, call, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1169                                 break;
1170                         case ArgInFloatReg:
1171                         case ArgInFloatRegR4:
1172                                 add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, in);
1173                                 break;
1174                         case ArgOnStack:
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);
1179                                 else
1180                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, IA64_SP, 16 + ainfo->offset, in->dreg);
1181                                 break;
1182                         default:
1183                                 g_assert_not_reached ();
1184                         }
1185                 }
1186         }
1187
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);
1191         }
1192
1193         call->stack_usage = cinfo->stack_usage;
1194         cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1195 }
1196
1197 void
1198 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1199 {
1200         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1201         ArgInfo *ainfo = (ArgInfo*)ins->inst_p1;
1202         int size = ins->backend.size;
1203
1204         if (ainfo->storage == ArgAggregate) {
1205                 MonoInst *load, *store;
1206                 int i, slot;
1207
1208                 /* 
1209                  * Part of the structure is passed in registers.
1210                  */
1211                 for (i = 0; i < ainfo->nregs; ++i) {
1212                         slot = ainfo->reg + i;
1213                         
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);
1219
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);
1226
1227                                 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg + i, TRUE);
1228                         } else {
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);
1233
1234                                 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, cfg->arch.reg_out0 + ainfo->reg + i, FALSE);
1235                         }
1236                         MONO_ADD_INS (cfg->cbb, load);
1237                 }
1238
1239                 /* 
1240                  * Part of the structure is passed on the stack.
1241                  */
1242                 for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
1243                         slot = ainfo->reg + i;
1244
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);
1250
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);
1256                 }
1257         } else {
1258                 mini_emit_memcpy (cfg, IA64_SP, 16 + ainfo->offset, src->dreg, 0, size, 4);
1259         }
1260 }
1261
1262 void
1263 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1264 {
1265         CallInfo *cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
1266
1267         switch (cinfo->ret.storage) {
1268         case ArgInIReg:
1269                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1270                 break;
1271         case ArgInFloatReg:
1272                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1273                 break;
1274         default:
1275                 g_assert_not_reached ();
1276         }
1277 }
1278
1279 void
1280 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1281 {
1282 }
1283
1284 void
1285 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1286 {
1287         MonoInst *ins, *n, *last_ins = NULL;
1288         ins = bb->code;
1289
1290         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1291                 switch (ins->opcode) {
1292                 case OP_MOVE:
1293                 case OP_FMOVE:
1294                         /*
1295                          * Removes:
1296                          *
1297                          * OP_MOVE reg, reg 
1298                          */
1299                         if (ins->dreg == ins->sreg1) {
1300                                 MONO_DELETE_INS (bb, ins);
1301                                 continue;
1302                         }
1303                         /* 
1304                          * Removes:
1305                          *
1306                          * OP_MOVE sreg, dreg 
1307                          * OP_MOVE dreg, sreg
1308                          */
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);
1313                                 continue;
1314                         }
1315                         break;
1316                 case OP_MUL_IMM: 
1317                 case OP_IMUL_IMM: 
1318                         /* remove unnecessary multiplication with 1 */
1319                         if (ins->inst_imm == 1) {
1320                                 if (ins->dreg != ins->sreg1) {
1321                                         ins->opcode = OP_MOVE;
1322                                 } else {
1323                                         MONO_DELETE_INS (bb, ins);
1324                                         continue;
1325                                 }
1326                         }
1327                         break;
1328                 }
1329
1330                 last_ins = ins;
1331                 ins = ins->next;
1332         }
1333         bb->last_ins = last_ins;
1334 }
1335
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}
1347 };
1348
1349 static int
1350 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1351 {
1352         return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1353 }
1354
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},
1366 };
1367
1368 static int
1369 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1370 {
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)];
1373 }
1374
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); \
1380         } while (0)
1381
1382 /*
1383  * mono_arch_lowering_pass:
1384  *
1385  *  Converts complex opcodes into simpler ones so that each IR instruction
1386  * corresponds to one machine instruction.
1387  */
1388 void
1389 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1390 {
1391         MonoInst *ins, *n, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1392         ins = bb->code;
1393
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) {
1403                                 temp2 = NULL;
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);
1409                         }
1410                         else {
1411                                 NEW_INS (cfg, temp, OP_I8CONST);
1412                                 temp->inst_c0 = ins->inst_offset;
1413                                 temp->dreg = mono_alloc_ireg (cfg);
1414
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);
1419                         }
1420
1421                         switch (ins->opcode) {
1422                         case OP_STOREI1_MEMBASE_IMM:
1423                                 ins->opcode = OP_STOREI1_MEMBASE_REG;
1424                                 break;
1425                         case OP_STOREI2_MEMBASE_IMM:
1426                                 ins->opcode = OP_STOREI2_MEMBASE_REG;
1427                                 break;
1428                         case OP_STOREI4_MEMBASE_IMM:
1429                                 ins->opcode = OP_STOREI4_MEMBASE_REG;
1430                                 break;
1431                         case OP_STOREI8_MEMBASE_IMM:
1432                         case OP_STORE_MEMBASE_IMM:
1433                                 ins->opcode = OP_STOREI8_MEMBASE_REG;
1434                                 break;
1435                         default:
1436                                 g_assert_not_reached ();
1437                         }
1438
1439                         if (ins->inst_imm == 0)
1440                                 ins->sreg1 = IA64_R0;
1441                         else {
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;
1446                         }
1447
1448                         ins->inst_offset = 0;
1449                         if (temp2)
1450                                 ins->inst_destbasereg = temp2->dreg;
1451                         break;
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) {
1461                                 break;
1462                         }
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);
1468                         }
1469                         else {
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);
1477                         }
1478
1479                         ins->inst_offset = 0;
1480                         ins->inst_destbasereg = temp2->dreg;
1481                         break;
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) {
1500                                 break;
1501                         }
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);
1507                         }
1508                         else {
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);
1516                         }
1517
1518                         ins->inst_offset = 0;
1519                         ins->inst_basereg = temp2->dreg;
1520                         break;
1521                 case OP_ADD_IMM:
1522                 case OP_IADD_IMM:
1523                 case OP_LADD_IMM:
1524                 case OP_ISUB_IMM:
1525                 case OP_LSUB_IMM:
1526                 case OP_AND_IMM:
1527                 case OP_IAND_IMM:
1528                 case OP_LAND_IMM:
1529                 case OP_IOR_IMM:
1530                 case OP_LOR_IMM:
1531                 case OP_IXOR_IMM:
1532                 case OP_LXOR_IMM:
1533                 case OP_SHL_IMM:
1534                 case OP_SHR_IMM:
1535                 case OP_ISHL_IMM:
1536                 case OP_LSHL_IMM:
1537                 case OP_ISHR_IMM:
1538                 case OP_LSHR_IMM:
1539                 case OP_ISHR_UN_IMM:
1540                 case OP_LSHR_UN_IMM: {
1541                         gboolean is_imm = FALSE;
1542                         gboolean switched = FALSE;
1543
1544                         if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1545                                 ins->opcode = OP_ZEXT_I1;
1546                                 break;
1547                         }
1548
1549                         switch (ins->opcode) {
1550                         case OP_ADD_IMM:
1551                         case OP_IADD_IMM:
1552                         case OP_LADD_IMM:
1553                                 is_imm = ia64_is_imm14 (ins->inst_imm);
1554                                 switched = TRUE;
1555                                 break;
1556                         case OP_ISUB_IMM:
1557                         case OP_LSUB_IMM:
1558                                 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1559                                 if (is_imm) {
1560                                         /* A = B - IMM -> A = B + (-IMM) */
1561                                         ins->inst_imm = - ins->inst_imm;
1562                                         ins->opcode = OP_IADD_IMM;
1563                                 }
1564                                 switched = TRUE;
1565                                 break;
1566                         case OP_IAND_IMM:
1567                         case OP_IOR_IMM:
1568                         case OP_IXOR_IMM:
1569                         case OP_AND_IMM:
1570                         case OP_LAND_IMM:
1571                         case OP_LOR_IMM:
1572                         case OP_LXOR_IMM:
1573                                 is_imm = ia64_is_imm8 (ins->inst_imm);
1574                                 switched = TRUE;
1575                                 break;
1576                         case OP_SHL_IMM:
1577                         case OP_SHR_IMM:
1578                         case OP_ISHL_IMM:
1579                         case OP_LSHL_IMM:
1580                         case OP_ISHR_IMM:
1581                         case OP_LSHR_IMM:
1582                         case OP_ISHR_UN_IMM:
1583                         case OP_LSHR_UN_IMM:
1584                                 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1585                                 break;
1586                         default:
1587                                 break;
1588                         }
1589
1590                         if (is_imm) {
1591                                 if (switched)
1592                                         ins->sreg2 = ins->sreg1;
1593                                 break;
1594                         }
1595
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);
1599
1600                         if (ins->inst_imm == 0)
1601                                 ins->sreg2 = IA64_R0;
1602                         else {
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;
1607                         }
1608                         break;
1609                 }
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 */
1614                         gboolean imm;
1615                         CompRelation cond;
1616
1617                         next = ins->next;
1618
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)))) {
1621                                 NULLIFY_INS (ins);
1622                                 break;
1623                         }
1624
1625                         /* 
1626                          * The compare_imm instructions have switched up arguments, and 
1627                          * some of them take an imm between -127 and 128.
1628                          */
1629                         next = ins->next;
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);
1635                         else
1636                                 imm = ia64_is_imm8 (ins->inst_imm);
1637
1638                         if (imm) {
1639                                 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1640                                 ins->sreg2 = ins->sreg1;
1641                         }
1642                         else {
1643                                 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1644
1645                                 if (ins->inst_imm == 0)
1646                                         ins->sreg2 = IA64_R0;
1647                                 else {
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;
1652                                 }
1653                         }
1654
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;
1662                         } else {
1663                                 printf ("%s\n", mono_inst_name (next->opcode));
1664                                 NOT_IMPLEMENTED;
1665                         }
1666
1667                         break;
1668                 }
1669                 case OP_COMPARE:
1670                 case OP_ICOMPARE:
1671                 case OP_LCOMPARE:
1672                 case OP_FCOMPARE: {
1673                         /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1674
1675                         next = ins->next;
1676
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)))) {
1679                                 NULLIFY_INS (ins);
1680                                 break;
1681                         }
1682
1683                         ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1684
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;
1692                         } else {
1693                                 printf ("%s\n", mono_inst_name (next->opcode));
1694                                 NOT_IMPLEMENTED;
1695                         }
1696
1697                         break;
1698                 }
1699                 case OP_FCEQ:
1700                 case OP_FCGT:
1701                 case OP_FCGT_UN:
1702                 case OP_FCLT:
1703                 case OP_FCLT_UN:
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;
1708                         
1709                         ins->opcode = OP_IA64_CSET;
1710                         MONO_INST_NULLIFY_SREGS (ins);
1711                         break;
1712                 case OP_MUL_IMM:
1713                 case OP_LMUL_IMM:
1714                 case OP_IMUL_IMM: {
1715                         int i, sum_reg;
1716                         gboolean found = FALSE;
1717                         int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1718
1719                         /* First the easy cases */
1720                         if (ins->inst_imm == 1) {
1721                                 ins->opcode = OP_MOVE;
1722                                 break;
1723                         }
1724                         for (i = 1; i < 64; ++i)
1725                                 if (ins->inst_imm == (((gint64)1) << i)) {
1726                                         ins->opcode = shl_op;
1727                                         ins->inst_imm = i;
1728                                         found = TRUE;
1729                                         break;
1730                                 }
1731
1732                         /* This could be optimized */
1733                         if (!found) {
1734                                 sum_reg = 0;
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;
1740                                                 temp->inst_imm = i;
1741
1742                                                 if (sum_reg == 0)
1743                                                         sum_reg = temp->dreg;
1744                                                 else {
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;
1750                                                 }
1751                                         }
1752                                 }
1753                                 ins->opcode = OP_MOVE;
1754                                 ins->sreg1 = sum_reg;
1755                         }
1756                         break;
1757                 }
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;
1762
1763                         NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1764                         temp->inst_p1 = (char*)"OverflowException";
1765
1766                         ins->opcode = OP_MOVE;
1767                         break;
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);
1772
1773                         NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1774                         temp2->sreg1 = ins->sreg1;
1775                         temp2->sreg2 = temp->dreg;
1776
1777                         NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1778                         temp->inst_p1 = (char*)"OverflowException";
1779
1780                         ins->opcode = OP_MOVE;
1781                         break;
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;
1790
1791                         switch (ins->opcode) {
1792                         case OP_FCONV_TO_I4:
1793                                 ins->opcode = OP_SEXT_I4;
1794                                 break;
1795                         case OP_FCONV_TO_I2:
1796                                 ins->opcode = OP_SEXT_I2;
1797                                 break;
1798                         case OP_FCONV_TO_U2:
1799                                 ins->opcode = OP_ZEXT_I4;
1800                                 break;
1801                         case OP_FCONV_TO_I1:
1802                                 ins->opcode = OP_SEXT_I1;
1803                                 break;
1804                         case OP_FCONV_TO_U1:
1805                                 ins->opcode = OP_ZEXT_I1;
1806                                 break;
1807                         default:
1808                                 g_assert_not_reached ();
1809                         }
1810                         ins->sreg1 = ins->dreg;
1811                         break;
1812                 default:
1813                         break;
1814                 }
1815                 last_ins = ins;
1816                 ins = ins->next;
1817         }
1818         bb->last_ins = last_ins;
1819
1820         bb->max_vreg = cfg->next_vreg;
1821 }
1822
1823 /*
1824  * emit_load_volatile_arguments:
1825  *
1826  *  Load volatile arguments from the stack to the original input registers.
1827  * Required before a tail call.
1828  */
1829 static Ia64CodegenState
1830 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1831 {
1832         MonoMethod *method = cfg->method;
1833         MonoMethodSignature *sig;
1834         MonoInst *ins;
1835         CallInfo *cinfo;
1836         guint32 i;
1837
1838         /* FIXME: Generate intermediate code instead */
1839
1840         sig = mono_method_signature (method);
1841
1842         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
1843         
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;
1848                 MonoType *arg_type;
1849
1850                 ins = cfg->args [i];
1851
1852                 if (sig->hasthis && (i == 0))
1853                         arg_type = &mono_defaults.object_class->byval_arg;
1854                 else
1855                         arg_type = sig->params [i - sig->hasthis];
1856
1857                 arg_type = mini_get_underlying_type (arg_type);
1858
1859                 stack_offset = ainfo->offset + ARGS_OFFSET;
1860
1861                 /* Save volatile arguments to the stack */
1862                 if (ins->opcode != OP_REGVAR) {
1863                         switch (ainfo->storage) {
1864                         case ArgInIReg:
1865                         case ArgInFloatReg:
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);
1871                                 else {
1872                                         switch (arg_type->type) {
1873                                         case MONO_TYPE_R4:
1874                                                 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1875                                                 break;
1876                                         case MONO_TYPE_R8:
1877                                                 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1878                                                 break;
1879                                         default:
1880                                                 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1881                                                 break;
1882                                         }
1883                                 }
1884                                 break;
1885                         case ArgOnStack:
1886                                 break;
1887                         default:
1888                                 NOT_IMPLEMENTED;
1889                         }
1890                 }
1891
1892                 if (ins->opcode == OP_REGVAR) {
1893                         /* Argument allocated to (non-volatile) register */
1894                         switch (ainfo->storage) {
1895                         case ArgInIReg:
1896                                 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1897                                         ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1898                                 break;
1899                         case ArgOnStack:
1900                                 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1901                                 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1902                                 break;
1903                         default:
1904                                 NOT_IMPLEMENTED;
1905                         }
1906                 }
1907         }
1908
1909         return code;
1910 }
1911
1912 static Ia64CodegenState
1913 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1914 {
1915         CallInfo *cinfo;
1916         int i;
1917
1918         /* Move return value to the target register */
1919         switch (ins->opcode) {
1920         case OP_VOIDCALL:
1921         case OP_VOIDCALL_REG:
1922         case OP_VOIDCALL_MEMBASE:
1923                 break;
1924         case OP_CALL:
1925         case OP_CALL_REG:
1926         case OP_CALL_MEMBASE:
1927         case OP_LCALL:
1928         case OP_LCALL_REG:
1929         case OP_LCALL_MEMBASE:
1930                 g_assert (ins->dreg == IA64_R8);
1931                 break;
1932         case OP_FCALL:
1933         case OP_FCALL_REG:
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);
1938                 break;
1939         case OP_VCALL:
1940         case OP_VCALL_REG:
1941         case OP_VCALL_MEMBASE:
1942         case OP_VCALL2:
1943         case OP_VCALL2_REG:
1944         case OP_VCALL2_MEMBASE: {
1945                 ArgStorage storage;
1946
1947                 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
1948                 storage = cinfo->ret.storage;
1949
1950                 if (storage == ArgAggregate) {
1951                         MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
1952
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);
1957
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);
1962                                         break;
1963                                 case AggregateSingleHFA:
1964                                         ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
1965                                         break;
1966                                 case AggregateDoubleHFA:
1967                                         ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
1968                                         break;
1969                                 default:
1970                                         g_assert_not_reached ();
1971                                 }
1972                         }
1973                 }
1974                 break;
1975         }
1976         default:
1977                 g_assert_not_reached ();
1978         }
1979
1980         return code;
1981 }
1982
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); \
1985 } while (0)
1986
1987 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
1988         MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1989     if (tins == NULL) \
1990         add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
1991     else \
1992                 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
1993         ia64_br_cond_pred (code, (predicate), 0); \
1994 } while (0)
1995
1996 static Ia64CodegenState
1997 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
1998 {
1999         add_patch_info (cfg, code, patch_type, data);
2000
2001         if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2002                 /* Indirect call */
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);
2009         }
2010         else {
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);
2016         }
2017
2018         return code;
2019 }
2020
2021 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2022
2023 void
2024 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2025 {
2026         MonoInst *ins;
2027         MonoCallInst *call;
2028         guint offset;
2029         Ia64CodegenState code;
2030         guint8 *code_start = cfg->native_code + cfg->code_len;
2031         MonoInst *last_ins = NULL;
2032         guint last_offset = 0;
2033         int max_len, cpos;
2034
2035         if (cfg->opt & MONO_OPT_LOOP) {
2036                 /* FIXME: */
2037         }
2038
2039         if (cfg->verbose_level > 2)
2040                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2041
2042         cpos = bb->max_offset;
2043
2044         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2045                 NOT_IMPLEMENTED;
2046         }
2047
2048         offset = code_start - cfg->native_code;
2049
2050         ia64_codegen_init (code, code_start);
2051
2052 #if 0
2053         if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2054                 break_count ();
2055 #endif
2056
2057         MONO_BB_FOR_EACH_INS (bb, ins) {
2058                 offset = code.buf - cfg->native_code;
2059
2060                 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2061
2062                 while (offset + max_len + 16 > cfg->code_size) {
2063                         ia64_codegen_close (code);
2064
2065                         offset = code.buf - cfg->native_code;
2066
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++;
2071
2072                         ia64_codegen_init (code, code_start);
2073                 }
2074
2075                 mono_debug_record_line_number (cfg, ins, offset);
2076
2077                 switch (ins->opcode) {
2078                 case OP_ICONST:
2079                 case OP_I8CONST:
2080                         if (ia64_is_imm14 (ins->inst_c0))
2081                                 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2082                         else
2083                                 ia64_movl (code, ins->dreg, ins->inst_c0);
2084                         break;
2085                 case OP_JUMP_TABLE:
2086                         add_patch_info (cfg, code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2087                         ia64_movl (code, ins->dreg, 0);
2088                         break;
2089                 case OP_MOVE:
2090                         ia64_mov (code, ins->dreg, ins->sreg1);
2091                         break;
2092                 case OP_BR:
2093                 case OP_IA64_BR_COND: {
2094                         int pred = 0;
2095                         if (ins->opcode == OP_IA64_BR_COND)
2096                                 pred = 6;
2097                         if (ins->inst_target_bb->native_offset) {
2098                                 guint8 *pos = code.buf + code.nins;
2099
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);
2103                         } else {
2104                                 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2105                                 ia64_br_cond_pred (code, pred, 0);
2106                         } 
2107                         break;
2108                 }
2109                 case OP_LABEL:
2110                         ia64_begin_bundle (code);
2111                         ins->inst_c0 = code.buf - cfg->native_code;
2112                         break;
2113                 case OP_NOP:
2114                 case OP_RELAXED_NOP:
2115                 case OP_DUMMY_USE:
2116                 case OP_DUMMY_STORE:
2117                 case OP_NOT_REACHED:
2118                 case OP_NOT_NULL:
2119                         break;
2120                 case OP_BR_REG:
2121                         ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2122                         ia64_br_cond_reg (code, IA64_B6);
2123                         break;
2124                 case OP_IADD:
2125                 case OP_LADD:
2126                         ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2127                         break;
2128                 case OP_ISUB:
2129                 case OP_LSUB:
2130                         ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2131                         break;
2132                 case OP_IAND:
2133                 case OP_LAND:
2134                         ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2135                         break;
2136                 case OP_IOR:
2137                 case OP_LOR:
2138                         ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2139                         break;
2140                 case OP_IXOR:
2141                 case OP_LXOR:
2142                         ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2143                         break;
2144                 case OP_INEG:
2145                 case OP_LNEG:
2146                         ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2147                         break;
2148                 case OP_INOT:
2149                 case OP_LNOT:
2150                         ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2151                         break;
2152                 case OP_ISHL:
2153                 case OP_LSHL:
2154                         ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2155                         break;
2156                 case OP_ISHR:
2157                         ia64_sxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2158                         ia64_shr (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2159                         break;
2160                 case OP_LSHR:
2161                         ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2162                         break;
2163                 case OP_ISHR_UN:
2164                         ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2165                         ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2166                         break;
2167                 case OP_LSHR_UN:
2168                         ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2169                         break;
2170                 case OP_IADDCC:
2171                         /* p6 and p7 is set if there is signed/unsigned overflow */
2172                         
2173                         /* Set p8-p9 == (sreg2 > 0) */
2174                         ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2175
2176                         ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2177                         
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);
2182
2183                         /* res <u sreg1 => unsigned overflow */
2184                         ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2185
2186                         /* FIXME: Predicate this since this is a side effect */
2187                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2188                         break;
2189                 case OP_ISUBCC:
2190                         /* p6 and p7 is set if there is signed/unsigned overflow */
2191                         
2192                         /* Set p8-p9 == (sreg2 > 0) */
2193                         ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2194
2195                         ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2196                         
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);
2201
2202                         /* sreg1 <u sreg2 => unsigned overflow */
2203                         ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2204
2205                         /* FIXME: Predicate this since this is a side effect */
2206                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2207                         break;
2208                 case OP_ADDCC:
2209                         /* Same as OP_IADDCC */
2210                         ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2211
2212                         ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2213                         
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);
2216
2217                         ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2218
2219                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2220                         break;
2221                 case OP_SUBCC:
2222                         /* Same as OP_ISUBCC */
2223
2224                         ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2225
2226                         ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2227                         
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);
2230
2231                         ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2232
2233                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2234                         break;
2235                 case OP_ADD_IMM:
2236                 case OP_IADD_IMM:
2237                 case OP_LADD_IMM:
2238                         ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2239                         break;
2240                 case OP_IAND_IMM:
2241                 case OP_AND_IMM:
2242                 case OP_LAND_IMM:
2243                         ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2244                         break;
2245                 case OP_IOR_IMM:
2246                 case OP_LOR_IMM:
2247                         ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2248                         break;
2249                 case OP_IXOR_IMM:
2250                 case OP_LXOR_IMM:
2251                         ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2252                         break;
2253                 case OP_SHL_IMM:
2254                 case OP_ISHL_IMM:
2255                 case OP_LSHL_IMM:
2256                         ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2257                         break;
2258                 case OP_SHR_IMM:
2259                 case OP_LSHR_IMM:
2260                         ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2261                         break;
2262                 case OP_ISHR_IMM:
2263                         g_assert (ins->inst_imm <= 64);
2264                         ia64_extr (code, ins->dreg, ins->sreg1, ins->inst_imm, 32 - ins->inst_imm);
2265                         break;
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);
2269                         break;
2270                 case OP_LSHR_UN_IMM:
2271                         ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2272                         break;
2273                 case OP_LMUL:
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);
2279                         break;
2280
2281                 case OP_STOREI1_MEMBASE_REG:
2282                         ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2283                         break;
2284                 case OP_STOREI2_MEMBASE_REG:
2285                         ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2286                         break;
2287                 case OP_STOREI4_MEMBASE_REG:
2288                         ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2289                         break;
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);
2296                                 } else {
2297                                         ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2298                                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2299                                 }
2300                                 ins->inst_destbasereg = GP_SCRATCH_REG;
2301                         }
2302                         ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2303                         break;
2304
2305                 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2306                         ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2307                         break;
2308                 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2309                         ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2310                         break;
2311                 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2312                         ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2313                         break;
2314                 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2315                         ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2316                         break;
2317
2318                 case OP_LOADU1_MEMBASE:
2319                         ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2320                         break;
2321                 case OP_LOADU2_MEMBASE:
2322                         ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2323                         break;
2324                 case OP_LOADU4_MEMBASE:
2325                         ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2326                         break;
2327                 case OP_LOADI1_MEMBASE:
2328                         ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2329                         ia64_sxt1 (code, ins->dreg, ins->dreg);
2330                         break;
2331                 case OP_LOADI2_MEMBASE:
2332                         ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2333                         ia64_sxt2 (code, ins->dreg, ins->dreg);
2334                         break;
2335                 case OP_LOADI4_MEMBASE:
2336                         ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2337                         ia64_sxt4 (code, ins->dreg, ins->dreg);
2338                         break;
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);
2345                                 } else {
2346                                         ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2347                                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2348                                 }
2349                                 ins->inst_basereg = GP_SCRATCH_REG;
2350                         }
2351                         ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2352                         break;
2353
2354                 case OP_IA64_LOADU1_MEMBASE_INC:
2355                         ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2356                         break;
2357                 case OP_IA64_LOADU2_MEMBASE_INC:
2358                         ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2359                         break;
2360                 case OP_IA64_LOADU4_MEMBASE_INC:
2361                         ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2362                         break;
2363                 case OP_IA64_LOADI8_MEMBASE_INC:
2364                         ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2365                         break;
2366
2367                 case OP_SEXT_I1:
2368                         ia64_sxt1 (code, ins->dreg, ins->sreg1);
2369                         break;
2370                 case OP_SEXT_I2:
2371                         ia64_sxt2 (code, ins->dreg, ins->sreg1);
2372                         break;
2373                 case OP_SEXT_I4:
2374                         ia64_sxt4 (code, ins->dreg, ins->sreg1);
2375                         break;
2376                 case OP_ZEXT_I1:
2377                         ia64_zxt1 (code, ins->dreg, ins->sreg1);
2378                         break;
2379                 case OP_ZEXT_I2:
2380                         ia64_zxt2 (code, ins->dreg, ins->sreg1);
2381                         break;
2382                 case OP_ZEXT_I4:
2383                         ia64_zxt4 (code, ins->dreg, ins->sreg1);
2384                         break;
2385
2386                         /* Compare opcodes */
2387                 case OP_IA64_CMP4_EQ:
2388                         ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2389                         break;
2390                 case OP_IA64_CMP4_NE:
2391                         ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2392                         break;
2393                 case OP_IA64_CMP4_LE:
2394                         ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2395                         break;
2396                 case OP_IA64_CMP4_LT:
2397                         ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2398                         break;
2399                 case OP_IA64_CMP4_GE:
2400                         ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2401                         break;
2402                 case OP_IA64_CMP4_GT:
2403                         ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2404                         break;
2405                 case OP_IA64_CMP4_LT_UN:
2406                         ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2407                         break;
2408                 case OP_IA64_CMP4_LE_UN:
2409                         ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2410                         break;
2411                 case OP_IA64_CMP4_GT_UN:
2412                         ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2413                         break;
2414                 case OP_IA64_CMP4_GE_UN:
2415                         ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2416                         break;
2417                 case OP_IA64_CMP_EQ:
2418                         ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2419                         break;
2420                 case OP_IA64_CMP_NE:
2421                         ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2422                         break;
2423                 case OP_IA64_CMP_LE:
2424                         ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2425                         break;
2426                 case OP_IA64_CMP_LT:
2427                         ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2428                         break;
2429                 case OP_IA64_CMP_GE:
2430                         ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2431                         break;
2432                 case OP_IA64_CMP_GT:
2433                         ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2434                         break;
2435                 case OP_IA64_CMP_GT_UN:
2436                         ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2437                         break;
2438                 case OP_IA64_CMP_LT_UN:
2439                         ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2440                         break;
2441                 case OP_IA64_CMP_GE_UN:
2442                         ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2443                         break;
2444                 case OP_IA64_CMP_LE_UN:
2445                         ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2446                         break;
2447                 case OP_IA64_CMP4_EQ_IMM:
2448                         ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2449                         break;
2450                 case OP_IA64_CMP4_NE_IMM:
2451                         ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2452                         break;
2453                 case OP_IA64_CMP4_LE_IMM:
2454                         ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2455                         break;
2456                 case OP_IA64_CMP4_LT_IMM:
2457                         ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2458                         break;
2459                 case OP_IA64_CMP4_GE_IMM:
2460                         ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2461                         break;
2462                 case OP_IA64_CMP4_GT_IMM:
2463                         ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2464                         break;
2465                 case OP_IA64_CMP4_LT_UN_IMM:
2466                         ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2467                         break;
2468                 case OP_IA64_CMP4_LE_UN_IMM:
2469                         ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2470                         break;
2471                 case OP_IA64_CMP4_GT_UN_IMM:
2472                         ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2473                         break;
2474                 case OP_IA64_CMP4_GE_UN_IMM:
2475                         ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2476                         break;
2477                 case OP_IA64_CMP_EQ_IMM:
2478                         ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2479                         break;
2480                 case OP_IA64_CMP_NE_IMM:
2481                         ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2482                         break;
2483                 case OP_IA64_CMP_LE_IMM:
2484                         ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2485                         break;
2486                 case OP_IA64_CMP_LT_IMM:
2487                         ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2488                         break;
2489                 case OP_IA64_CMP_GE_IMM:
2490                         ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2491                         break;
2492                 case OP_IA64_CMP_GT_IMM:
2493                         ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2494                         break;
2495                 case OP_IA64_CMP_GT_UN_IMM:
2496                         ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2497                         break;
2498                 case OP_IA64_CMP_LT_UN_IMM:
2499                         ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2500                         break;
2501                 case OP_IA64_CMP_GE_UN_IMM:
2502                         ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2503                         break;
2504                 case OP_IA64_CMP_LE_UN_IMM:
2505                         ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2506                         break;
2507                 case OP_IA64_FCMP_EQ:
2508                         ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2509                         break;
2510                 case OP_IA64_FCMP_NE:
2511                         ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2512                         break;
2513                 case OP_IA64_FCMP_LT:
2514                         ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2515                         break;
2516                 case OP_IA64_FCMP_GT:
2517                         ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2518                         break;
2519                 case OP_IA64_FCMP_LE:
2520                         ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2521                         break;
2522                 case OP_IA64_FCMP_GE:
2523                         ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2524                         break;
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);
2528                         break;
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);
2532                         break;
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);
2536                         break;
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);
2540                         break;
2541
2542                 case OP_COND_EXC_IOV:
2543                 case OP_COND_EXC_OV:
2544                         emit_cond_system_exception (cfg, code, "OverflowException", 6);
2545                         break;
2546                 case OP_COND_EXC_IC:
2547                 case OP_COND_EXC_C:
2548                         emit_cond_system_exception (cfg, code, "OverflowException", 7);
2549                         break;
2550                 case OP_IA64_COND_EXC:
2551                         emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2552                         break;
2553                 case OP_IA64_CSET:
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);
2557                         break;
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);
2562                         break;
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);
2567                         break;
2568                 case OP_LCONV_TO_I4:
2569                         /* FIXME: Is this needed ? */
2570                         ia64_sxt4 (code, ins->dreg, ins->sreg1);
2571                         break;
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);
2576                         break;
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);
2581                         break;
2582                 case OP_LCONV_TO_U4:
2583                         /* FIXME: Is this needed */
2584                         ia64_zxt4 (code, ins->dreg, ins->sreg1);
2585                         break;
2586                 case OP_ICONV_TO_I8:
2587                 case OP_ICONV_TO_I:
2588                 case OP_LCONV_TO_I8:
2589                 case OP_LCONV_TO_I:
2590                         ia64_sxt4 (code, ins->dreg, ins->sreg1);
2591                         break;
2592                 case OP_LCONV_TO_U8:
2593                 case OP_LCONV_TO_U:
2594                         ia64_zxt4 (code, ins->dreg, ins->sreg1);
2595                         break;
2596
2597                         /*
2598                          * FLOAT OPCODES
2599                          */
2600                 case OP_R8CONST: {
2601                         double d = *(double *)ins->inst_p0;
2602
2603                         if ((d == 0.0) && (mono_signbit (d) == 0))
2604                                 ia64_fmov (code, ins->dreg, 0);
2605                         else if (d == 1.0)
2606                                 ia64_fmov (code, ins->dreg, 1);
2607                         else {
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);
2611                         }
2612                         break;
2613                 }
2614                 case OP_R4CONST: {
2615                         float f = *(float *)ins->inst_p0;
2616
2617                         if ((f == 0.0) && (mono_signbit (f) == 0))
2618                                 ia64_fmov (code, ins->dreg, 0);
2619                         else if (f == 1.0)
2620                                 ia64_fmov (code, ins->dreg, 1);
2621                         else {
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);
2625                         }
2626                         break;
2627                 }
2628                 case OP_FMOVE:
2629                         ia64_fmov (code, ins->dreg, ins->sreg1);
2630                         break;
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);
2636                                 } else {
2637                                         ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2638                                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_destbasereg);
2639                                 }
2640                                 ins->inst_destbasereg = GP_SCRATCH_REG;
2641                         }
2642                         ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2643                         break;
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);
2647                         break;
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);
2653                                 } else {
2654                                         ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2655                                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, ins->inst_basereg);
2656                                 }
2657                                 ins->inst_basereg = GP_SCRATCH_REG;
2658                         }
2659                         ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2660                         break;
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);
2664                         break;
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);
2670                         break;
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);
2676                         break;
2677                 case OP_FCONV_TO_R4:
2678                         ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2679                         break;
2680                 case OP_FCONV_TO_I8:
2681                 case OP_FCONV_TO_I:
2682                         ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2683                         ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2684                         break;
2685                 case OP_FADD:
2686                         ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2687                         break;
2688                 case OP_FSUB:
2689                         ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2690                         break;
2691                 case OP_FMUL:
2692                         ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2693                         break;
2694                 case OP_FNEG:
2695                         ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2696                         break;
2697                 case OP_CKFINITE:
2698                         /* Quiet NaN */
2699                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2700                         emit_cond_system_exception (cfg, code, "OverflowException", 6);
2701                         /* Signaling NaN */
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);
2710                         break;
2711
2712                 /* Calls */
2713                 case OP_CHECK_THIS:
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);
2717                         break;
2718                 case OP_ARGLIST:
2719                         ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2720                         ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2721                         break;
2722                 case OP_FCALL:
2723                 case OP_LCALL:
2724                 case OP_VCALL:
2725                 case OP_VCALL2:
2726                 case OP_VOIDCALL:
2727                 case OP_CALL:
2728                         call = (MonoCallInst*)ins;
2729
2730                         if (ins->flags & MONO_INST_HAS_METHOD)
2731                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2732                         else
2733                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2734
2735                         code = emit_move_return_value (cfg, ins, code);
2736                         break;
2737
2738                 case OP_CALL_REG:
2739                 case OP_FCALL_REG:
2740                 case OP_LCALL_REG:
2741                 case OP_VCALL_REG:
2742                 case OP_VCALL2_REG:
2743                 case OP_VOIDCALL_REG: {
2744                         MonoCallInst *call = (MonoCallInst*)ins;
2745                         CallInfo *cinfo;
2746                         int out_reg;
2747
2748                         /* 
2749                          * mono_arch_get_this_arg_from_call () needs to find the this argument in a global 
2750                          * register.
2751                          */
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);
2755
2756                         /* Indirect call */
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);
2762
2763                         code = emit_move_return_value (cfg, ins, code);
2764                         break;
2765                 }
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;
2773                         CallInfo *cinfo;
2774                         int out_reg;
2775
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);
2779                         else {
2780                                 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2781                                 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2782                         }
2783
2784                         if (call->method && ins->inst_offset < 0) {
2785                                 /* 
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 
2788                                  * access it.
2789                                  */
2790                                 ia64_movl (code, IA64_R9, call->method);
2791                         }
2792
2793                         /* 
2794                          * mono_arch_find_this_arg () needs to find the this argument in a global 
2795                          * register.
2796                          */
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);
2800
2801                         ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2802
2803                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2804
2805                         ia64_br_call_reg (code, IA64_B0, IA64_B6);
2806
2807                         code = emit_move_return_value (cfg, ins, code);
2808                         break;
2809                 }
2810                 case OP_JMP: {
2811                         /*
2812                          * Keep in sync with the code in emit_epilog.
2813                          */
2814
2815                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2816                                 NOT_IMPLEMENTED;
2817
2818                         g_assert (!cfg->method->save_lmf);
2819
2820                         /* Load arguments into their original registers */
2821                         code = emit_load_volatile_arguments (cfg, code);
2822
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);
2827                                         else {
2828                                                 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2829                                                 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2830                                         }
2831                                 }
2832                                 else
2833                                         ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2834                         }
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);
2837
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);
2842
2843                         break;
2844                 }
2845                 case OP_BREAK:
2846                         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_break);
2847                         break;
2848
2849                 case OP_LOCALLOC: {
2850                         gint32 abi_offset;
2851
2852                         /* FIXME: Sigaltstack support */
2853
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);
2858
2859                         ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2860
2861                         ia64_mov (code, ins->dreg, IA64_SP);
2862
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);
2867                         else {
2868                                 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2869                                 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2870                         }
2871
2872                         if (ins->flags & MONO_INST_INIT) {
2873                                 /* Upper limit */
2874                                 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2875
2876                                 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2877
2878                                 /* Init loop */
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);
2882
2883                                 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2884
2885                                 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2886                         }
2887
2888                         break;
2889                 }
2890                 case OP_LOCALLOC_IMM: {
2891                         gint32 abi_offset;
2892
2893                         /* FIXME: Sigaltstack support */
2894
2895                         gssize size = ins->inst_imm;
2896                         size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
2897
2898                         if (ia64_is_adds_imm (size))
2899                                 ia64_adds_imm (code, GP_SCRATCH_REG, size, IA64_R0);
2900                         else
2901                                 ia64_movl (code, GP_SCRATCH_REG, size);
2902
2903                         ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2904                         ia64_mov (code, ins->dreg, IA64_SP);
2905
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);
2910                         else {
2911                                 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2912                                 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2913                         }
2914
2915                         if (ins->flags & MONO_INST_INIT) {
2916                                 /* Upper limit */
2917                                 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2918
2919                                 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2920
2921                                 /* Init loop */
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);
2925
2926                                 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2927
2928                                 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2929                         }
2930
2931                         break;
2932                 }
2933                         /* Synchronization */
2934                 case OP_MEMORY_BARRIER:
2935                         ia64_mf (code);
2936                         break;
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);
2941                         break;
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);
2946                         break;
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);
2950                         break;
2951                 case OP_ATOMIC_EXCHANGE_I8:
2952                         ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2953                         break;
2954                 case OP_ATOMIC_ADD_I4: {
2955                         guint8 *label, *buf;
2956
2957                         /* From libatomic_ops */
2958                         ia64_mf (code);
2959
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);
2972                         break;
2973                 }
2974                 case OP_ATOMIC_ADD_I8: {
2975                         guint8 *label, *buf;
2976
2977                         /* From libatomic_ops */
2978                         ia64_mf (code);
2979
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);
2992                         break;
2993                 }
2994
2995                         /* Exception handling */
2996                 case OP_CALL_HANDLER:
2997                         /*
2998                          * Using a call instruction would mess up the register stack, so
2999                          * save the return address to a register and use a
3000                          * branch.
3001                          */
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);
3011                         // FIXME:
3012                         //mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3013                         ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3014                         break;
3015                 case OP_START_HANDLER: {
3016                         /*
3017                          * We receive the return address in GP_SCRATCH_REG.
3018                          */
3019                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3020
3021                         /* 
3022                          * R15 determines our caller. It is used since it is writable using
3023                          * libunwind.
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 ().
3026                          */
3027                         ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3028                         ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3029
3030                         ia64_br_cond_pred (code, 6, 6);
3031
3032                         /*
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. 
3040                          */
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);
3047
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);
3051                         else {
3052                                 ia64_movl (code, GP_SCRATCH_REG2, spvar->inst_offset);
3053                                 ia64_add (code, GP_SCRATCH_REG2, cfg->frame_reg, GP_SCRATCH_REG2);
3054                         }
3055
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);
3059
3060                         break;
3061                 }
3062                 case OP_ENDFINALLY:
3063                 case OP_ENDFILTER: {
3064                         /* FIXME: Return the value in ENDFILTER */
3065                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3066
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);
3070                         } else {
3071                                 ia64_movl (code, GP_SCRATCH_REG, spvar->inst_offset);
3072                                 ia64_add (code, GP_SCRATCH_REG, cfg->frame_reg, GP_SCRATCH_REG);
3073                         }
3074                         ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3075
3076                         /* Test caller */
3077                         ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3078                         ia64_br_cond_pred (code, 7, 4);
3079
3080                         /* Called by call_filter */
3081                         /* Pop frame */
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);                        
3085
3086                         /* Called by CALL_HANDLER */
3087                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3088                         ia64_br_cond_reg (code, IA64_B6);
3089                         break;
3090                 }
3091                 case OP_THROW:
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");
3095
3096                         /* 
3097                          * This might be the last instruction in the method, so add a dummy
3098                          * instruction so the unwinder will work.
3099                          */
3100                         ia64_break_i (code, 0);
3101                         break;
3102                 case OP_RETHROW:
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");
3106
3107                         ia64_break_i (code, 0);
3108                         break;
3109                 case OP_GC_SAFE_POINT:
3110                         break;
3111
3112                 default:
3113                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3114                         g_assert_not_reached ();
3115                 }
3116
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 ();
3121                 }
3122                
3123                 cpos += max_len;
3124
3125                 last_ins = ins;
3126                 last_offset = offset;
3127         }
3128
3129         ia64_codegen_close (code);
3130
3131         cfg->code_len = code.buf - cfg->native_code;
3132 }
3133
3134 void
3135 mono_arch_register_lowlevel_calls (void)
3136 {
3137 }
3138
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},
3146         {0, 0, 0},
3147         {0, 0, 0},
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},
3160         {0, 0, 0},
3161         {0, 0, 0},
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},
3166         {0, 0, 0},
3167         {0, 0, 0},
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},
3170         {0, 0, 0},
3171         {0, 0, 0}
3172 };
3173
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 },
3183
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 },
3192
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 },
3201
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 }
3210 };
3211
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
3217 };
3218
3219 static guint64 nops_for_ins_types [6] = {
3220         IA64_NOP_I,
3221         IA64_NOP_I,
3222         IA64_NOP_M,
3223         IA64_NOP_F,
3224         IA64_NOP_B,
3225         IA64_NOP_X
3226 };
3227
3228 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3229
3230 /* 
3231  * Debugging support
3232  */
3233
3234 #if 0
3235 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3236 #else
3237 #define DEBUG_INS_SCHED(a)
3238 #endif
3239
3240 static void
3241 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3242 {
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;
3246
3247         for (i = 0; i < code->nins; ++i)
3248                 stops [i] = FALSE;
3249         
3250         ins_index = 0;
3251         current_deps_start = 0;
3252         current_ins_start = 0;
3253         deps_start [ins_index] = current_ins_start;
3254         pos = 0;
3255         no_stop = FALSE;
3256         DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3257         while (pos < code->dep_info_pos) {
3258                 need_stop = FALSE;
3259                 switch (deps [pos]) {
3260                 case IA64_END_OF_INS:
3261                         ins_index ++;
3262                         current_ins_start = pos + 2;
3263                         deps_start [ins_index] = current_ins_start;
3264                         no_stop = FALSE;
3265                         DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3266                         break;
3267                 case IA64_NONE:
3268                         break;
3269                 case IA64_READ_GR:
3270                         reg = deps [pos + 1];
3271
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)
3275                                         need_stop = TRUE;
3276                         break;
3277                 case IA64_WRITE_GR:
3278                         reg = code->dep_info [pos + 1];
3279
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)
3283                                         need_stop = TRUE;
3284                         break;
3285                 case IA64_READ_PR:
3286                         reg = deps [pos + 1];
3287
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)
3291                                         need_stop = TRUE;
3292                         break;
3293                 case IA64_READ_PR_BRANCH:
3294                         reg = deps [pos + 1];
3295
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)
3300                                         need_stop = TRUE;
3301                         break;
3302                 case IA64_WRITE_PR:
3303                         reg = code->dep_info [pos + 1];
3304
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)
3308                                         need_stop = TRUE;
3309                         break;
3310                 case IA64_WRITE_PR_FLOAT:
3311                         reg = code->dep_info [pos + 1];
3312
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)
3316                                         need_stop = TRUE;
3317                         break;
3318                 case IA64_READ_BR:
3319                         reg = deps [pos + 1];
3320
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)
3324                                         need_stop = TRUE;
3325                         break;
3326                 case IA64_WRITE_BR:
3327                         reg = code->dep_info [pos + 1];
3328
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)
3332                                         need_stop = TRUE;
3333                         break;
3334                 case IA64_READ_BR_BRANCH:
3335                         reg = deps [pos + 1];
3336
3337                         /* Writes to brs are visible to branches */
3338                         DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3339                         break;
3340                 case IA64_READ_FR:
3341                         reg = deps [pos + 1];
3342
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)
3346                                         need_stop = TRUE;
3347                         break;
3348                 case IA64_WRITE_FR:
3349                         reg = code->dep_info [pos + 1];
3350
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)
3354                                         need_stop = TRUE;
3355                         break;
3356                 case IA64_READ_AR:
3357                         reg = deps [pos + 1];
3358
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)
3362                                         need_stop = TRUE;
3363                         break;
3364                 case IA64_WRITE_AR:
3365                         reg = code->dep_info [pos + 1];
3366
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)
3370                                         need_stop = TRUE;
3371                         break;
3372                 case IA64_NO_STOP:
3373                         /* 
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.
3377                          */
3378                         no_stop = TRUE;
3379                         break;
3380                 default:
3381                         g_assert_not_reached ();
3382                 }
3383                 pos += 2;
3384
3385                 if (need_stop && !no_stop) {
3386                         g_assert (ins_index > 0);
3387                         stops [ins_index - 1] = 1;
3388
3389                         DEBUG_INS_SCHED (printf ("STOP\n"));
3390                         current_deps_start = current_ins_start;
3391
3392                         /* Skip remaining deps for this instruction */
3393                         while (deps [pos] != IA64_END_OF_INS)
3394                                 pos += 2;
3395                 }
3396         }
3397
3398         if (code->nins > 0) {
3399                 /* No dependency info for the last instruction */
3400                 stops [code->nins - 1] = 1;
3401         }
3402
3403         deps_start [code->nins] = code->dep_info_pos;
3404 }
3405
3406 static void
3407 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3408 {
3409         int stop_pos, i, deps_to_shift, dep_shift;
3410
3411         g_assert (n <= code->nins);
3412
3413         // if (n > 1) printf ("FOUND: %ld.\n", template);
3414
3415         ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3416
3417         stop_pos = last_stop_in_template [template] + 1;
3418         if (stop_pos > n)
3419                 stop_pos = n;
3420
3421         /* Compute the number of 'real' instructions before the stop */
3422         deps_to_shift = stop_pos;
3423         if (stop_pos >= 3 && (nops & (1 << 2)))
3424                 deps_to_shift --;
3425         if (stop_pos >= 2 && (nops & (1 << 1)))
3426                 deps_to_shift --;
3427         if (stop_pos >= 1 && (nops & (1 << 0)))
3428                 deps_to_shift --;
3429
3430         /* 
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
3433          * array.
3434          */
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;
3438
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];
3442
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;
3446
3447         /* Determine the exact positions of instructions with unwind ops */
3448         if (code->unw_op_count) {
3449                 int ins_pos [16];
3450                 int curr_ins, curr_ins_pos;
3451
3452                 curr_ins = 0;
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;
3457                                 curr_ins ++;
3458                         }
3459                 }
3460
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);
3465                         }
3466                 }
3467                 if (code->unw_op_pos < code->unw_op_count)
3468                         code->unw_op_pos += n;
3469         }
3470
3471         if (n == code->nins) {
3472                 code->template = 0;
3473                 code->nins = 0;
3474         }               
3475         else {
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));
3479                 code->nins -= n;
3480         }
3481 }
3482
3483 void
3484 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3485 {
3486         int i, ins_type, template, nins_to_emit;
3487         int deps_start [16];
3488         int stops [16];
3489         gboolean found;
3490
3491         /*
3492          * We implement a simple scheduler which tries to put three instructions 
3493          * per bundle, then two, then one.
3494          */
3495         ia64_analyze_deps (code, deps_start, stops);
3496
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])
3503                                 continue;
3504
3505                         found = TRUE;
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);
3511                                         break;
3512                                 default:
3513                                         found &= (ins_type == code->itypes [i]);
3514                                         break;
3515                                 }
3516                         }
3517
3518                         if (found)
3519                                 found = debug_ins_sched ();
3520
3521                         if (found) {
3522                                 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3523                                 break;
3524                         }
3525                 }
3526         }
3527
3528         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3529                 /* Wait for more instructions */
3530                 return;
3531
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])))
3539                                  
3540                                 continue;
3541
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]))
3544                                 continue;
3545
3546                         if (!debug_ins_sched ())
3547                                 continue;
3548
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);
3550                         break;
3551                 }
3552         }
3553
3554         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3555                 /* Wait for more instructions */
3556                 return;
3557
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])
3564                                 continue;
3565
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]))
3568                                 continue;
3569
3570                         if (!debug_ins_sched ())
3571                                 continue;
3572
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);
3574                         break;
3575                 }
3576         }
3577
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]))
3583                                 continue;
3584
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]))
3587                                 continue;
3588
3589                         if (!debug_ins_sched ())
3590                                 continue;
3591
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);
3593                         break;
3594                 }
3595         }
3596
3597         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3598                 /* Wait for more instructions */
3599                 return;
3600
3601         if (flush)
3602                 nins_to_emit = code->nins;
3603         else
3604                 nins_to_emit = 1;
3605
3606         while (nins_to_emit > 0) {
3607                 if (!debug_ins_sched ())
3608                         stops [0] = 1;
3609                 switch (code->itypes [0]) {
3610                 case IA64_INS_TYPE_A:
3611                         if (stops [0])
3612                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3613                         else
3614                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3615                         break;
3616                 case IA64_INS_TYPE_I:
3617                         if (stops [0])
3618                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3619                         else
3620                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3621                         break;
3622                 case IA64_INS_TYPE_M:
3623                         if (stops [0])
3624                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3625                         else
3626                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3627                         break;
3628                 case IA64_INS_TYPE_B:
3629                         if (stops [0])
3630                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3631                         else
3632                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3633                         break;
3634                 case IA64_INS_TYPE_F:
3635                         if (stops [0])
3636                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3637                         else
3638                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3639                         break;
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);
3643                         else
3644                                 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3645                         nins_to_emit --;
3646                         break;
3647                 default:
3648                         g_assert_not_reached ();
3649                 }
3650                 nins_to_emit --;
3651         }
3652 }
3653
3654 unw_dyn_region_info_t*
3655 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3656 {
3657         unw_dyn_region_info_t *r;
3658
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;
3667
3668         return r;
3669 }
3670
3671 static void 
3672 ia64_patch (unsigned char* code, gpointer target)
3673 {
3674         int template, i;
3675         guint64 instructions [3];
3676         guint8 gen_buf [16];
3677         Ia64CodegenState gen;
3678         int ins_to_skip;
3679         gboolean found;
3680
3681         /* 
3682          * code encodes both the position inside the buffer and code.nins when
3683          * the instruction was emitted.
3684          */
3685         ins_to_skip = (guint64)code % 16;
3686         code = (unsigned char*)((guint64)code & ~15);
3687
3688         /*
3689          * Search for the first instruction which is 'patchable', skipping
3690          * ins_to_skip instructions.
3691          */
3692
3693         while (TRUE) {
3694
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);
3699
3700         ia64_codegen_init (gen, gen_buf);
3701
3702         found = FALSE;
3703         for (i = 0; i < 3; ++i) {
3704                 guint64 ins = instructions [i];
3705                 int opcode = ia64_ins_opcode (ins);
3706
3707                 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3708                         continue;
3709
3710                 if (ins_to_skip) {
3711                         ins_to_skip --;
3712                         continue;
3713                 }
3714
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)) {
3719                                 /* adds */
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];
3722                                 found = TRUE;
3723                         }
3724                         else
3725                                 NOT_IMPLEMENTED;
3726                         break;
3727                 case IA64_INS_TYPE_B:
3728                         if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3729                                 /* br.cond */
3730                                 gint64 disp = ((guint8*)target - code) >> 4;
3731
3732                                 /* FIXME: hints */
3733                                 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3734                                 
3735                                 instructions [i] = gen.instructions [0];
3736                                 found = TRUE;
3737                         }
3738                         else if (opcode == 5) {
3739                                 /* br.call */
3740                                 gint64 disp = ((guint8*)target - code) >> 4;
3741
3742                                 /* FIXME: hints */
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];
3745                                 found = TRUE;
3746                         }
3747                         else
3748                                 NOT_IMPLEMENTED;
3749                         break;
3750                 case IA64_INS_TYPE_LX:
3751                         if (i == 1)
3752                                 break;
3753
3754                         if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3755                                 /* movl */
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];
3759                                 found = TRUE;
3760                         }
3761                         else
3762                                 NOT_IMPLEMENTED;
3763
3764                         break;
3765                 default:
3766                         NOT_IMPLEMENTED;
3767                 }
3768
3769                 if (found) {
3770                         /* Rewrite code */
3771                         ia64_codegen_init (gen, code);
3772                         ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3773                         return;
3774                 }
3775         }
3776
3777         code += 16;
3778         }
3779 }
3780
3781 void
3782 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
3783 {
3784         MonoJumpInfo *patch_info;
3785
3786         error_init (error);
3787
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;
3791
3792                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
3793                 return_if_nok (error);
3794
3795                 if (patch_info->type == MONO_PATCH_INFO_NONE)
3796                         continue;
3797                 if (mono_compile_aot) {
3798                         NOT_IMPLEMENTED;
3799                 }
3800
3801                 ia64_patch (ip, (gpointer)target);
3802         }
3803 }
3804
3805 guint8 *
3806 mono_arch_emit_prolog (MonoCompile *cfg)
3807 {
3808         MonoMethod *method = cfg->method;
3809         MonoMethodSignature *sig;
3810         MonoInst *inst;
3811         int alloc_size, pos, i;
3812         Ia64CodegenState code;
3813         CallInfo *cinfo;
3814         
3815         sig = mono_method_signature (method);
3816         pos = 0;
3817
3818         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
3819
3820         cfg->code_size =  MAX (cfg->header->code_size * 4, 512);
3821
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;
3826
3827         cfg->native_code = g_malloc (cfg->code_size);
3828
3829         ia64_codegen_init (code, cfg->native_code);
3830
3831         alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3832         if (cfg->param_area)
3833                 alloc_size += cfg->param_area;
3834         if (alloc_size)
3835                 /* scratch area */
3836                 alloc_size += 16;
3837         alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3838
3839         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3840                 /* Force sp to be saved/restored */
3841                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3842
3843         cfg->arch.stack_alloc_size = alloc_size;
3844
3845         pos = 0;
3846
3847         if (method->save_lmf) {
3848                 /* No LMF on IA64 */
3849         }
3850
3851         alloc_size -= pos;
3852
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);
3857
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);
3863         }
3864
3865         if (alloc_size) {
3866 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3867                 int pagesize = getpagesize ();
3868
3869                 if (alloc_size >= pagesize) {
3870                         gint32 remaining_size = alloc_size;
3871
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;
3879                         }
3880                 }
3881 #endif
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);
3886                 }
3887                 else {
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);
3892                 }
3893         }
3894
3895         ia64_begin_bundle (code);
3896
3897         /* Initialize unwind info */
3898         cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3899
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 */
3903                         NOT_IMPLEMENTED;
3904                 }
3905         }
3906
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;
3911                 MonoType *arg_type;
3912
3913                 inst = cfg->args [i];
3914
3915                 if (sig->hasthis && (i == 0))
3916                         arg_type = &mono_defaults.object_class->byval_arg;
3917                 else
3918                         arg_type = sig->params [i - sig->hasthis];
3919
3920                 arg_type = mini_get_underlying_type (arg_type);
3921
3922                 stack_offset = ainfo->offset + ARGS_OFFSET;
3923
3924                 /*
3925                  * FIXME: Native code might pass non register sized integers 
3926                  * without initializing the upper bits.
3927                  */
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;
3930
3931                         switch (mono_type_to_load_membase (cfg, arg_type)) {
3932                         case OP_LOADI1_MEMBASE:
3933                                 ia64_sxt1 (code, reg, reg);
3934                                 break;
3935                         case OP_LOADU1_MEMBASE:
3936                                 ia64_zxt1 (code, reg, reg);
3937                                 break;
3938                         case OP_LOADI2_MEMBASE:
3939                                 ia64_sxt2 (code, reg, reg);
3940                                 break;
3941                         case OP_LOADU2_MEMBASE:
3942                                 ia64_zxt2 (code, reg, reg);
3943                                 break;
3944                         default:
3945                                 break;
3946                         }
3947                 }
3948
3949                 /* Save volatile arguments to the stack */
3950                 if (inst->opcode != OP_REGVAR) {
3951                         switch (ainfo->storage) {
3952                         case ArgInIReg:
3953                         case ArgInFloatReg:
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);
3958                                 else {
3959                                         ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3960                                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3961                                 }
3962                                 if (arg_type->byref)
3963                                         ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3964                                 else {
3965                                         switch (arg_type->type) {
3966                                         case MONO_TYPE_R4:
3967                                                 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3968                                                 break;
3969                                         case MONO_TYPE_R8:
3970                                                 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3971                                                 break;
3972                                         default:
3973                                                 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3974                                                 break;
3975                                         }
3976                                 }
3977                                 break;
3978                         case ArgOnStack:
3979                                 break;
3980                         case ArgAggregate:
3981                                 if (ainfo->nslots != ainfo->nregs)
3982                                         NOT_IMPLEMENTED;
3983
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);
3990                                                 break;
3991                                         case AggregateSingleHFA:
3992                                                 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3993                                                 break;
3994                                         case AggregateDoubleHFA:
3995                                                 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3996                                                 break;
3997                                         default:
3998                                                 NOT_IMPLEMENTED;
3999                                         }
4000                                 }
4001                                 break;
4002                         default:
4003                                 g_assert_not_reached ();
4004                         }
4005                 }
4006
4007                 if (inst->opcode == OP_REGVAR) {
4008                         /* Argument allocated to (non-volatile) register */
4009                         switch (ainfo->storage) {
4010                         case ArgInIReg:
4011                                 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
4012                                         ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
4013                                 break;
4014                         case ArgOnStack:
4015                                 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
4016                                 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
4017                                 break;
4018                         default:
4019                                 NOT_IMPLEMENTED;
4020                         }
4021                 }
4022         }
4023
4024         if (method->save_lmf) {
4025                 /* No LMF on IA64 */
4026         }
4027
4028         ia64_codegen_close (code);
4029
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);
4032
4033         cfg->code_len = code.buf - cfg->native_code;
4034
4035         g_assert (cfg->code_len < cfg->code_size);
4036
4037         cfg->arch.prolog_end_offset = cfg->code_len;
4038
4039         return code.buf;
4040 }
4041
4042 void
4043 mono_arch_emit_epilog (MonoCompile *cfg)
4044 {
4045         MonoMethod *method = cfg->method;
4046         int i, pos;
4047         int max_epilog_size = 16 * 4;
4048         Ia64CodegenState code;
4049         guint8 *buf;
4050         CallInfo *cinfo;
4051         ArgInfo *ainfo;
4052
4053         if (mono_jit_trace_calls != NULL)
4054                 max_epilog_size += 1024;
4055
4056         cfg->arch.epilog_begin_offset = cfg->code_len;
4057
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++;
4062         }
4063
4064         /* FIXME: Emit unwind info */
4065
4066         buf = cfg->native_code + cfg->code_len;
4067
4068         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4069                 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4070
4071         ia64_codegen_init (code, buf);
4072
4073         /* the code restoring the registers must be kept in sync with OP_JMP */
4074         pos = 0;
4075         
4076         if (method->save_lmf) {
4077                 /* No LMF on IA64 */
4078         }
4079
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) {
4084         case ArgAggregate:
4085                 if (ainfo->nslots != ainfo->nregs)
4086                         NOT_IMPLEMENTED;
4087
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);
4094                                 break;
4095                         case AggregateSingleHFA:
4096                                 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4097                                 break;
4098                         case AggregateDoubleHFA:
4099                                 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4100                                 break;
4101                         default:
4102                                 g_assert_not_reached ();
4103                         }
4104                 }
4105                 break;
4106         default:
4107                 break;
4108         }
4109
4110         ia64_begin_bundle (code);
4111
4112         code.region_start = cfg->native_code;
4113
4114         /* Label the unwind state at the start of the exception throwing region */
4115         //ia64_unw_label_state (code, 1234);
4116
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);
4122                         } else {
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);
4126                         }
4127                 }
4128                 else {
4129                         ia64_unw_pop_frames (code, 1);
4130                         ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4131                 }
4132         }
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);
4136
4137         ia64_codegen_close (code);
4138
4139         cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4140         cfg->arch.r_pro->next = cfg->arch.r_epilog;
4141
4142         cfg->code_len = code.buf - cfg->native_code;
4143
4144         g_assert (cfg->code_len < cfg->code_size);
4145 }
4146
4147 void
4148 mono_arch_emit_exceptions (MonoCompile *cfg)
4149 {
4150         MonoJumpInfo *patch_info;
4151         int i, nthrows;
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;
4158
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)
4162                         code_size += 256;
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 */
4167         }
4168
4169         if (code_size == 0)
4170                 return;
4171
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++;
4176         }
4177
4178         ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4179
4180         /* The unwind state here is the same as before the epilog */
4181         //ia64_unw_copy_state (code, 1234);
4182
4183         /* add code to raise exceptions */
4184         /* FIXME: Optimize this */
4185         nthrows = 0;
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;
4190                         guint8* throw_ip;
4191                         guint8* buf;
4192                         guint64 exc_token_index;
4193
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;
4197
4198                         ia64_begin_bundle (code);
4199
4200                         ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4201
4202                         /* Find a throw sequence for the same exception class */
4203                         for (i = 0; i < nthrows; ++i)
4204                                 if (exc_classes [i] == exc_class)
4205                                         break;
4206
4207                         if (i < nthrows) {
4208                                 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4209
4210                                 if (ia64_is_adds_imm (offset))
4211                                         ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4212                                 else
4213                                         ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4214
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]);
4219
4220                                 patch_info->type = MONO_PATCH_INFO_NONE;
4221                         }
4222                         else {
4223                                 /* Arg1 */
4224                                 buf = code.buf;
4225                                 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4226
4227                                 ia64_begin_bundle (code);
4228
4229                                 if (nthrows < 16) {
4230                                         exc_classes [nthrows] = exc_class;
4231                                         exc_throw_start [nthrows] = code.buf;
4232                                 }
4233
4234                                 /* Arg2 */
4235                                 if (ia64_is_adds_imm (exc_token_index))
4236                                         ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4237                                 else
4238                                         ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4239
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;
4243
4244                                 /* Indirect call */
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);
4249
4250                                 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4251
4252                                 /* Patch up the throw offset */
4253                                 ia64_begin_bundle (code);
4254
4255                                 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4256
4257                                 if (nthrows < 16) {
4258                                         exc_throw_end [nthrows] = code.buf;
4259                                         nthrows ++;
4260                                 }
4261                         }
4262
4263                         empty = FALSE;
4264                         break;
4265                 }
4266                 default:
4267                         break;
4268                 }
4269         }
4270
4271         if (!empty)
4272                 /* The unwinder needs this to work */
4273                 ia64_break_i (code, 0);
4274
4275         ia64_codegen_close (code);
4276
4277         /* FIXME: */
4278         //r_exceptions = mono_ia64_create_unwind_region (&code);
4279         //cfg->arch.r_epilog = r_exceptions;
4280
4281         cfg->code_len = code.buf - cfg->native_code;
4282
4283         g_assert (cfg->code_len < cfg->code_size);
4284 }
4285
4286 void*
4287 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4288 {
4289         Ia64CodegenState code;
4290         CallInfo *cinfo = NULL;
4291         MonoMethodSignature *sig;
4292         MonoInst *ins;
4293         int i, n, stack_area = 0;
4294
4295         ia64_codegen_init (code, p);
4296
4297         /* Keep this in sync with mono_arch_get_argument_info */
4298
4299         if (enable_arguments) {
4300                 /* Allocate a new area on the stack and save arguments there */
4301                 sig = mono_method_signature (cfg->method);
4302
4303                 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4304
4305                 n = sig->param_count + sig->hasthis;
4306
4307                 stack_area = ALIGN_TO (n * 8, 16);
4308
4309                 if (n) {
4310                         ia64_movl (code, GP_SCRATCH_REG, stack_area);
4311
4312                         ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4313
4314                         /* FIXME: Allocate out registers */
4315
4316                         ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4317
4318                         /* Required by the ABI */
4319                         ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4320
4321                         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4322                         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4323
4324                         /* Save arguments to the stack */
4325                         for (i = 0; i < n; ++i) {
4326                                 ins = cfg->args [i];
4327
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);
4332                                 }
4333                                 else {
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);
4340                                 }
4341                         }
4342                 }
4343                 else
4344                         ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4345         }
4346         else
4347                 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4348
4349         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4350         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4351
4352         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4353
4354         if (enable_arguments && stack_area) {
4355                 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4356
4357                 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4358
4359                 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4360         }
4361
4362         ia64_codegen_close (code);
4363
4364         return code.buf;
4365 }
4366
4367 void*
4368 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
4369 {
4370         Ia64CodegenState code;
4371         CallInfo *cinfo = NULL;
4372         MonoMethod *method = cfg->method;
4373         MonoMethodSignature *sig = mono_method_signature (cfg->method);
4374
4375         ia64_codegen_init (code, p);
4376
4377         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4378
4379         /* Save return value + pass it to func */
4380         switch (cinfo->ret.storage) {
4381         case ArgNone:
4382                 break;
4383         case ArgInIReg:
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);
4386                 break;
4387         case ArgInFloatReg:
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);
4392                 break;
4393         case ArgValuetypeAddrInIReg:
4394                 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4395                 break;
4396         case ArgAggregate:
4397                 NOT_IMPLEMENTED;
4398                 break;
4399         default:
4400                 break;
4401         }
4402
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);
4406
4407         /* Restore return value */
4408         switch (cinfo->ret.storage) {
4409         case ArgNone:
4410                 break;
4411         case ArgInIReg:
4412                 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4413                 break;
4414         case ArgInFloatReg:
4415                 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4416                 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4417                 break;
4418         case ArgValuetypeAddrInIReg:
4419                 break;
4420         case ArgAggregate:
4421                 break;
4422         default:
4423                 break;
4424         }
4425
4426         ia64_codegen_close (code);
4427
4428         return code.buf;
4429 }
4430
4431 void
4432 mono_arch_save_unwind_info (MonoCompile *cfg)
4433 {
4434         unw_dyn_info_t *di;
4435
4436         /* FIXME: Unregister this for dynamic methods */
4437
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;
4441         di->gp = 0;
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;
4445
4446         _U_dyn_register (di);
4447
4448         /*
4449         {
4450                 unw_dyn_region_info_t *region = di->u.pi.regions;
4451
4452                 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4453                 while (region) {
4454                         printf ("    [Region: %d]\n", region->insn_count);
4455                         region = region->next;
4456                 }
4457         }
4458         */
4459 }
4460
4461 void
4462 mono_arch_flush_icache (guint8 *code, gint size)
4463 {
4464         guint8* p = (guint8*)((guint64)code & ~(0x3f));
4465         guint8* end = (guint8*)((guint64)code + size);
4466
4467 #ifdef __INTEL_COMPILER
4468         /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4469         while (p < end) {
4470                 __fc ((guint64)p);
4471                 p += 32;
4472         }
4473 #else
4474         while (p < end) {
4475                 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4476                 /* FIXME: This could be increased to 128 on some cpus */
4477                 p += 32;
4478         }
4479 #endif
4480 }
4481
4482 void
4483 mono_arch_flush_register_windows (void)
4484 {
4485         /* Not needed because of libunwind */
4486 }
4487
4488 gboolean 
4489 mono_arch_is_inst_imm (gint64 imm)
4490 {
4491         /* The lowering pass will take care of it */
4492
4493         return TRUE;
4494 }
4495
4496 /*
4497  * Determine whenever the trap whose info is in SIGINFO is caused by
4498  * integer overflow.
4499  */
4500 gboolean
4501 mono_arch_is_int_overflow (void *sigctx, void *info)
4502 {
4503         /* Division is emulated with explicit overflow checks */
4504         return FALSE;
4505 }
4506
4507 guint32
4508 mono_arch_get_patch_offset (guint8 *code)
4509 {
4510         NOT_IMPLEMENTED;
4511
4512         return 0;
4513 }
4514
4515 gpointer*
4516 mono_arch_get_delegate_method_ptr_addr (guint8* code, mgreg_t *regs)
4517 {
4518         NOT_IMPLEMENTED;
4519
4520         return NULL;
4521 }
4522
4523 void
4524 mono_arch_finish_init (void)
4525 {
4526 }
4527
4528 void
4529 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4530 {
4531 }
4532
4533 /*
4534  * LOCKING: called with the domain lock held
4535  */
4536 gpointer
4537 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4538                                                                 gpointer fail_tramp)
4539 {
4540         int i;
4541         int size = 0;
4542         guint8 *start, *buf;
4543         Ia64CodegenState code;
4544
4545         size = count * 256;
4546         buf = g_malloc0 (size);
4547         ia64_codegen_init (code, buf);
4548
4549         /* IA64_R9 contains the IMT method */
4550
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;
4557
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);
4562                                 }
4563                                 item->jmp_code = (guint8*)code.buf + code.nins;
4564                                 ia64_br_cond_pred (code, 7, 0);
4565
4566                                 if (item->has_target_code) {
4567                                         ia64_movl (code, GP_SCRATCH_REG, item->value.target_code);
4568                                 } else {
4569                                         ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->value.vtable_slot]));
4570                                         ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4571                                 }
4572                                 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4573                                 ia64_br_cond_reg (code, IA64_B6);
4574
4575                                 if (fail_case) {
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;
4582                                 }
4583                         } else {
4584                                 /* enable the commented code to assert on wrong method */
4585 #if ENABLE_WRONG_METHOD_CHECK
4586                                 g_assert_not_reached ();
4587 #endif
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 ();
4594 #endif
4595                         }
4596                 } else {
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);
4601                 }
4602         }
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);
4609                         }
4610                 }
4611         }
4612
4613         ia64_codegen_close (code);
4614         g_assert (code.buf - buf <= size);
4615
4616         size = code.buf - buf;
4617         if (fail_tramp) {
4618                 start = mono_method_alloc_generic_virtual_trampoline (domain, size + 16);
4619                 start = (gpointer)ALIGN_TO (start, 16);
4620         } else {
4621                 start = mono_domain_code_reserve (domain, size);
4622         }
4623         memcpy (start, buf, size);
4624
4625         mono_arch_flush_icache (start, size);
4626
4627         mono_stats.imt_thunks_size += size;
4628
4629         mono_tramp_info_register (mono_tramp_info_create (NULL, start, size, NULL, NULL), domain);
4630
4631         return start;
4632 }
4633
4634 MonoMethod*
4635 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
4636 {
4637         return (MonoMethod*)regs [IA64_R9];
4638 }
4639
4640 gpointer
4641 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
4642 {
4643         return (gpointer)regs [IA64_R10];
4644 }
4645
4646 gpointer
4647 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
4648 {
4649         return NULL;
4650 }
4651
4652 gpointer
4653 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
4654 {
4655         return NULL;
4656 }
4657
4658 MonoInst*
4659 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4660 {
4661         MonoInst *ins = NULL;
4662
4663         if (cmethod->klass->image == mono_defaults.corlib &&
4664                 (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4665                 (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4666
4667                 /* 
4668                  * We don't use the generic version in mini_emit_inst_for_method () since we
4669                  * ia64 has atomic_add_imm opcodes.
4670                  */
4671                 if (strcmp (cmethod->name, "Increment") == 0) {
4672                         guint32 opcode;
4673
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;
4678                         else
4679                                 g_assert_not_reached ();
4680                         MONO_INST_NEW (cfg, ins, opcode);
4681                         ins->dreg = mono_alloc_preg (cfg);
4682                         ins->inst_imm = 1;
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) {
4687                         guint32 opcode;
4688
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;
4693                         else
4694                                 g_assert_not_reached ();
4695                         MONO_INST_NEW (cfg, ins, opcode);
4696                         ins->dreg = mono_alloc_preg (cfg);
4697                         ins->inst_imm = -1;
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) {
4702                         guint32 opcode;
4703                         gboolean is_imm = FALSE;
4704                         gint64 imm = 0;
4705
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;
4708
4709                                 is_imm = (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
4710                         }
4711
4712                         if (is_imm) {
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;
4717                                 else
4718                                         g_assert_not_reached ();
4719
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;
4726                         } else {
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;
4731                                 else
4732                                         g_assert_not_reached ();
4733
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;
4740                         }
4741                         MONO_ADD_INS (cfg->cbb, ins);
4742                 }
4743         }
4744
4745         return ins;
4746 }
4747
4748 gboolean
4749 mono_arch_print_tree (MonoInst *tree, int arity)
4750 {
4751         return 0;
4752 }
4753
4754 mgreg_t
4755 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4756 {
4757         /* FIXME: implement */
4758         g_assert_not_reached ();
4759 }
4760
4761 gboolean
4762 mono_arch_opcode_supported (int opcode)
4763 {
4764         switch (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:
4769                 return TRUE;
4770         default:
4771                 return FALSE;
4772         }
4773 }