2007-11-28 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-ia64.c
1 /*
2  * mini-ia64.c: IA64 backend for the Mono code generator
3  *
4  * Authors:
5  *   Zoltan Varga (vargaz@gmail.com)
6  *
7  * (C) 2003 Ximian, Inc.
8  */
9 #include "mini.h"
10 #include <string.h>
11 #include <math.h>
12 #include <unistd.h>
13 #include <sys/mman.h>
14
15 #ifdef __INTEL_COMPILER
16 #include <ia64intrin.h>
17 #endif
18
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/utils/mono-math.h>
24
25 #include "trace.h"
26 #include "mini-ia64.h"
27 #include "inssel.h"
28 #include "cpu-ia64.h"
29
30 static gint appdomain_tls_offset = -1;
31 static gint thread_tls_offset = -1;
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 #define NOT_IMPLEMENTED g_assert_not_reached ()
65
66 static const char* gregs [] = {
67         "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
68         "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
69         "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
70         "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
71         "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
72         "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
73         "r60", "r61", "r62", "r63", "r64", "r65", "r66", "r67", "r68", "r69",
74         "r70", "r71", "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
75         "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", "r88", "r89",
76         "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97", "r98", "r99",
77         "r100", "r101", "r102", "r103", "r104", "r105", "r106", "r107", "r108", "r109",
78         "r110", "r111", "r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
79         "r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127"
80 };
81
82 const char*
83 mono_arch_regname (int reg)
84 {
85         if (reg < 128)
86                 return gregs [reg];
87         else
88                 return "unknown";
89 }
90
91 static const char* fregs [] = {
92         "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
93         "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
94         "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29",
95         "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
96         "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49",
97         "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59",
98         "f60", "f61", "f62", "f63", "f64", "f65", "f66", "f67", "f68", "f69",
99         "f70", "f71", "f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
100         "f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87", "f88", "f89",
101         "f90", "f91", "f92", "f93", "f94", "f95", "f96", "f97", "f98", "f99",
102         "f100", "f101", "f102", "f103", "f104", "f105", "f106", "f107", "f108", "f109",
103         "f110", "f111", "f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
104         "f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127"
105 };
106
107 const char*
108 mono_arch_fregname (int reg)
109 {
110         if (reg < 128)
111                 return fregs [reg];
112         else
113                 return "unknown";
114 }
115
116 G_GNUC_UNUSED static void
117 break_count (void)
118 {
119 }
120
121 G_GNUC_UNUSED static gboolean
122 debug_count (void)
123 {
124         static int count = 0;
125         count ++;
126
127         if (count == atoi (getenv ("COUNT"))) {
128                 break_count ();
129         }
130
131         if (count > atoi (getenv ("COUNT"))) {
132                 return FALSE;
133         }
134
135         return TRUE;
136 }
137
138 static gboolean
139 debug_ins_sched (void)
140 {
141 #if 0
142         return debug_count ();
143 #else
144         return TRUE;
145 #endif
146 }
147
148 static gboolean
149 debug_omit_fp (void)
150 {
151 #if 0
152         return debug_count ();
153 #else
154         return TRUE;
155 #endif
156 }
157
158 static void 
159 ia64_patch (unsigned char* code, gpointer target);
160
161 typedef enum {
162         ArgInIReg,
163         ArgInFloatReg,
164         ArgOnStack,
165         ArgValuetypeAddrInIReg,
166         ArgAggregate,
167         ArgSingleHFA,
168         ArgDoubleHFA,
169         ArgNone
170 } ArgStorage;
171
172 typedef enum {
173         AggregateNormal,
174         AggregateSingleHFA,
175         AggregateDoubleHFA
176 } AggregateType;
177
178 typedef struct {
179         gint16 offset;
180         gint8  reg;
181         ArgStorage storage;
182
183         /* Only if storage == ArgAggregate */
184         int nregs, nslots;
185         AggregateType atype;
186 } ArgInfo;
187
188 typedef struct {
189         int nargs;
190         guint32 stack_usage;
191         guint32 reg_usage;
192         guint32 freg_usage;
193         gboolean need_stack_align;
194         ArgInfo ret;
195         ArgInfo sig_cookie;
196         ArgInfo args [1];
197 } CallInfo;
198
199 #define DEBUG(a) if (cfg->verbose_level > 1) a
200
201 #define NEW_ICONST(cfg,dest,val) do {   \
202                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
203                 (dest)->opcode = OP_ICONST;     \
204                 (dest)->inst_c0 = (val);        \
205                 (dest)->type = STACK_I4;        \
206         } while (0)
207
208 #define PARAM_REGS 8
209
210 static void inline
211 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
212 {
213     ainfo->offset = *stack_size;
214
215     if (*gr >= PARAM_REGS) {
216                 ainfo->storage = ArgOnStack;
217                 (*stack_size) += sizeof (gpointer);
218     }
219     else {
220                 ainfo->storage = ArgInIReg;
221                 ainfo->reg = *gr;
222                 *(gr) += 1;
223     }
224 }
225
226 #define FLOAT_PARAM_REGS 8
227
228 static void inline
229 add_float (guint32 *gr, guint32 *fr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
230 {
231     ainfo->offset = *stack_size;
232
233     if (*gr >= PARAM_REGS) {
234                 ainfo->storage = ArgOnStack;
235                 (*stack_size) += sizeof (gpointer);
236     }
237     else {
238                 ainfo->storage = ArgInFloatReg;
239                 ainfo->reg = 8 + *fr;
240                 (*fr) += 1;
241                 (*gr) += 1;
242     }
243 }
244
245 static void
246 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
247                gboolean is_return,
248                guint32 *gr, guint32 *fr, guint32 *stack_size)
249 {
250         guint32 size, i;
251         MonoClass *klass;
252         MonoMarshalType *info;
253         gboolean is_hfa = TRUE;
254         guint32 hfa_type = 0;
255
256         klass = mono_class_from_mono_type (type);
257         if (type->type == MONO_TYPE_TYPEDBYREF)
258                 size = 3 * sizeof (gpointer);
259         else if (sig->pinvoke) 
260                 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
261         else 
262                 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
263
264         if (!sig->pinvoke || (size == 0)) {
265                 /* Allways pass in memory */
266                 ainfo->offset = *stack_size;
267                 *stack_size += ALIGN_TO (size, 8);
268                 ainfo->storage = ArgOnStack;
269
270                 return;
271         }
272
273         /* Determine whenever it is a HFA (Homogeneous Floating Point Aggregate) */
274         info = mono_marshal_load_type_info (klass);
275         g_assert (info);
276         for (i = 0; i < info->num_fields; ++i) {
277                 guint32 ftype = info->fields [i].field->type->type;
278                 if (!(info->fields [i].field->type->byref) && 
279                         ((ftype == MONO_TYPE_R4) || (ftype == MONO_TYPE_R8))) {
280                         if (hfa_type == 0)
281                                 hfa_type = ftype;
282                         else if (hfa_type != ftype)
283                                 is_hfa = FALSE;
284                 }
285                 else
286                         is_hfa = FALSE;
287         }
288         if (hfa_type == 0)
289                 is_hfa = FALSE;
290
291         ainfo->storage = ArgAggregate;
292         ainfo->atype = AggregateNormal;
293
294         if (is_hfa) {
295                 ainfo->atype = hfa_type == MONO_TYPE_R4 ? AggregateSingleHFA : AggregateDoubleHFA;
296                 if (is_return) {
297                         if (info->num_fields <= 8) {
298                                 ainfo->reg = 8;
299                                 ainfo->nregs = info->num_fields;
300                                 ainfo->nslots = ainfo->nregs;
301                                 return;
302                         }
303                         /* Fall through */
304                 }
305                 else {
306                         if ((*fr) + info->num_fields > 8)
307                                 NOT_IMPLEMENTED;
308
309                         ainfo->reg = 8 + (*fr);
310                         ainfo->nregs = info->num_fields;
311                         ainfo->nslots = ainfo->nregs;
312                         (*fr) += info->num_fields;
313                         return;
314                 }
315         }
316
317         /* This also handles returning of TypedByRef used by some icalls */
318         if (is_return) {
319                 if (size <= 32) {
320                         ainfo->reg = IA64_R8;
321                         ainfo->nregs = (size + 7) / 8;
322                         ainfo->nslots = ainfo->nregs;
323                         return;
324                 }
325                 NOT_IMPLEMENTED;
326         }
327
328         ainfo->reg = (*gr);
329         ainfo->offset = *stack_size;
330         ainfo->nslots = (size + 7) / 8;
331
332         if (((*gr) + ainfo->nslots) <= 8) {
333                 /* Fits entirely in registers */
334                 ainfo->nregs = ainfo->nslots;
335                 (*gr) += ainfo->nregs;
336                 return;
337         }
338
339         ainfo->nregs = 8 - (*gr);
340         (*gr) = 8;
341         (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
342 }
343
344 /*
345  * get_call_info:
346  *
347  *  Obtain information about a call according to the calling convention.
348  * For IA64, see the "Itanium Software Conventions and Runtime Architecture
349  * Gude" document for more information.
350  */
351 static CallInfo*
352 get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
353 {
354         guint32 i, gr, fr;
355         MonoType *ret_type;
356         int n = sig->hasthis + sig->param_count;
357         guint32 stack_size = 0;
358         CallInfo *cinfo;
359         MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
360
361         if (mp)
362                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
363         else
364                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
365
366         gr = 0;
367         fr = 0;
368
369         /* return value */
370         {
371                 ret_type = mono_type_get_underlying_type (sig->ret);
372                 ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
373                 switch (ret_type->type) {
374                 case MONO_TYPE_BOOLEAN:
375                 case MONO_TYPE_I1:
376                 case MONO_TYPE_U1:
377                 case MONO_TYPE_I2:
378                 case MONO_TYPE_U2:
379                 case MONO_TYPE_CHAR:
380                 case MONO_TYPE_I4:
381                 case MONO_TYPE_U4:
382                 case MONO_TYPE_I:
383                 case MONO_TYPE_U:
384                 case MONO_TYPE_PTR:
385                 case MONO_TYPE_FNPTR:
386                 case MONO_TYPE_CLASS:
387                 case MONO_TYPE_OBJECT:
388                 case MONO_TYPE_SZARRAY:
389                 case MONO_TYPE_ARRAY:
390                 case MONO_TYPE_STRING:
391                         cinfo->ret.storage = ArgInIReg;
392                         cinfo->ret.reg = IA64_R8;
393                         break;
394                 case MONO_TYPE_U8:
395                 case MONO_TYPE_I8:
396                         cinfo->ret.storage = ArgInIReg;
397                         cinfo->ret.reg = IA64_R8;
398                         break;
399                 case MONO_TYPE_R4:
400                 case MONO_TYPE_R8:
401                         cinfo->ret.storage = ArgInFloatReg;
402                         cinfo->ret.reg = 8;
403                         break;
404                 case MONO_TYPE_GENERICINST:
405                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
406                                 cinfo->ret.storage = ArgInIReg;
407                                 cinfo->ret.reg = IA64_R8;
408                                 break;
409                         }
410                         /* Fall through */
411                 case MONO_TYPE_VALUETYPE:
412                 case MONO_TYPE_TYPEDBYREF: {
413                         guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
414
415                         add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
416                         if (cinfo->ret.storage == ArgOnStack)
417                                 /* The caller passes the address where the value is stored */
418                                 add_general (&gr, &stack_size, &cinfo->ret);
419                         if (cinfo->ret.storage == ArgInIReg)
420                                 cinfo->ret.storage = ArgValuetypeAddrInIReg;
421                         break;
422                 }
423                 case MONO_TYPE_VOID:
424                         cinfo->ret.storage = ArgNone;
425                         break;
426                 default:
427                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
428                 }
429         }
430
431         /* this */
432         if (sig->hasthis)
433                 add_general (&gr, &stack_size, cinfo->args + 0);
434
435         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
436                 gr = PARAM_REGS;
437                 fr = FLOAT_PARAM_REGS;
438                 
439                 /* Emit the signature cookie just before the implicit arguments */
440                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
441         }
442
443         for (i = 0; i < sig->param_count; ++i) {
444                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
445                 MonoType *ptype;
446
447                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
448                         /* We allways pass the sig cookie on the stack for simplicity */
449                         /* 
450                          * Prevent implicit arguments + the sig cookie from being passed 
451                          * in registers.
452                          */
453                         gr = PARAM_REGS;
454                         fr = FLOAT_PARAM_REGS;
455
456                         /* Emit the signature cookie just before the implicit arguments */
457                         add_general (&gr, &stack_size, &cinfo->sig_cookie);
458                 }
459
460                 if (sig->params [i]->byref) {
461                         add_general (&gr, &stack_size, ainfo);
462                         continue;
463                 }
464                 ptype = mono_type_get_underlying_type (sig->params [i]);
465                 ptype = mini_get_basic_type_from_generic (gsctx, ptype);
466                 switch (ptype->type) {
467                 case MONO_TYPE_BOOLEAN:
468                 case MONO_TYPE_I1:
469                 case MONO_TYPE_U1:
470                         add_general (&gr, &stack_size, ainfo);
471                         break;
472                 case MONO_TYPE_I2:
473                 case MONO_TYPE_U2:
474                 case MONO_TYPE_CHAR:
475                         add_general (&gr, &stack_size, ainfo);
476                         break;
477                 case MONO_TYPE_I4:
478                 case MONO_TYPE_U4:
479                         add_general (&gr, &stack_size, ainfo);
480                         break;
481                 case MONO_TYPE_I:
482                 case MONO_TYPE_U:
483                 case MONO_TYPE_PTR:
484                 case MONO_TYPE_FNPTR:
485                 case MONO_TYPE_CLASS:
486                 case MONO_TYPE_OBJECT:
487                 case MONO_TYPE_STRING:
488                 case MONO_TYPE_SZARRAY:
489                 case MONO_TYPE_ARRAY:
490                         add_general (&gr, &stack_size, ainfo);
491                         break;
492                 case MONO_TYPE_GENERICINST:
493                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
494                                 add_general (&gr, &stack_size, ainfo);
495                                 break;
496                         }
497                         /* Fall through */
498                 case MONO_TYPE_VALUETYPE:
499                 case MONO_TYPE_TYPEDBYREF:
500                         /* FIXME: */
501                         /* We allways pass valuetypes on the stack */
502                         add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
503                         break;
504                 case MONO_TYPE_U8:
505                 case MONO_TYPE_I8:
506                         add_general (&gr, &stack_size, ainfo);
507                         break;
508                 case MONO_TYPE_R4:
509                         add_float (&gr, &fr, &stack_size, ainfo, FALSE);
510                         break;
511                 case MONO_TYPE_R8:
512                         add_float (&gr, &fr, &stack_size, ainfo, TRUE);
513                         break;
514                 default:
515                         g_assert_not_reached ();
516                 }
517         }
518
519         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
520                 gr = PARAM_REGS;
521                 fr = FLOAT_PARAM_REGS;
522                 
523                 /* Emit the signature cookie just before the implicit arguments */
524                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
525         }
526
527         cinfo->stack_usage = stack_size;
528         cinfo->reg_usage = gr;
529         cinfo->freg_usage = fr;
530         return cinfo;
531 }
532
533 /*
534  * mono_arch_get_argument_info:
535  * @csig:  a method signature
536  * @param_count: the number of parameters to consider
537  * @arg_info: an array to store the result infos
538  *
539  * Gathers information on parameters such as size, alignment and
540  * padding. arg_info should be large enought to hold param_count + 1 entries. 
541  *
542  * Returns the size of the argument area on the stack.
543  */
544 int
545 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
546 {
547         int k;
548         CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
549         guint32 args_size = cinfo->stack_usage;
550
551         /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
552         if (csig->hasthis) {
553                 arg_info [0].offset = 0;
554         }
555
556         for (k = 0; k < param_count; k++) {
557                 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
558                 /* FIXME: */
559                 arg_info [k + 1].size = 0;
560         }
561
562         g_free (cinfo);
563
564         return args_size;
565 }
566
567 /*
568  * Initialize the cpu to execute managed code.
569  */
570 void
571 mono_arch_cpu_init (void)
572 {
573 }
574
575 /*
576  * Initialize architecture specific code.
577  */
578 void
579 mono_arch_init (void)
580 {
581 }
582
583 /*
584  * Cleanup architecture specific code.
585  */
586 void
587 mono_arch_cleanup (void)
588 {
589 }
590
591 /*
592  * This function returns the optimizations supported on this cpu.
593  */
594 guint32
595 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
596 {
597         *exclude_mask = 0;
598
599         return 0;
600 }
601
602 static void
603 mono_arch_break (void)
604 {
605 }
606
607 GList *
608 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
609 {
610         GList *vars = NULL;
611         int i;
612         MonoMethodSignature *sig;
613         MonoMethodHeader *header;
614         CallInfo *cinfo;
615
616         header = mono_method_get_header (cfg->method);
617
618         sig = mono_method_signature (cfg->method);
619
620         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
621
622         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
623                 MonoInst *ins = cfg->args [i];
624
625                 ArgInfo *ainfo = &cinfo->args [i];
626
627                 if (ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
628                         continue;
629
630                 if (ainfo->storage == ArgInIReg) {
631                         /* The input registers are non-volatile */
632                         ins->opcode = OP_REGVAR;
633                         ins->dreg = 32 + ainfo->reg;
634                 }
635         }
636
637         for (i = 0; i < cfg->num_varinfo; i++) {
638                 MonoInst *ins = cfg->varinfo [i];
639                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
640
641                 /* unused vars */
642                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
643                         continue;
644
645                 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || 
646                     (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
647                         continue;
648
649                 if (mono_is_regsize_var (ins->inst_vtype)) {
650                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
651                         g_assert (i == vmv->idx);
652                         vars = g_list_prepend (vars, vmv);
653                 }
654         }
655
656         vars = mono_varlist_sort (cfg, vars, 0);
657
658         return vars;
659 }
660
661 static void
662 mono_ia64_alloc_stacked_registers (MonoCompile *cfg)
663 {
664         CallInfo *cinfo;
665         guint32 reserved_regs;
666         MonoMethodHeader *header;
667
668         if (cfg->arch.reg_local0 > 0)
669                 /* Already done */
670                 return;
671
672         cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (cfg->method), FALSE);
673
674         header = mono_method_get_header (cfg->method);
675         
676         /* Some registers are reserved for use by the prolog/epilog */
677         reserved_regs = header->num_clauses ? 4 : 3;
678
679         if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
680                 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
681                 /* One registers is needed by instrument_epilog to save the return value */
682                 reserved_regs ++;
683                 if (cinfo->reg_usage < 2)
684                         /* Number of arguments passed to function call in instrument_prolog */
685                         cinfo->reg_usage = 2;
686         }
687
688         cfg->arch.reg_in0 = 32;
689         cfg->arch.reg_local0 = cfg->arch.reg_in0 + cinfo->reg_usage + reserved_regs;
690         cfg->arch.reg_out0 = cfg->arch.reg_local0 + 16;
691
692         cfg->arch.reg_saved_ar_pfs = cfg->arch.reg_local0 - 1;
693         cfg->arch.reg_saved_b0 = cfg->arch.reg_local0 - 2;
694         cfg->arch.reg_fp = cfg->arch.reg_local0 - 3;
695
696         /* 
697          * Frames without handlers save sp to fp, frames with handlers save it into
698          * a dedicated register.
699          */
700         if (header->num_clauses)
701                 cfg->arch.reg_saved_sp = cfg->arch.reg_local0 - 4;
702         else
703                 cfg->arch.reg_saved_sp = cfg->arch.reg_fp;
704
705         if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
706                 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) {
707                 cfg->arch.reg_saved_return_val = cfg->arch.reg_local0 - reserved_regs;
708         }
709
710         /* 
711          * Need to allocate at least 2 out register for use by OP_THROW / the system
712          * exception throwing code.
713          */
714         cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, 2);
715 }
716
717 GList *
718 mono_arch_get_global_int_regs (MonoCompile *cfg)
719 {
720         GList *regs = NULL;
721         int i;
722
723         mono_ia64_alloc_stacked_registers (cfg);
724
725         for (i = cfg->arch.reg_local0; i < cfg->arch.reg_out0; ++i) {
726                 /* FIXME: regmask */
727                 g_assert (i < 64);
728                 regs = g_list_prepend (regs, (gpointer)(gssize)(i));
729         }
730
731         return regs;
732 }
733
734 /*
735  * mono_arch_regalloc_cost:
736  *
737  *  Return the cost, in number of memory references, of the action of 
738  * allocating the variable VMV into a register during global register
739  * allocation.
740  */
741 guint32
742 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
743 {
744         /* FIXME: Increase costs linearly to avoid using all local registers */
745
746         return 0;
747 }
748  
749 void
750 mono_arch_allocate_vars (MonoCompile *cfg)
751 {
752         MonoMethodSignature *sig;
753         MonoMethodHeader *header;
754         MonoInst *inst;
755         int i, offset;
756         guint32 locals_stack_size, locals_stack_align;
757         gint32 *offsets;
758         CallInfo *cinfo;
759
760         header = mono_method_get_header (cfg->method);
761
762         sig = mono_method_signature (cfg->method);
763
764         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
765
766         /*
767          * Determine whenever the frame pointer can be eliminated.
768          * FIXME: Remove some of the restrictions.
769          */
770         cfg->arch.omit_fp = TRUE;
771
772         if (!debug_omit_fp ())
773                 cfg->arch.omit_fp = FALSE;
774
775         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
776                 cfg->arch.omit_fp = FALSE;
777         if (header->num_clauses)
778                 cfg->arch.omit_fp = FALSE;
779         if (cfg->param_area)
780                 cfg->arch.omit_fp = FALSE;
781         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
782                 ArgInfo *ainfo = &cinfo->args [i];
783
784                 if (ainfo->storage == ArgOnStack) {
785                         /* 
786                          * The stack offset can only be determined when the frame
787                          * size is known.
788                          */
789                         cfg->arch.omit_fp = FALSE;
790                 }
791         }
792
793         mono_ia64_alloc_stacked_registers (cfg);
794
795         /*
796          * We use the ABI calling conventions for managed code as well.
797          * Exception: valuetypes are never passed or returned in registers.
798          */
799
800         if (cfg->arch.omit_fp) {
801                 cfg->frame_reg = IA64_SP;
802                 offset = ARGS_OFFSET;
803         }
804         else {
805                 /* Locals are allocated backwards from %fp */
806                 cfg->frame_reg = cfg->arch.reg_fp;
807                 offset = 0;
808         }
809
810         if (cfg->method->save_lmf) {
811                 /* No LMF on IA64 */
812         }
813
814         if (sig->ret->type != MONO_TYPE_VOID) {
815                 switch (cinfo->ret.storage) {
816                 case ArgInIReg:
817                         cfg->ret->opcode = OP_REGVAR;
818                         cfg->ret->inst_c0 = cinfo->ret.reg;
819                         break;
820                 case ArgInFloatReg:
821                         cfg->ret->opcode = OP_REGVAR;
822                         cfg->ret->inst_c0 = cinfo->ret.reg;
823                         break;
824                 case ArgValuetypeAddrInIReg:
825                         cfg->ret->opcode = OP_REGVAR;
826                         cfg->ret->inst_c0 = cfg->arch.reg_in0 + cinfo->ret.reg;
827                         break;
828                 case ArgAggregate:
829                         /* Allocate a local to hold the result, the epilog will copy it to the correct place */
830                         if (cfg->arch.omit_fp)
831                                 g_assert_not_reached ();
832                         offset = ALIGN_TO (offset, 8);
833                         offset += cinfo->ret.nslots * 8;
834                         cfg->ret->opcode = OP_REGOFFSET;
835                         cfg->ret->inst_basereg = cfg->frame_reg;
836                         cfg->ret->inst_offset = - offset;
837                         break;
838                 default:
839                         g_assert_not_reached ();
840                 }
841                 cfg->ret->dreg = cfg->ret->inst_c0;
842         }
843
844         /* Allocate locals */
845         offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE : TRUE, &locals_stack_size, &locals_stack_align);
846         if (locals_stack_align) {
847                 offset = ALIGN_TO (offset, locals_stack_align);
848         }
849         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
850                 if (offsets [i] != -1) {
851                         MonoInst *inst = cfg->varinfo [i];
852                         inst->opcode = OP_REGOFFSET;
853                         inst->inst_basereg = cfg->frame_reg;
854                         if (cfg->arch.omit_fp)
855                                 inst->inst_offset = (offset + offsets [i]);
856                         else
857                                 inst->inst_offset = - (offset + offsets [i]);
858                         // printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
859                 }
860         }
861         offset += locals_stack_size;
862
863         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
864                 if (cfg->arch.omit_fp)
865                         g_assert_not_reached ();
866                 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
867                 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
868         }
869
870         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
871                 inst = cfg->args [i];
872                 if (inst->opcode != OP_REGVAR) {
873                         ArgInfo *ainfo = &cinfo->args [i];
874                         gboolean inreg = TRUE;
875                         MonoType *arg_type;
876
877                         if (sig->hasthis && (i == 0))
878                                 arg_type = &mono_defaults.object_class->byval_arg;
879                         else
880                                 arg_type = sig->params [i - sig->hasthis];
881
882                         /* FIXME: VOLATILE is only set if the liveness pass runs */
883                         if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
884                                 inreg = FALSE;
885
886                         inst->opcode = OP_REGOFFSET;
887
888                         switch (ainfo->storage) {
889                         case ArgInIReg:
890                                 inst->opcode = OP_REGVAR;
891                                 inst->dreg = cfg->arch.reg_in0 + ainfo->reg;
892                                 break;
893                         case ArgInFloatReg:
894                                 /* 
895                                  * Since float regs are volatile, we save the arguments to
896                                  * the stack in the prolog.
897                                  */
898                                 inreg = FALSE;
899                                 break;
900                         case ArgOnStack:
901                                 if (cfg->arch.omit_fp)
902                                         g_assert_not_reached ();
903                                 inst->opcode = OP_REGOFFSET;
904                                 inst->inst_basereg = cfg->frame_reg;
905                                 inst->inst_offset = ARGS_OFFSET + ainfo->offset;
906                                 break;
907                         case ArgAggregate:
908                                 inreg = FALSE;
909                                 break;
910                         default:
911                                 NOT_IMPLEMENTED;
912                         }
913
914                         if (!inreg && (ainfo->storage != ArgOnStack)) {
915                                 inst->opcode = OP_REGOFFSET;
916                                 inst->inst_basereg = cfg->frame_reg;
917                                 /* These arguments are saved to the stack in the prolog */
918                                 switch (ainfo->storage) {
919                                 case ArgAggregate:
920                                         if (ainfo->atype == AggregateSingleHFA)
921                                                 offset += ainfo->nslots * 4;
922                                         else
923                                                 offset += ainfo->nslots * 8;
924                                         break;
925                                 default:
926                                         offset += sizeof (gpointer);
927                                         break;
928                                 }
929                                 offset = ALIGN_TO (offset, sizeof (gpointer));
930                                 if (cfg->arch.omit_fp)
931                                         inst->inst_offset = offset;
932                                 else
933                                         inst->inst_offset = - offset;
934                         }
935                 }
936         }
937
938         if (cfg->arch.omit_fp && offset == 16)
939                 offset = 0;
940
941         cfg->stack_offset = offset;
942 }
943
944 void
945 mono_arch_create_vars (MonoCompile *cfg)
946 {
947         MonoMethodSignature *sig;
948         CallInfo *cinfo;
949
950         sig = mono_method_signature (cfg->method);
951
952         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
953
954         if (cinfo->ret.storage == ArgAggregate)
955                 cfg->ret_var_is_local = TRUE;
956 }
957
958 static void
959 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage storage, int reg, MonoInst *tree)
960 {
961         switch (storage) {
962         case ArgInIReg:
963                 arg->opcode = OP_OUTARG_REG;
964                 arg->inst_left = tree;
965                 arg->inst_right = (MonoInst*)call;
966                 arg->backend.reg3 = reg;
967                 call->used_iregs |= 1 << reg;
968                 break;
969         case ArgInFloatReg:
970                 arg->opcode = OP_OUTARG_FREG;
971                 arg->inst_left = tree;
972                 arg->inst_right = (MonoInst*)call;
973                 arg->backend.reg3 = reg;
974                 call->used_fregs |= 1 << reg;
975                 break;
976         default:
977                 g_assert_not_reached ();
978         }
979 }
980
981 static void
982 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
983 {
984         MonoInst *arg;
985         MonoMethodSignature *tmp_sig;
986         MonoInst *sig_arg;
987
988         /* FIXME: Add support for signature tokens to AOT */
989         cfg->disable_aot = TRUE;
990
991         g_assert (cinfo->sig_cookie.storage == ArgOnStack);
992
993         /*
994          * mono_ArgIterator_Setup assumes the signature cookie is 
995          * passed first and all the arguments which were before it are
996          * passed on the stack after the signature. So compensate by 
997          * passing a different signature.
998          */
999         tmp_sig = mono_metadata_signature_dup (call->signature);
1000         tmp_sig->param_count -= call->signature->sentinelpos;
1001         tmp_sig->sentinelpos = 0;
1002         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1003
1004         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1005         sig_arg->inst_p0 = tmp_sig;
1006
1007         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1008         arg->inst_left = sig_arg;
1009         arg->inst_imm = 16 + cinfo->sig_cookie.offset;
1010         arg->type = STACK_PTR;
1011
1012         /* prepend, so they get reversed */
1013         arg->next = call->out_args;
1014         call->out_args = arg;
1015 }
1016
1017 /* 
1018  * take the arguments and generate the arch-specific
1019  * instructions to properly call the function in call.
1020  * This includes pushing, moving arguments to the right register
1021  * etc.
1022  */
1023 MonoCallInst*
1024 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
1025 {
1026         MonoInst *arg, *in;
1027         MonoMethodSignature *sig;
1028         int i, n, stack_size;
1029         CallInfo *cinfo;
1030         ArgInfo *ainfo;
1031
1032         stack_size = 0;
1033
1034         mono_ia64_alloc_stacked_registers (cfg);
1035
1036         sig = call->signature;
1037         n = sig->param_count + sig->hasthis;
1038
1039         cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
1040
1041         if (cinfo->ret.storage == ArgAggregate) {
1042                 /* The code in emit_this_vret_arg needs a local */
1043                 cfg->arch.ret_var_addr_local = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1044                 ((MonoInst*)cfg->arch.ret_var_addr_local)->flags |= MONO_INST_VOLATILE;
1045         }
1046
1047         for (i = 0; i < n; ++i) {
1048                 ainfo = cinfo->args + i;
1049
1050                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1051                         /* Emit the signature cookie just before the implicit arguments */
1052                         emit_sig_cookie (cfg, call, cinfo);
1053                 }
1054
1055                 if (is_virtual && i == 0) {
1056                         /* the argument will be attached to the call instruction */
1057                         in = call->args [i];
1058                 } else {
1059                         MonoType *arg_type;
1060
1061                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1062                         in = call->args [i];
1063                         arg->cil_code = in->cil_code;
1064                         arg->inst_left = in;
1065                         arg->type = in->type;
1066                         /* prepend, so they get reversed */
1067                         arg->next = call->out_args;
1068                         call->out_args = arg;
1069
1070                         if (sig->hasthis && (i == 0))
1071                                 arg_type = &mono_defaults.object_class->byval_arg;
1072                         else
1073                                 arg_type = sig->params [i - sig->hasthis];
1074
1075                         if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(arg_type))) {
1076                                 MonoInst *stack_addr;
1077                                 guint32 align;
1078                                 guint32 size;
1079
1080                                 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
1081                                         size = sizeof (MonoTypedRef);
1082                                         align = sizeof (gpointer);
1083                                 }
1084                                 else
1085                                 if (sig->pinvoke)
1086                                         size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
1087                                 else {
1088                                         /* 
1089                                          * Other backends use mini_type_stack_size (), but that
1090                                          * aligns the size to 8, which is larger than the size of
1091                                          * the source, leading to reads of invalid memory if the
1092                                          * source is at the end of address space.
1093                                          */
1094                                         size = mono_class_value_size (in->klass, &align);
1095                                 }
1096
1097                                 if (ainfo->storage == ArgAggregate) {
1098                                         MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
1099                                         int slot, j;
1100
1101                                         vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1102
1103                                         /* 
1104                                          * Part of the structure is passed in registers.
1105                                          */
1106                                         for (j = 0; j < ainfo->nregs; ++j) {
1107                                                 int offset, load_op, dest_reg, arg_storage;
1108
1109                                                 slot = ainfo->reg + j;
1110                                                 
1111                                                 if (ainfo->atype == AggregateSingleHFA) {
1112                                                         load_op = CEE_LDIND_R4;
1113                                                         offset = j * 4;
1114                                                         dest_reg = ainfo->reg + j;
1115                                                         arg_storage = ArgInFloatReg;
1116                                                 } else if (ainfo->atype == AggregateDoubleHFA) {
1117                                                         load_op = CEE_LDIND_R8;
1118                                                         offset = j * 8;
1119                                                         dest_reg = ainfo->reg + j;
1120                                                         arg_storage = ArgInFloatReg;
1121                                                 } else {
1122                                                         load_op = CEE_LDIND_I;
1123                                                         offset = j * 8;
1124                                                         dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
1125                                                         arg_storage = ArgInIReg;
1126                                                 }
1127
1128                                                 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1129                                                 load->ssa_op = MONO_SSA_LOAD;
1130                                                 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1131
1132                                                 NEW_ICONST (cfg, offset_ins, offset);
1133                                                 MONO_INST_NEW (cfg, load2, CEE_ADD);
1134                                                 load2->inst_left = load;
1135                                                 load2->inst_right = offset_ins;
1136
1137                                                 MONO_INST_NEW (cfg, load, load_op);
1138                                                 load->inst_left = load2;
1139
1140                                                 if (j == 0)
1141                                                         set_reg = arg;
1142                                                 else
1143                                                         MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
1144                                                 add_outarg_reg (cfg, call, set_reg, arg_storage, dest_reg, load);
1145                                                 if (set_reg != call->out_args) {
1146                                                         set_reg->next = call->out_args;
1147                                                         call->out_args = set_reg;
1148                                                 }
1149                                         }
1150
1151                                         /* 
1152                                          * Part of the structure is passed on the stack.
1153                                          */
1154                                         for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
1155                                                 MonoInst *outarg;
1156
1157                                                 slot = ainfo->reg + j;
1158
1159                                                 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1160                                                 load->ssa_op = MONO_SSA_LOAD;
1161                                                 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
1162
1163                                                 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
1164                                                 MONO_INST_NEW (cfg, load2, CEE_ADD);
1165                                                 load2->inst_left = load;
1166                                                 load2->inst_right = offset_ins;
1167
1168                                                 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
1169                                                 load->inst_left = load2;
1170
1171                                                 if (j == 0)
1172                                                         outarg = arg;
1173                                                 else
1174                                                         MONO_INST_NEW (cfg, outarg, OP_OUTARG);
1175                                                 outarg->inst_left = load;
1176                                                 outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
1177
1178                                                 if (outarg != call->out_args) {
1179                                                         outarg->next = call->out_args;
1180                                                         call->out_args = outarg;
1181                                                 }
1182                                         }
1183
1184                                         /* Trees can't be shared so make a copy */
1185                                         MONO_INST_NEW (cfg, arg, CEE_STIND_I);
1186                                         arg->cil_code = in->cil_code;
1187                                         arg->ssa_op = MONO_SSA_STORE;
1188                                         arg->inst_left = vtaddr;
1189                                         arg->inst_right = in;
1190                                         arg->type = in->type;
1191                                         
1192                                         /* prepend, so they get reversed */
1193                                         arg->next = call->out_args;
1194                                         call->out_args = arg;
1195                                 }
1196                                 else {
1197                                         MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
1198                                         stack_addr->inst_basereg = IA64_SP;
1199                                         stack_addr->inst_offset = 16 + ainfo->offset;
1200                                         stack_addr->inst_imm = size;
1201
1202                                         arg->opcode = OP_OUTARG_VT;
1203                                         arg->inst_right = stack_addr;
1204                                 }
1205                         }
1206                         else {
1207                                 switch (ainfo->storage) {
1208                                 case ArgInIReg:
1209                                         add_outarg_reg (cfg, call, arg, ainfo->storage, cfg->arch.reg_out0 + ainfo->reg, in);
1210                                         break;
1211                                 case ArgInFloatReg:
1212                                         add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
1213                                         break;
1214                                 case ArgOnStack:
1215                                         if (arg_type->type == MONO_TYPE_R4 && !arg_type->byref) {
1216                                                 arg->opcode = OP_OUTARG_R4;
1217                                         }
1218                                         else
1219                                                 arg->opcode = OP_OUTARG;
1220                                         arg->inst_imm = 16 + ainfo->offset;
1221                                         break;
1222                                 default:
1223                                         g_assert_not_reached ();
1224                                 }
1225                         }
1226                 }
1227         }
1228
1229         /* Handle the case where there are no implicit arguments */
1230         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
1231                 emit_sig_cookie (cfg, call, cinfo);
1232         }
1233
1234         call->stack_usage = cinfo->stack_usage;
1235         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
1236         cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
1237         cfg->flags |= MONO_CFG_HAS_CALLS;
1238
1239         return call;
1240 }
1241
1242 static void
1243 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1244 {
1245         MonoInst *ins, *last_ins = NULL;
1246         ins = bb->code;
1247
1248         while (ins) {
1249                 switch (ins->opcode) {
1250                 case OP_MOVE:
1251                 case OP_FMOVE:
1252                         /*
1253                          * Removes:
1254                          *
1255                          * OP_MOVE reg, reg 
1256                          */
1257                         if (ins->dreg == ins->sreg1) {
1258                                 if (last_ins)
1259                                         last_ins->next = ins->next;                             
1260                                 ins = ins->next;
1261                                 continue;
1262                         }
1263                         /* 
1264                          * Removes:
1265                          *
1266                          * OP_MOVE sreg, dreg 
1267                          * OP_MOVE dreg, sreg
1268                          */
1269                         if (last_ins && last_ins->opcode == OP_MOVE &&
1270                             ins->sreg1 == last_ins->dreg &&
1271                             ins->dreg == last_ins->sreg1) {
1272                                 last_ins->next = ins->next;                             
1273                                 ins = ins->next;                                
1274                                 continue;
1275                         }
1276                         break;
1277                 case OP_MUL_IMM: 
1278                 case OP_IMUL_IMM: 
1279                         /* remove unnecessary multiplication with 1 */
1280                         if (ins->inst_imm == 1) {
1281                                 if (ins->dreg != ins->sreg1) {
1282                                         ins->opcode = OP_MOVE;
1283                                 } else {
1284                                         last_ins->next = ins->next;
1285                                         ins = ins->next;
1286                                         continue;
1287                                 }
1288                         }
1289                         break;
1290                 }
1291
1292                 last_ins = ins;
1293                 ins = ins->next;
1294         }
1295         bb->last_ins = last_ins;
1296 }
1297
1298 int cond_to_ia64_cmp [][3] = {
1299         {OP_IA64_CMP_EQ, OP_IA64_CMP4_EQ, OP_IA64_FCMP_EQ},
1300         {OP_IA64_CMP_NE, OP_IA64_CMP4_NE, OP_IA64_FCMP_NE},
1301         {OP_IA64_CMP_LE, OP_IA64_CMP4_LE, OP_IA64_FCMP_LE},
1302         {OP_IA64_CMP_GE, OP_IA64_CMP4_GE, OP_IA64_FCMP_GE},
1303         {OP_IA64_CMP_LT, OP_IA64_CMP4_LT, OP_IA64_FCMP_LT},
1304         {OP_IA64_CMP_GT, OP_IA64_CMP4_GT, OP_IA64_FCMP_GT},
1305         {OP_IA64_CMP_LE_UN, OP_IA64_CMP4_LE_UN, OP_IA64_FCMP_LE_UN},
1306         {OP_IA64_CMP_GE_UN, OP_IA64_CMP4_GE_UN, OP_IA64_FCMP_GE_UN},
1307         {OP_IA64_CMP_LT_UN, OP_IA64_CMP4_LT_UN, OP_IA64_FCMP_LT_UN},
1308         {OP_IA64_CMP_GT_UN, OP_IA64_CMP4_GT_UN, OP_IA64_FCMP_GT_UN}
1309 };
1310
1311 static int
1312 opcode_to_ia64_cmp (int opcode, int cmp_opcode)
1313 {
1314         return cond_to_ia64_cmp [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1315 }
1316
1317 int cond_to_ia64_cmp_imm [][3] = {
1318         {OP_IA64_CMP_EQ_IMM, OP_IA64_CMP4_EQ_IMM, 0},
1319         {OP_IA64_CMP_NE_IMM, OP_IA64_CMP4_NE_IMM, 0},
1320         {OP_IA64_CMP_GE_IMM, OP_IA64_CMP4_GE_IMM, 0},
1321         {OP_IA64_CMP_LE_IMM, OP_IA64_CMP4_LE_IMM, 0},
1322         {OP_IA64_CMP_GT_IMM, OP_IA64_CMP4_GT_IMM, 0},
1323         {OP_IA64_CMP_LT_IMM, OP_IA64_CMP4_LT_IMM, 0},
1324         {OP_IA64_CMP_GE_UN_IMM, OP_IA64_CMP4_GE_UN_IMM, 0},
1325         {OP_IA64_CMP_LE_UN_IMM, OP_IA64_CMP4_LE_UN_IMM, 0},
1326         {OP_IA64_CMP_GT_UN_IMM, OP_IA64_CMP4_GT_UN_IMM, 0},
1327         {OP_IA64_CMP_LT_UN_IMM, OP_IA64_CMP4_LT_UN_IMM, 0},
1328 };
1329
1330 static int
1331 opcode_to_ia64_cmp_imm (int opcode, int cmp_opcode)
1332 {
1333         /* The condition needs to be reversed */
1334         return cond_to_ia64_cmp_imm [mono_opcode_to_cond (opcode)][mono_opcode_to_type (opcode, cmp_opcode)];
1335 }
1336
1337 static void
1338 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1339 {
1340         if (ins == NULL) {
1341                 ins = bb->code;
1342                 bb->code = to_insert;
1343                 to_insert->next = ins;
1344         }
1345         else {
1346                 to_insert->next = ins->next;
1347                 ins->next = to_insert;
1348         }
1349 }
1350
1351 #define NEW_INS(cfg,dest,op) do {       \
1352                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
1353                 (dest)->opcode = (op);  \
1354         insert_after_ins (bb, last_ins, (dest)); \
1355         last_ins = (dest); \
1356         } while (0)
1357
1358 /*
1359  * mono_arch_lowering_pass:
1360  *
1361  *  Converts complex opcodes into simpler ones so that each IR instruction
1362  * corresponds to one machine instruction.
1363  */
1364 static void
1365 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1366 {
1367         MonoInst *ins, *next, *temp, *temp2, *temp3, *last_ins = NULL;
1368         ins = bb->code;
1369
1370         if (bb->max_vreg > cfg->rs->next_vreg)
1371                 cfg->rs->next_vreg = bb->max_vreg;
1372
1373         while (ins) {
1374                 switch (ins->opcode) {
1375                 case OP_STOREI1_MEMBASE_IMM:
1376                 case OP_STOREI2_MEMBASE_IMM:
1377                 case OP_STOREI4_MEMBASE_IMM:
1378                 case OP_STOREI8_MEMBASE_IMM:
1379                 case OP_STORE_MEMBASE_IMM:
1380                         /* There are no store_membase instructions on ia64 */
1381                         if (ins->inst_offset == 0) {
1382                                 temp2 = NULL;
1383                         } else if (ia64_is_imm14 (ins->inst_offset)) {
1384                                 NEW_INS (cfg, temp2, OP_ADD_IMM);
1385                                 temp2->sreg1 = ins->inst_destbasereg;
1386                                 temp2->inst_imm = ins->inst_offset;
1387                                 temp2->dreg = mono_regstate_next_int (cfg->rs);
1388                         }
1389                         else {
1390                                 NEW_INS (cfg, temp, OP_I8CONST);
1391                                 temp->inst_c0 = ins->inst_offset;
1392                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1393                                 NEW_INS (cfg, temp2, CEE_ADD);
1394                                 temp2->sreg1 = ins->inst_destbasereg;
1395                                 temp2->sreg2 = temp->dreg;
1396                                 temp2->dreg = mono_regstate_next_int (cfg->rs);
1397                         }
1398
1399                         switch (ins->opcode) {
1400                         case OP_STOREI1_MEMBASE_IMM:
1401                                 ins->opcode = OP_STOREI1_MEMBASE_REG;
1402                                 break;
1403                         case OP_STOREI2_MEMBASE_IMM:
1404                                 ins->opcode = OP_STOREI2_MEMBASE_REG;
1405                                 break;
1406                         case OP_STOREI4_MEMBASE_IMM:
1407                                 ins->opcode = OP_STOREI4_MEMBASE_REG;
1408                                 break;
1409                         case OP_STOREI8_MEMBASE_IMM:
1410                         case OP_STORE_MEMBASE_IMM:
1411                                 ins->opcode = OP_STOREI8_MEMBASE_REG;
1412                                 break;
1413                         default:
1414                                 g_assert_not_reached ();
1415                         }
1416
1417                         if (ins->inst_imm == 0)
1418                                 ins->sreg1 = IA64_R0;
1419                         else {
1420                                 NEW_INS (cfg, temp3, OP_I8CONST);
1421                                 temp3->inst_c0 = ins->inst_imm;
1422                                 temp3->dreg = mono_regstate_next_int (cfg->rs);
1423                                 ins->sreg1 = temp3->dreg;
1424                         }
1425
1426                         ins->inst_offset = 0;
1427                         if (temp2)
1428                                 ins->inst_destbasereg = temp2->dreg;
1429                         break;
1430                 case OP_STOREI1_MEMBASE_REG:
1431                 case OP_STOREI2_MEMBASE_REG:
1432                 case OP_STOREI4_MEMBASE_REG:
1433                 case OP_STOREI8_MEMBASE_REG:
1434                 case OP_STORER4_MEMBASE_REG:
1435                 case OP_STORER8_MEMBASE_REG:
1436                 case OP_STORE_MEMBASE_REG:
1437                         /* There are no store_membase instructions on ia64 */
1438                         if (ins->inst_offset == 0) {
1439                                 break;
1440                         }
1441                         else if (ia64_is_imm14 (ins->inst_offset)) {
1442                                 NEW_INS (cfg, temp2, OP_ADD_IMM);
1443                                 temp2->sreg1 = ins->inst_destbasereg;
1444                                 temp2->inst_imm = ins->inst_offset;
1445                                 temp2->dreg = mono_regstate_next_int (cfg->rs);
1446                         }
1447                         else {
1448                                 NEW_INS (cfg, temp, OP_I8CONST);
1449                                 temp->inst_c0 = ins->inst_offset;
1450                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1451                                 NEW_INS (cfg, temp2, CEE_ADD);
1452                                 temp2->sreg1 = ins->inst_destbasereg;
1453                                 temp2->sreg2 = temp->dreg;
1454                                 temp2->dreg = mono_regstate_next_int (cfg->rs);
1455                         }
1456
1457                         ins->inst_offset = 0;
1458                         ins->inst_destbasereg = temp2->dreg;
1459                         break;
1460                 case OP_LOADI1_MEMBASE:
1461                 case OP_LOADU1_MEMBASE:
1462                 case OP_LOADI2_MEMBASE:
1463                 case OP_LOADU2_MEMBASE:
1464                 case OP_LOADI4_MEMBASE:
1465                 case OP_LOADU4_MEMBASE:
1466                 case OP_LOADI8_MEMBASE:
1467                 case OP_LOAD_MEMBASE:
1468                 case OP_LOADR4_MEMBASE:
1469                 case OP_LOADR8_MEMBASE:
1470                 case OP_ATOMIC_EXCHANGE_I4:
1471                 case OP_ATOMIC_EXCHANGE_I8:
1472                 case OP_ATOMIC_ADD_NEW_I4:
1473                 case OP_ATOMIC_ADD_NEW_I8:
1474                 case OP_ATOMIC_ADD_IMM_NEW_I4:
1475                 case OP_ATOMIC_ADD_IMM_NEW_I8:
1476                         /* There are no membase instructions on ia64 */
1477                         if (ins->inst_offset == 0) {
1478                                 break;
1479                         }
1480                         else if (ia64_is_imm14 (ins->inst_offset)) {
1481                                 NEW_INS (cfg, temp2, OP_ADD_IMM);
1482                                 temp2->sreg1 = ins->inst_basereg;
1483                                 temp2->inst_imm = ins->inst_offset;
1484                                 temp2->dreg = mono_regstate_next_int (cfg->rs);
1485                         }
1486                         else {
1487                                 NEW_INS (cfg, temp, OP_I8CONST);
1488                                 temp->inst_c0 = ins->inst_offset;
1489                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1490                                 NEW_INS (cfg, temp2, CEE_ADD);
1491                                 temp2->sreg1 = ins->inst_basereg;
1492                                 temp2->sreg2 = temp->dreg;
1493                                 temp2->dreg = mono_regstate_next_int (cfg->rs);
1494                         }
1495
1496                         ins->inst_offset = 0;
1497                         ins->inst_basereg = temp2->dreg;
1498                         break;
1499                 case OP_ADD_IMM:
1500                 case OP_IADD_IMM:
1501                 case OP_ISUB_IMM:
1502                 case OP_IAND_IMM:
1503                 case OP_IOR_IMM:
1504                 case OP_IXOR_IMM:
1505                 case OP_AND_IMM:
1506                 case OP_SHL_IMM:
1507                 case OP_SHR_IMM:
1508                 case OP_ISHL_IMM:
1509                 case OP_LSHL_IMM:
1510                 case OP_ISHR_IMM:
1511                 case OP_LSHR_IMM:
1512                 case OP_ISHR_UN_IMM:
1513                 case OP_LSHR_UN_IMM: {
1514                         gboolean is_imm = FALSE;
1515                         gboolean switched = FALSE;
1516
1517                         if (ins->opcode == OP_AND_IMM && ins->inst_imm == 255) {
1518                                 ins->opcode = OP_ZEXT_I1;
1519                                 break;
1520                         }
1521
1522                         switch (ins->opcode) {
1523                         case OP_ADD_IMM:
1524                         case OP_IADD_IMM:
1525                                 is_imm = ia64_is_imm14 (ins->inst_imm);
1526                                 switched = TRUE;
1527                                 break;
1528                         case OP_ISUB_IMM:
1529                                 is_imm = ia64_is_imm14 (- (ins->inst_imm));
1530                                 if (is_imm) {
1531                                         /* A = B - IMM -> A = B + (-IMM) */
1532                                         ins->inst_imm = - ins->inst_imm;
1533                                         ins->opcode = OP_IADD_IMM;
1534                                 }
1535                                 switched = TRUE;
1536                                 break;
1537                         case OP_IAND_IMM:
1538                         case OP_IOR_IMM:
1539                         case OP_IXOR_IMM:
1540                         case OP_AND_IMM:
1541                                 is_imm = ia64_is_imm8 (ins->inst_imm);
1542                                 switched = TRUE;
1543                                 break;
1544                         case OP_SHL_IMM:
1545                         case OP_SHR_IMM:
1546                         case OP_ISHL_IMM:
1547                         case OP_LSHL_IMM:
1548                         case OP_ISHR_IMM:
1549                         case OP_LSHR_IMM:
1550                         case OP_ISHR_UN_IMM:
1551                         case OP_LSHR_UN_IMM:
1552                                 is_imm = (ins->inst_imm >= 0) && (ins->inst_imm < 64);
1553                                 break;
1554                         default:
1555                                 break;
1556                         }
1557
1558                         if (is_imm) {
1559                                 if (switched)
1560                                         ins->sreg2 = ins->sreg1;
1561                                 break;
1562                         }
1563
1564                         switch (ins->opcode) {
1565                         case OP_ADD_IMM:                                        
1566                                 ins->opcode = CEE_ADD;
1567                                 break;
1568                         case OP_IADD_IMM:
1569                                 ins->opcode = OP_IADD;
1570                                 break;
1571                         case OP_ISUB_IMM:
1572                                 ins->opcode = OP_ISUB;
1573                                 break;
1574                         case OP_IAND_IMM:
1575                                 ins->opcode = OP_IAND;
1576                                 break;
1577                         case OP_IOR_IMM:
1578                                 ins->opcode = OP_IOR;
1579                                 break;
1580                         case OP_IXOR_IMM:
1581                                 ins->opcode = OP_IXOR;
1582                                 break;
1583                         case OP_ISHL_IMM:
1584                                 ins->opcode = OP_ISHL;
1585                                 break;
1586                         case OP_ISHR_IMM:
1587                                 ins->opcode = OP_ISHR;
1588                                 break;
1589                         case OP_ISHR_UN_IMM:
1590                                 ins->opcode = OP_ISHR_UN;
1591                                 break;
1592                         case OP_AND_IMM:
1593                                 ins->opcode = CEE_AND;
1594                                 break;
1595                         case OP_SHL_IMM:
1596                                 ins->opcode = OP_LSHL;
1597                                 break;
1598                         case OP_SHR_IMM:
1599                                 ins->opcode = OP_LSHR;
1600                                 break;
1601                         case OP_LSHL_IMM:
1602                                 ins->opcode = OP_LSHL;
1603                                 break;
1604                         case OP_LSHR_IMM:
1605                                 ins->opcode = OP_LSHR;
1606                                 break;
1607                         case OP_LSHR_UN_IMM:
1608                                 ins->opcode = OP_LSHR_UN;
1609                                 break;
1610                         default:
1611                                 g_assert_not_reached ();
1612                         }
1613
1614                         if (ins->inst_imm == 0)
1615                                 ins->sreg2 = IA64_R0;
1616                         else {
1617                                 NEW_INS (cfg, temp, OP_I8CONST);
1618                                 temp->inst_c0 = ins->inst_imm;
1619                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1620                                 ins->sreg2 = temp->dreg;
1621                         }
1622                         break;
1623                 }
1624                 case OP_COMPARE_IMM:
1625                 case OP_ICOMPARE_IMM: {
1626                         /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1627                         gboolean imm;
1628                         CompRelation cond;
1629
1630                         /* 
1631                          * The compare_imm instructions have switched up arguments, and 
1632                          * some of them take an imm between -127 and 128.
1633                          */
1634                         next = ins->next;
1635                         cond = mono_opcode_to_cond (next->opcode);
1636                         if ((cond == CMP_LT) || (cond == CMP_GE))
1637                                 imm = ia64_is_imm8 (ins->inst_imm - 1);
1638                         else if ((cond == CMP_LT_UN) || (cond == CMP_GE_UN))
1639                                 imm = ia64_is_imm8 (ins->inst_imm - 1) && (ins->inst_imm > 0);
1640                         else
1641                                 imm = ia64_is_imm8 (ins->inst_imm);
1642
1643                         if (imm) {
1644                                 ins->opcode = opcode_to_ia64_cmp_imm (next->opcode, ins->opcode);
1645                                 ins->sreg2 = ins->sreg1;
1646                         }
1647                         else {
1648                                 ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1649
1650                                 if (ins->inst_imm == 0)
1651                                         ins->sreg2 = IA64_R0;
1652                                 else {
1653                                         NEW_INS (cfg, temp, OP_I8CONST);
1654                                         temp->inst_c0 = ins->inst_imm;
1655                                         temp->dreg = mono_regstate_next_int (cfg->rs);
1656                                         ins->sreg2 = temp->dreg;
1657                                 }
1658                         }
1659
1660                         switch (next->opcode) {
1661                         case CEE_BEQ:
1662                         case CEE_BNE_UN:
1663                         case CEE_BLE:
1664                         case CEE_BGT:
1665                         case CEE_BLE_UN:
1666                         case CEE_BGT_UN:
1667                         case CEE_BGE:
1668                         case CEE_BLT:
1669                         case CEE_BGE_UN:
1670                         case CEE_BLT_UN:
1671                         case OP_IBEQ:
1672                         case OP_IBNE_UN:
1673                         case OP_IBLE:
1674                         case OP_IBLT:
1675                         case OP_IBGT:
1676                         case OP_IBGE:
1677                         case OP_IBLE_UN:
1678                         case OP_IBLT_UN:
1679                         case OP_IBGE_UN:
1680                         case OP_IBGT_UN:
1681                                 next->opcode = OP_IA64_BR_COND;
1682                                 if (! (next->flags & MONO_INST_BRLABEL))
1683                                         next->inst_target_bb = next->inst_true_bb;
1684                                 break;
1685                         case OP_COND_EXC_EQ:
1686                         case OP_COND_EXC_GT:
1687                         case OP_COND_EXC_LT:
1688                         case OP_COND_EXC_GT_UN:
1689                         case OP_COND_EXC_LE_UN:
1690                         case OP_COND_EXC_NE_UN:
1691                         case OP_COND_EXC_LT_UN:
1692                                 next->opcode = OP_IA64_COND_EXC;
1693                                 break;
1694                         case OP_CEQ:
1695                         case OP_CLT:
1696                         case OP_CGT:
1697                         case OP_CLT_UN:
1698                         case OP_CGT_UN:
1699                         case OP_ICEQ:
1700                         case OP_ICLT:
1701                         case OP_ICGT:
1702                         case OP_ICLT_UN:
1703                         case OP_ICGT_UN:
1704                                 next->opcode = OP_IA64_CSET;
1705                                 break;
1706                         default:
1707                                 printf ("%s\n", mono_inst_name (next->opcode));
1708                                 NOT_IMPLEMENTED;
1709                         }
1710
1711                         break;
1712                 }
1713                 case OP_COMPARE:
1714                 case OP_ICOMPARE:
1715                 case OP_LCOMPARE:
1716                 case OP_FCOMPARE: {
1717                         /* Instead of compare+b<cond>, ia64 has compare<cond>+br */
1718
1719                         next = ins->next;
1720
1721                         ins->opcode = opcode_to_ia64_cmp (next->opcode, ins->opcode);
1722                         switch (next->opcode) {
1723                         case CEE_BEQ:
1724                         case CEE_BNE_UN:
1725                         case CEE_BLE:
1726                         case CEE_BGE:
1727                         case CEE_BLT:
1728                         case CEE_BGT:
1729                         case CEE_BLE_UN:
1730                         case CEE_BGE_UN:
1731                         case CEE_BLT_UN:
1732                         case CEE_BGT_UN:
1733                         case OP_IBEQ:
1734                         case OP_IBNE_UN:
1735                         case OP_IBLE:
1736                         case OP_IBLT:
1737                         case OP_IBGT:
1738                         case OP_IBGE:
1739                         case OP_IBLE_UN:
1740                         case OP_IBLT_UN:
1741                         case OP_IBGE_UN:
1742                         case OP_IBGT_UN:
1743                         case OP_FBEQ:
1744                         case OP_FBNE_UN:
1745                         case OP_FBLT:
1746                         case OP_FBLT_UN:
1747                         case OP_FBGT:
1748                         case OP_FBGT_UN:
1749                         case OP_FBGE:
1750                         case OP_FBGE_UN:
1751                         case OP_FBLE:
1752                         case OP_FBLE_UN:
1753                                 next->opcode = OP_IA64_BR_COND;
1754                                 if (! (next->flags & MONO_INST_BRLABEL))
1755                                         next->inst_target_bb = next->inst_true_bb;
1756                                 break;
1757                         case OP_COND_EXC_LT:
1758                         case OP_COND_EXC_GT:
1759                         case OP_COND_EXC_GT_UN:
1760                         case OP_COND_EXC_LE_UN:
1761                                 next->opcode = OP_IA64_COND_EXC;
1762                                 break;
1763                         case OP_CEQ:
1764                         case OP_CLT:
1765                         case OP_CGT:
1766                         case OP_CLT_UN:
1767                         case OP_CGT_UN:
1768                         case OP_ICEQ:
1769                         case OP_ICLT:
1770                         case OP_ICGT:
1771                         case OP_ICLT_UN:
1772                         case OP_ICGT_UN:
1773                         case OP_FCEQ:
1774                         case OP_FCLT:
1775                         case OP_FCGT:
1776                         case OP_FCLT_UN:
1777                         case OP_FCGT_UN:
1778                                 next->opcode = OP_IA64_CSET;
1779                                 break;
1780                         default:
1781                                 printf ("%s\n", mono_inst_name (next->opcode));
1782                                 NOT_IMPLEMENTED;
1783                         }
1784                         break;
1785                 }
1786                 case OP_MUL_IMM:
1787                 case OP_LMUL_IMM:
1788                 case OP_IMUL_IMM: {
1789                         int i, sum_reg;
1790                         gboolean found = FALSE;
1791                         int shl_op = ins->opcode == OP_IMUL_IMM ? OP_ISHL_IMM : OP_SHL_IMM;
1792
1793                         /* First the easy cases */
1794                         if (ins->inst_imm == 1) {
1795                                 ins->opcode = OP_MOVE;
1796                                 break;
1797                         }
1798                         for (i = 1; i < 64; ++i)
1799                                 if (ins->inst_imm == (((gint64)1) << i)) {
1800                                         ins->opcode = shl_op;
1801                                         ins->inst_imm = i;
1802                                         found = TRUE;
1803                                         break;
1804                                 }
1805
1806                         /* This could be optimized */
1807                         if (!found) {
1808                                 sum_reg = 0;
1809                                 for (i = 0; i < 64; ++i) {
1810                                         if (ins->inst_imm & (((gint64)1) << i)) {
1811                                                 NEW_INS (cfg, temp, shl_op);
1812                                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1813                                                 temp->sreg1 = ins->sreg1;
1814                                                 temp->inst_imm = i;
1815
1816                                                 if (sum_reg == 0)
1817                                                         sum_reg = temp->dreg;
1818                                                 else {
1819                                                         NEW_INS (cfg, temp2, CEE_ADD);
1820                                                         temp2->dreg = mono_regstate_next_int (cfg->rs);
1821                                                         temp2->sreg1 = sum_reg;
1822                                                         temp2->sreg2 = temp->dreg;
1823                                                         sum_reg = temp2->dreg;
1824                                                 }
1825                                         }
1826                                 }
1827                                 ins->opcode = OP_MOVE;
1828                                 ins->sreg1 = sum_reg;
1829                         }
1830                         break;
1831                 }
1832                 case CEE_CONV_OVF_U4:
1833                         NEW_INS (cfg, temp, OP_IA64_CMP4_LT);
1834                         temp->sreg1 = ins->sreg1;
1835                         temp->sreg2 = IA64_R0;
1836
1837                         NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1838                         temp->inst_p1 = (char*)"OverflowException";
1839
1840                         ins->opcode = OP_MOVE;
1841                         break;
1842                 case CEE_CONV_OVF_I4_UN:
1843                         NEW_INS (cfg, temp, OP_ICONST);
1844                         temp->inst_c0 = 0x7fffffff;
1845                         temp->dreg = mono_regstate_next_int (cfg->rs);
1846
1847                         NEW_INS (cfg, temp2, OP_IA64_CMP4_GT_UN);
1848                         temp2->sreg1 = ins->sreg1;
1849                         temp2->sreg2 = temp->dreg;
1850
1851                         NEW_INS (cfg, temp, OP_IA64_COND_EXC);
1852                         temp->inst_p1 = (char*)"OverflowException";
1853
1854                         ins->opcode = OP_MOVE;
1855                         break;
1856                 case OP_FCONV_TO_I4:
1857                 case OP_FCONV_TO_I2:
1858                 case OP_FCONV_TO_U2:
1859                 case OP_FCONV_TO_I1:
1860                 case OP_FCONV_TO_U1:
1861                         NEW_INS (cfg, temp, OP_FCONV_TO_I8);
1862                         temp->sreg1 = ins->sreg1;
1863                         temp->dreg = ins->dreg;
1864
1865                         switch (ins->opcode) {
1866                         case OP_FCONV_TO_I4:
1867                                 ins->opcode = OP_SEXT_I4;
1868                                 break;
1869                         case OP_FCONV_TO_I2:
1870                                 ins->opcode = OP_SEXT_I2;
1871                                 break;
1872                         case OP_FCONV_TO_U2:
1873                                 ins->opcode = OP_ZEXT_I4;
1874                                 break;
1875                         case OP_FCONV_TO_I1:
1876                                 ins->opcode = OP_SEXT_I1;
1877                                 break;
1878                         case OP_FCONV_TO_U1:
1879                                 ins->opcode = OP_ZEXT_I1;
1880                                 break;
1881                         default:
1882                                 g_assert_not_reached ();
1883                         }
1884                         ins->sreg1 = ins->dreg;
1885                         break;
1886                 default:
1887                         break;
1888                 }
1889                 last_ins = ins;
1890                 ins = ins->next;
1891         }
1892         bb->last_ins = last_ins;
1893
1894         bb->max_vreg = cfg->rs->next_vreg;
1895 }
1896
1897 void
1898 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1899 {
1900         if (!bb->code)
1901                 return;
1902
1903         mono_arch_lowering_pass (cfg, bb);
1904
1905         mono_local_regalloc (cfg, bb);
1906 }
1907
1908 /*
1909  * emit_load_volatile_arguments:
1910  *
1911  *  Load volatile arguments from the stack to the original input registers.
1912  * Required before a tail call.
1913  */
1914 static Ia64CodegenState
1915 emit_load_volatile_arguments (MonoCompile *cfg, Ia64CodegenState code)
1916 {
1917         MonoMethod *method = cfg->method;
1918         MonoMethodSignature *sig;
1919         MonoInst *ins;
1920         CallInfo *cinfo;
1921         guint32 i;
1922
1923         /* FIXME: Generate intermediate code instead */
1924
1925         sig = mono_method_signature (method);
1926
1927         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
1928         
1929         /* This is the opposite of the code in emit_prolog */
1930         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1931                 ArgInfo *ainfo = cinfo->args + i;
1932                 gint32 stack_offset;
1933                 MonoType *arg_type;
1934                 ins = cfg->args [i];
1935
1936                 if (sig->hasthis && (i == 0))
1937                         arg_type = &mono_defaults.object_class->byval_arg;
1938                 else
1939                         arg_type = sig->params [i - sig->hasthis];
1940
1941                 arg_type = mono_type_get_underlying_type (arg_type);
1942
1943                 stack_offset = ainfo->offset + ARGS_OFFSET;
1944
1945                 /* Save volatile arguments to the stack */
1946                 if (ins->opcode != OP_REGVAR) {
1947                         switch (ainfo->storage) {
1948                         case ArgInIReg:
1949                         case ArgInFloatReg:
1950                                 /* FIXME: big offsets */
1951                                 g_assert (ins->opcode == OP_REGOFFSET);
1952                                 ia64_adds_imm (code, GP_SCRATCH_REG, ins->inst_offset, ins->inst_basereg);
1953                                 if (arg_type->byref)
1954                                         ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1955                                 else {
1956                                         switch (arg_type->type) {
1957                                         case MONO_TYPE_R4:
1958                                                 ia64_ldfs (code, ainfo->reg, GP_SCRATCH_REG);
1959                                                 break;
1960                                         case MONO_TYPE_R8:
1961                                                 ia64_ldfd (code, ainfo->reg, GP_SCRATCH_REG);
1962                                                 break;
1963                                         default:
1964                                                 ia64_ld8 (code, cfg->arch.reg_in0 + ainfo->reg, GP_SCRATCH_REG);
1965                                                 break;
1966                                         }
1967                                 }
1968                                 break;
1969                         case ArgOnStack:
1970                                 break;
1971                         default:
1972                                 NOT_IMPLEMENTED;
1973                         }
1974                 }
1975
1976                 if (ins->opcode == OP_REGVAR) {
1977                         /* Argument allocated to (non-volatile) register */
1978                         switch (ainfo->storage) {
1979                         case ArgInIReg:
1980                                 if (ins->dreg != cfg->arch.reg_in0 + ainfo->reg)
1981                                         ia64_mov (code, cfg->arch.reg_in0 + ainfo->reg, ins->dreg);
1982                                 break;
1983                         case ArgOnStack:
1984                                 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
1985                                 ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
1986                                 break;
1987                         default:
1988                                 NOT_IMPLEMENTED;
1989                         }
1990                 }
1991         }
1992
1993         return code;
1994 }
1995
1996 static Ia64CodegenState
1997 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, Ia64CodegenState code)
1998 {
1999         CallInfo *cinfo;
2000         int i;
2001
2002         /* Move return value to the target register */
2003         switch (ins->opcode) {
2004         case OP_VOIDCALL:
2005         case OP_VOIDCALL_REG:
2006         case OP_VOIDCALL_MEMBASE:
2007                 break;
2008         case CEE_CALL:
2009         case OP_CALL_REG:
2010         case OP_CALL_MEMBASE:
2011         case OP_LCALL:
2012         case OP_LCALL_REG:
2013         case OP_LCALL_MEMBASE:
2014                 g_assert (ins->dreg == IA64_R8);
2015                 break;
2016         case OP_FCALL:
2017         case OP_FCALL_REG:
2018         case OP_FCALL_MEMBASE:
2019                 g_assert (ins->dreg == 8);
2020                 break;
2021         case OP_VCALL:
2022         case OP_VCALL_REG:
2023         case OP_VCALL_MEMBASE: {
2024                 ArgStorage storage;
2025
2026                 cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
2027                 storage = cinfo->ret.storage;
2028
2029                 if (storage == ArgAggregate) {
2030                         MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
2031
2032                         /* Load address of stack space allocated for the return value */
2033                         ia64_movl (code, GP_SCRATCH_REG, local->inst_offset);
2034                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, local->inst_basereg);
2035                         ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
2036
2037                         for (i = 0; i < cinfo->ret.nregs; ++i) {
2038                                 switch (cinfo->ret.atype) {
2039                                 case AggregateNormal:
2040                                         ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2041                                         break;
2042                                 case AggregateSingleHFA:
2043                                         ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 4, 0);
2044                                         break;
2045                                 case AggregateDoubleHFA:
2046                                         ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, cinfo->ret.reg + i, 8, 0);
2047                                         break;
2048                                 default:
2049                                         g_assert_not_reached ();
2050                                 }
2051                         }
2052                 }
2053                 break;
2054         }
2055         default:
2056                 g_assert_not_reached ();
2057         }
2058
2059         return code;
2060 }
2061
2062 #define add_patch_info(cfg,code,patch_type,data) do { \
2063         mono_add_patch_info (cfg, code.buf + code.nins - cfg->native_code, patch_type, data); \
2064 } while (0)
2065
2066 #define emit_cond_system_exception(cfg,code,exc_name,predicate) do { \
2067         MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
2068     if (tins == NULL) \
2069         add_patch_info (cfg, code, MONO_PATCH_INFO_EXC, exc_name); \
2070     else \
2071                 add_patch_info (cfg, code, MONO_PATCH_INFO_BB, tins->inst_true_bb); \
2072         ia64_br_cond_pred (code, (predicate), 0); \
2073 } while (0)
2074
2075 static Ia64CodegenState
2076 emit_call (MonoCompile *cfg, Ia64CodegenState code, guint32 patch_type, gconstpointer data)
2077 {
2078         add_patch_info (cfg, code, patch_type, data);
2079
2080         if ((patch_type == MONO_PATCH_INFO_ABS) || (patch_type == MONO_PATCH_INFO_INTERNAL_METHOD)) {
2081                 /* Indirect call */
2082                 /* mono_arch_patch_callsite will patch this */
2083                 /* mono_arch_nullify_class_init_trampoline will patch this */
2084                 ia64_movl (code, GP_SCRATCH_REG, 0);
2085                 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
2086                 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2087                 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
2088                 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2089         }
2090         else {
2091                 /* Can't use a direct call since the displacement might be too small */
2092                 /* mono_arch_patch_callsite will patch this */
2093                 ia64_movl (code, GP_SCRATCH_REG, 0);
2094                 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2095                 ia64_br_call_reg (code, IA64_B0, IA64_B6);
2096         }
2097
2098         return code;
2099 }
2100
2101 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2102
2103 void
2104 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2105 {
2106         MonoInst *ins;
2107         MonoCallInst *call;
2108         guint offset;
2109         Ia64CodegenState code;
2110         guint8 *code_start = cfg->native_code + cfg->code_len;
2111         MonoInst *last_ins = NULL;
2112         guint last_offset = 0;
2113         int max_len, cpos;
2114
2115         if (cfg->opt & MONO_OPT_PEEPHOLE)
2116                 peephole_pass (cfg, bb);
2117
2118         if (cfg->opt & MONO_OPT_LOOP) {
2119                 /* FIXME: */
2120         }
2121
2122         if (cfg->verbose_level > 2)
2123                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2124
2125         cpos = bb->max_offset;
2126
2127         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2128                 NOT_IMPLEMENTED;
2129         }
2130
2131         offset = code_start - cfg->native_code;
2132
2133         ia64_codegen_init (code, code_start);
2134
2135 #if 0
2136         if (strstr (cfg->method->name, "conv_ovf_i1") && (bb->block_num == 2))
2137                 break_count ();
2138 #endif
2139
2140         ins = bb->code;
2141         while (ins) {
2142                 offset = code.buf - cfg->native_code;
2143
2144                 max_len = ((int)(((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN])) + 128;
2145
2146                 while (offset + max_len + 16 > cfg->code_size) {
2147                         ia64_codegen_close (code);
2148
2149                         offset = code.buf - cfg->native_code;
2150
2151                         cfg->code_size *= 2;
2152                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2153                         code_start = cfg->native_code + offset;
2154                         mono_jit_stats.code_reallocs++;
2155
2156                         ia64_codegen_init (code, code_start);
2157                 }
2158
2159                 mono_debug_record_line_number (cfg, ins, offset);
2160
2161                 switch (ins->opcode) {
2162                 case OP_ICONST:
2163                 case OP_I8CONST:
2164                         if (ia64_is_imm14 (ins->inst_c0))
2165                                 ia64_adds_imm (code, ins->dreg, ins->inst_c0, IA64_R0);
2166                         else
2167                                 ia64_movl (code, ins->dreg, ins->inst_c0);
2168                         break;
2169                 case OP_MOVE:
2170                         ia64_mov (code, ins->dreg, ins->sreg1);
2171                         break;
2172                 case OP_BR:
2173                 case OP_IA64_BR_COND: {
2174                         int pred = 0;
2175                         if (ins->opcode == OP_IA64_BR_COND)
2176                                 pred = 6;
2177                         if (ins->flags & MONO_INST_BRLABEL) {
2178                                 if (ins->inst_i0->inst_c0) {
2179                                         NOT_IMPLEMENTED;
2180                                 } else {
2181                                         add_patch_info (cfg, code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2182                                         ia64_br_cond_pred (code, pred, 0);
2183                                 }
2184                         } else {
2185                                 if (ins->inst_target_bb->native_offset) {
2186                                         guint8 *pos = code.buf + code.nins;
2187
2188                                         ia64_br_cond_pred (code, pred, 0);
2189                                         ia64_begin_bundle (code);
2190                                         ia64_patch (pos, cfg->native_code + ins->inst_target_bb->native_offset);
2191                                 } else {
2192                                         add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2193                                         ia64_br_cond_pred (code, pred, 0);
2194                                 } 
2195                         }
2196                         break;
2197                 }
2198                 case OP_LABEL:
2199                         ia64_begin_bundle (code);
2200                         ins->inst_c0 = code.buf - cfg->native_code;
2201                         break;
2202                 case OP_NOP:
2203                         break;
2204                 case OP_BR_REG:
2205                         ia64_mov_to_br (code, IA64_B6, ins->sreg1);
2206                         ia64_br_cond_reg (code, IA64_B6);
2207                         break;
2208                 case CEE_ADD:
2209                 case OP_IADD:
2210                         ia64_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2211                         break;
2212                 case CEE_AND:
2213                 case OP_IAND:
2214                         ia64_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2215                         break;
2216                 case OP_IOR:
2217                 case CEE_OR:
2218                         ia64_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2219                         break;
2220                 case OP_IXOR:
2221                 case CEE_XOR:
2222                         ia64_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2223                         break;
2224                 case OP_INEG:
2225                 case CEE_NEG:
2226                         ia64_sub (code, ins->dreg, IA64_R0, ins->sreg1);
2227                         break;
2228                 case OP_INOT:
2229                 case CEE_NOT:
2230                         ia64_andcm_imm (code, ins->dreg, -1, ins->sreg1);
2231                         break;
2232                 case OP_ISHL:
2233                         ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2234                         break;
2235                 case OP_ISHR:
2236                 case OP_LSHR:
2237                         ia64_shr (code, ins->dreg, ins->sreg1, ins->sreg2);
2238                         break;
2239                 case OP_ISHR_UN:
2240                         ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2241                         ia64_shr_u (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2242                         break;
2243                 case CEE_SHL:
2244                 case OP_LSHL:
2245                         ia64_shl (code, ins->dreg, ins->sreg1, ins->sreg2);
2246                         break;
2247                 case OP_LSHR_UN:
2248                         ia64_shr_u (code, ins->dreg, ins->sreg1, ins->sreg2);
2249                         break;
2250                 case CEE_SUB:
2251                 case OP_ISUB:
2252                         ia64_sub (code, ins->dreg, ins->sreg1, ins->sreg2);
2253                         break;
2254                 case OP_IADDCC:
2255                         /* p6 and p7 is set if there is signed/unsigned overflow */
2256                         
2257                         /* Set p8-p9 == (sreg2 > 0) */
2258                         ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2259
2260                         ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2261                         
2262                         /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2263                         ia64_cmp4_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2264                         /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2265                         ia64_cmp4_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2266
2267                         /* res <u sreg1 => unsigned overflow */
2268                         ia64_cmp4_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2269
2270                         /* FIXME: Predicate this since this is a side effect */
2271                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2272                         break;
2273                 case OP_ISUBCC:
2274                         /* p6 and p7 is set if there is signed/unsigned overflow */
2275                         
2276                         /* Set p8-p9 == (sreg2 > 0) */
2277                         ia64_cmp4_lt (code, 8, 9, IA64_R0, ins->sreg2);
2278
2279                         ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2280                         
2281                         /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2282                         ia64_cmp4_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2283                         /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2284                         ia64_cmp4_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2285
2286                         /* sreg1 <u sreg2 => unsigned overflow */
2287                         ia64_cmp4_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2288
2289                         /* FIXME: Predicate this since this is a side effect */
2290                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2291                         break;
2292                 case OP_ADDCC:
2293                         /* Same as OP_IADDCC */
2294                         ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2295
2296                         ia64_add (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2297                         
2298                         ia64_cmp_lt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2299                         ia64_cmp_lt_pred (code, 9, 6, 10, ins->sreg1, GP_SCRATCH_REG);
2300
2301                         ia64_cmp_ltu (code, 7, 10, GP_SCRATCH_REG, ins->sreg1);
2302
2303                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2304                         break;
2305                 case OP_SUBCC:
2306                         /* Same as OP_ISUBCC */
2307
2308                         ia64_cmp_lt (code, 8, 9, IA64_R0, ins->sreg2);
2309
2310                         ia64_sub (code, GP_SCRATCH_REG, ins->sreg1, ins->sreg2);
2311                         
2312                         ia64_cmp_gt_pred (code, 8, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2313                         ia64_cmp_lt_pred (code, 9, 6, 10, GP_SCRATCH_REG, ins->sreg1);
2314
2315                         ia64_cmp_ltu (code, 7, 10, ins->sreg1, ins->sreg2);
2316
2317                         ia64_mov (code, ins->dreg, GP_SCRATCH_REG);
2318                         break;
2319                 case OP_ADD_IMM:
2320                 case OP_IADD_IMM:
2321                         ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2322                         break;
2323                 case OP_IAND_IMM:
2324                 case OP_AND_IMM:
2325                         ia64_and_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2326                         break;
2327                 case OP_IOR_IMM:
2328                         ia64_or_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2329                         break;
2330                 case OP_IXOR_IMM:
2331                         ia64_xor_imm (code, ins->dreg, ins->inst_imm, ins->sreg1);
2332                         break;
2333                 case OP_SHL_IMM:
2334                 case OP_ISHL_IMM:
2335                 case OP_LSHL_IMM:
2336                         ia64_shl_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2337                         break;
2338                 case OP_SHR_IMM:
2339                 case OP_ISHR_IMM:
2340                 case OP_LSHR_IMM:
2341                         ia64_shr_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2342                         break;
2343                 case OP_ISHR_UN_IMM:
2344                         ia64_zxt4 (code, GP_SCRATCH_REG, ins->sreg1);
2345                         ia64_shr_u_imm (code, ins->dreg, GP_SCRATCH_REG, ins->inst_imm);
2346                         break;
2347                 case OP_LSHR_UN_IMM:
2348                         ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2349                         break;
2350                 case CEE_MUL:
2351                         /* Based on gcc code */
2352                         ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
2353                         ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
2354                         ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
2355                         ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2356                         break;
2357
2358                 case OP_STOREI1_MEMBASE_REG:
2359                         ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2360                         break;
2361                 case OP_STOREI2_MEMBASE_REG:
2362                         ia64_st2_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2363                         break;
2364                 case OP_STOREI4_MEMBASE_REG:
2365                         ia64_st4_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2366                         break;
2367                 case OP_STOREI8_MEMBASE_REG:
2368                 case OP_STORE_MEMBASE_REG:
2369                         ia64_st8_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2370                         break;
2371
2372                 case OP_IA64_STOREI1_MEMBASE_INC_REG:
2373                         ia64_st1_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 1, 0);
2374                         break;
2375                 case OP_IA64_STOREI2_MEMBASE_INC_REG:
2376                         ia64_st2_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 2, 0);
2377                         break;
2378                 case OP_IA64_STOREI4_MEMBASE_INC_REG:
2379                         ia64_st4_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 4, 0);
2380                         break;
2381                 case OP_IA64_STOREI8_MEMBASE_INC_REG:
2382                         ia64_st8_inc_imm_hint (code, ins->inst_destbasereg, ins->sreg1, 8, 0);
2383                         break;
2384
2385                 case OP_LOADU1_MEMBASE:
2386                         ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2387                         break;
2388                 case OP_LOADU2_MEMBASE:
2389                         ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2390                         break;
2391                 case OP_LOADU4_MEMBASE:
2392                         ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2393                         break;
2394                 case OP_LOADI1_MEMBASE:
2395                         ia64_ld1 (code, ins->dreg, ins->inst_basereg);
2396                         ia64_sxt1 (code, ins->dreg, ins->dreg);
2397                         break;
2398                 case OP_LOADI2_MEMBASE:
2399                         ia64_ld2 (code, ins->dreg, ins->inst_basereg);
2400                         ia64_sxt2 (code, ins->dreg, ins->dreg);
2401                         break;
2402                 case OP_LOADI4_MEMBASE:
2403                         ia64_ld4 (code, ins->dreg, ins->inst_basereg);
2404                         ia64_sxt4 (code, ins->dreg, ins->dreg);
2405                         break;
2406                 case OP_LOAD_MEMBASE:
2407                 case OP_LOADI8_MEMBASE:
2408                         ia64_ld8 (code, ins->dreg, ins->inst_basereg);
2409                         break;
2410
2411                 case OP_IA64_LOADU1_MEMBASE_INC:
2412                         ia64_ld1_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 1, 0);
2413                         break;
2414                 case OP_IA64_LOADU2_MEMBASE_INC:
2415                         ia64_ld2_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 2, 0);
2416                         break;
2417                 case OP_IA64_LOADU4_MEMBASE_INC:
2418                         ia64_ld4_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 4, 0);
2419                         break;
2420                 case OP_IA64_LOADI8_MEMBASE_INC:
2421                         ia64_ld8_inc_imm_hint (code, ins->dreg, ins->inst_basereg, 8, 0);
2422                         break;
2423
2424                 case OP_SEXT_I1:
2425                         ia64_sxt1 (code, ins->dreg, ins->sreg1);
2426                         break;
2427                 case OP_SEXT_I2:
2428                         ia64_sxt2 (code, ins->dreg, ins->sreg1);
2429                         break;
2430                 case OP_SEXT_I4:
2431                         ia64_sxt4 (code, ins->dreg, ins->sreg1);
2432                         break;
2433                 case OP_ZEXT_I1:
2434                         ia64_zxt1 (code, ins->dreg, ins->sreg1);
2435                         break;
2436                 case OP_ZEXT_I2:
2437                         ia64_zxt2 (code, ins->dreg, ins->sreg1);
2438                         break;
2439                 case OP_ZEXT_I4:
2440                         ia64_zxt4 (code, ins->dreg, ins->sreg1);
2441                         break;
2442
2443                         /* Compare opcodes */
2444                 case OP_IA64_CMP4_EQ:
2445                         ia64_cmp4_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2446                         break;
2447                 case OP_IA64_CMP4_NE:
2448                         ia64_cmp4_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2449                         break;
2450                 case OP_IA64_CMP4_LE:
2451                         ia64_cmp4_le (code, 6, 7, ins->sreg1, ins->sreg2);
2452                         break;
2453                 case OP_IA64_CMP4_LT:
2454                         ia64_cmp4_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2455                         break;
2456                 case OP_IA64_CMP4_GE:
2457                         ia64_cmp4_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2458                         break;
2459                 case OP_IA64_CMP4_GT:
2460                         ia64_cmp4_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2461                         break;
2462                 case OP_IA64_CMP4_LT_UN:
2463                         ia64_cmp4_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2464                         break;
2465                 case OP_IA64_CMP4_LE_UN:
2466                         ia64_cmp4_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2467                         break;
2468                 case OP_IA64_CMP4_GT_UN:
2469                         ia64_cmp4_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2470                         break;
2471                 case OP_IA64_CMP4_GE_UN:
2472                         ia64_cmp4_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2473                         break;
2474                 case OP_IA64_CMP_EQ:
2475                         ia64_cmp_eq (code, 6, 7, ins->sreg1, ins->sreg2);
2476                         break;
2477                 case OP_IA64_CMP_NE:
2478                         ia64_cmp_ne (code, 6, 7, ins->sreg1, ins->sreg2);
2479                         break;
2480                 case OP_IA64_CMP_LE:
2481                         ia64_cmp_le (code, 6, 7, ins->sreg1, ins->sreg2);
2482                         break;
2483                 case OP_IA64_CMP_LT:
2484                         ia64_cmp_lt (code, 6, 7, ins->sreg1, ins->sreg2);
2485                         break;
2486                 case OP_IA64_CMP_GE:
2487                         ia64_cmp_ge (code, 6, 7, ins->sreg1, ins->sreg2);
2488                         break;
2489                 case OP_IA64_CMP_GT:
2490                         ia64_cmp_gt (code, 6, 7, ins->sreg1, ins->sreg2);
2491                         break;
2492                 case OP_IA64_CMP_GT_UN:
2493                         ia64_cmp_gtu (code, 6, 7, ins->sreg1, ins->sreg2);
2494                         break;
2495                 case OP_IA64_CMP_LT_UN:
2496                         ia64_cmp_ltu (code, 6, 7, ins->sreg1, ins->sreg2);
2497                         break;
2498                 case OP_IA64_CMP_GE_UN:
2499                         ia64_cmp_geu (code, 6, 7, ins->sreg1, ins->sreg2);
2500                         break;
2501                 case OP_IA64_CMP_LE_UN:
2502                         ia64_cmp_leu (code, 6, 7, ins->sreg1, ins->sreg2);
2503                         break;
2504                 case OP_IA64_CMP4_EQ_IMM:
2505                         ia64_cmp4_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2506                         break;
2507                 case OP_IA64_CMP4_NE_IMM:
2508                         ia64_cmp4_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2509                         break;
2510                 case OP_IA64_CMP4_LE_IMM:
2511                         ia64_cmp4_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2512                         break;
2513                 case OP_IA64_CMP4_LT_IMM:
2514                         ia64_cmp4_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2515                         break;
2516                 case OP_IA64_CMP4_GE_IMM:
2517                         ia64_cmp4_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2518                         break;
2519                 case OP_IA64_CMP4_GT_IMM:
2520                         ia64_cmp4_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2521                         break;
2522                 case OP_IA64_CMP4_LT_UN_IMM:
2523                         ia64_cmp4_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2524                         break;
2525                 case OP_IA64_CMP4_LE_UN_IMM:
2526                         ia64_cmp4_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2527                         break;
2528                 case OP_IA64_CMP4_GT_UN_IMM:
2529                         ia64_cmp4_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2530                         break;
2531                 case OP_IA64_CMP4_GE_UN_IMM:
2532                         ia64_cmp4_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2533                         break;
2534                 case OP_IA64_CMP_EQ_IMM:
2535                         ia64_cmp_eq_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2536                         break;
2537                 case OP_IA64_CMP_NE_IMM:
2538                         ia64_cmp_ne_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2539                         break;
2540                 case OP_IA64_CMP_LE_IMM:
2541                         ia64_cmp_le_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2542                         break;
2543                 case OP_IA64_CMP_LT_IMM:
2544                         ia64_cmp_lt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2545                         break;
2546                 case OP_IA64_CMP_GE_IMM:
2547                         ia64_cmp_ge_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2548                         break;
2549                 case OP_IA64_CMP_GT_IMM:
2550                         ia64_cmp_gt_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2551                         break;
2552                 case OP_IA64_CMP_GT_UN_IMM:
2553                         ia64_cmp_gtu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2554                         break;
2555                 case OP_IA64_CMP_LT_UN_IMM:
2556                         ia64_cmp_ltu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2557                         break;
2558                 case OP_IA64_CMP_GE_UN_IMM:
2559                         ia64_cmp_geu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2560                         break;
2561                 case OP_IA64_CMP_LE_UN_IMM:
2562                         ia64_cmp_leu_imm (code, 6, 7, ins->inst_imm, ins->sreg2);
2563                         break;
2564                 case OP_IA64_FCMP_EQ:
2565                         ia64_fcmp_eq_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2566                         break;
2567                 case OP_IA64_FCMP_NE:
2568                         ia64_fcmp_ne_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2569                         break;
2570                 case OP_IA64_FCMP_LT:
2571                         ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2572                         break;
2573                 case OP_IA64_FCMP_GT:
2574                         ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2575                         break;
2576                 case OP_IA64_FCMP_LE:
2577                         ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2578                         break;
2579                 case OP_IA64_FCMP_GE:
2580                         ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2581                         break;
2582                 case OP_IA64_FCMP_GT_UN:
2583                         ia64_fcmp_gt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2584                         ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2585                         break;
2586                 case OP_IA64_FCMP_LT_UN:
2587                         ia64_fcmp_lt_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2588                         ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2589                         break;
2590                 case OP_IA64_FCMP_GE_UN:
2591                         ia64_fcmp_ge_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2592                         ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2593                         break;
2594                 case OP_IA64_FCMP_LE_UN:
2595                         ia64_fcmp_le_sf (code, 6, 7, ins->sreg1, ins->sreg2, 0);
2596                         ia64_fcmp_unord_sf_pred (code, 7, 6, 7, ins->sreg1, ins->sreg2, 0);
2597                         break;
2598
2599                 case OP_COND_EXC_IOV:
2600                 case OP_COND_EXC_OV:
2601                         emit_cond_system_exception (cfg, code, "OverflowException", 6);
2602                         break;
2603                 case OP_COND_EXC_IC:
2604                 case OP_COND_EXC_C:
2605                         emit_cond_system_exception (cfg, code, "OverflowException", 7);
2606                         break;
2607                 case OP_IA64_COND_EXC:
2608                         emit_cond_system_exception (cfg, code, ins->inst_p1, 6);
2609                         break;
2610                 case OP_IA64_CSET:
2611                         ia64_mov_pred (code, 7, ins->dreg, IA64_R0);
2612                         ia64_no_stop (code);
2613                         ia64_add1_pred (code, 6, ins->dreg, IA64_R0, IA64_R0);
2614                         break;
2615                 case CEE_CONV_I1:
2616                         /* FIXME: Is this needed ? */
2617                         ia64_sxt1 (code, ins->dreg, ins->sreg1);
2618                         break;
2619                 case CEE_CONV_I2:
2620                         /* FIXME: Is this needed ? */
2621                         ia64_sxt2 (code, ins->dreg, ins->sreg1);
2622                         break;
2623                 case CEE_CONV_I4:
2624                         /* FIXME: Is this needed ? */
2625                         ia64_sxt4 (code, ins->dreg, ins->sreg1);
2626                         break;
2627                 case CEE_CONV_U1:
2628                         /* FIXME: Is this needed */
2629                         ia64_zxt1 (code, ins->dreg, ins->sreg1);
2630                         break;
2631                 case CEE_CONV_U2:
2632                         /* FIXME: Is this needed */
2633                         ia64_zxt2 (code, ins->dreg, ins->sreg1);
2634                         break;
2635                 case CEE_CONV_U4:
2636                         /* FIXME: Is this needed */
2637                         ia64_zxt4 (code, ins->dreg, ins->sreg1);
2638                         break;
2639                 case CEE_CONV_I8:
2640                 case CEE_CONV_I:
2641                         ia64_sxt4 (code, ins->dreg, ins->sreg1);
2642                         break;
2643                 case CEE_CONV_U8:
2644                 case CEE_CONV_U:
2645                         ia64_zxt4 (code, ins->dreg, ins->sreg1);
2646                         break;
2647
2648                         /*
2649                          * FLOAT OPCODES
2650                          */
2651                 case OP_R8CONST: {
2652                         double d = *(double *)ins->inst_p0;
2653
2654                         if ((d == 0.0) && (mono_signbit (d) == 0))
2655                                 ia64_fmov (code, ins->dreg, 0);
2656                         else if (d == 1.0)
2657                                 ia64_fmov (code, ins->dreg, 1);
2658                         else {
2659                                 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2660                                 ia64_movl (code, GP_SCRATCH_REG, 0);
2661                                 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2662                         }
2663                         break;
2664                 }
2665                 case OP_R4CONST: {
2666                         float f = *(float *)ins->inst_p0;
2667
2668                         if ((f == 0.0) && (mono_signbit (f) == 0))
2669                                 ia64_fmov (code, ins->dreg, 0);
2670                         else if (f == 1.0)
2671                                 ia64_fmov (code, ins->dreg, 1);
2672                         else {
2673                                 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2674                                 ia64_movl (code, GP_SCRATCH_REG, 0);
2675                                 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2676                         }
2677                         break;
2678                 }
2679                 case OP_FMOVE:
2680                         ia64_fmov (code, ins->dreg, ins->sreg1);
2681                         break;
2682                 case OP_STORER8_MEMBASE_REG:
2683                         ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2684                         break;
2685                 case OP_STORER4_MEMBASE_REG:
2686                         ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2687                         ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2688                         break;
2689                 case OP_LOADR8_MEMBASE:
2690                         ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2691                         break;
2692                 case OP_LOADR4_MEMBASE:
2693                         ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2694                         ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2695                         break;
2696                 case CEE_CONV_R4:
2697                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2698                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2699                         ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2700                         break;
2701                 case CEE_CONV_R8:
2702                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2703                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2704                         ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2705                         break;
2706                 case OP_LCONV_TO_R8:
2707                         /* FIXME: Difference with CEE_CONV_R8 ? */
2708                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2709                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2710                         ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2711                         break;
2712                 case OP_LCONV_TO_R4:
2713                         /* FIXME: Difference with CEE_CONV_R4 ? */
2714                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2715                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2716                         ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2717                         break;
2718                 case OP_FCONV_TO_R4:
2719                         ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2720                         break;
2721                 case OP_FCONV_TO_I8:
2722                         ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2723                         ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2724                         break;
2725                 case OP_FADD:
2726                         ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2727                         break;
2728                 case OP_FSUB:
2729                         ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2730                         break;
2731                 case OP_FMUL:
2732                         ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2733                         break;
2734                 case OP_FNEG:
2735                         ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2736                         break;
2737                 case OP_CKFINITE:
2738                         /* Quiet NaN */
2739                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2740                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2741                         /* Signaling NaN */
2742                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2743                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2744                         /* Positive infinity */
2745                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2746                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2747                         /* Negative infinity */
2748                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2749                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2750                         break;
2751
2752                 /* Calls */
2753                 case OP_CHECK_THIS:
2754                         /* ensure ins->sreg1 is not NULL */
2755                         ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2756                         break;
2757                 case OP_ARGLIST:
2758                         ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2759                         ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2760                         break;
2761                 case OP_FCALL:
2762                 case OP_LCALL:
2763                 case OP_VCALL:
2764                 case OP_VOIDCALL:
2765                 case CEE_CALL:
2766                         call = (MonoCallInst*)ins;
2767
2768                         if (ins->flags & MONO_INST_HAS_METHOD)
2769                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2770                         else
2771                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2772
2773                         code = emit_move_return_value (cfg, ins, code);
2774                         break;
2775
2776                 case OP_CALL_REG:
2777                 case OP_FCALL_REG:
2778                 case OP_LCALL_REG:
2779                 case OP_VCALL_REG:
2780                 case OP_VOIDCALL_REG:
2781                         call = (MonoCallInst*)ins;
2782
2783                         /* Indirect call */
2784                         /* 
2785                          * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is 
2786                          * used.
2787                          */
2788                         ia64_mov (code, IA64_R8, ins->sreg1);
2789                         ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2790                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2791                         ia64_ld8 (code, IA64_GP, IA64_R8);
2792                         ia64_br_call_reg (code, IA64_B0, IA64_B6);
2793
2794                         code = emit_move_return_value (cfg, ins, code);
2795                         break;
2796
2797                 case OP_FCALL_MEMBASE:
2798                 case OP_LCALL_MEMBASE:
2799                 case OP_VCALL_MEMBASE:
2800                 case OP_VOIDCALL_MEMBASE:
2801                 case OP_CALL_MEMBASE: {
2802                         MonoCallInst *call = (MonoCallInst*)ins;
2803                         CallInfo *cinfo;
2804                         int out_reg;
2805
2806                         /* 
2807                          * There are no membase instructions on ia64, but we can't 
2808                          * lower this since get_vcall_slot_addr () needs to decode it.
2809                          */
2810
2811                         /* Keep this in synch with get_vcall_slot_addr */
2812                         ia64_mov (code, IA64_R11, ins->sreg1);
2813                         if (ia64_is_imm14 (ins->inst_offset))
2814                                 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2815                         else {
2816                                 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2817                                 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2818                         }
2819
2820                         if (call->method && ins->inst_offset < 0) {
2821                                 /* 
2822                                  * This is a possible IMT call so save the IMT method in a global 
2823                                  * register where mono_arch_find_imt_method () and its friends can access 
2824                                  * it.
2825                                  */
2826                                 ia64_movl (code, IA64_R9, call->method);
2827                         }
2828
2829                         /* 
2830                          * mono_arch_find_this_arg () needs to find the this argument in a global 
2831                          * register.
2832                          */
2833                         cinfo = get_call_info (cfg, cfg->mempool, call->signature, FALSE);
2834                         out_reg = cfg->arch.reg_out0;
2835                         if (cinfo->ret.storage == ArgValuetypeAddrInIReg)
2836                                 out_reg ++;
2837                         ia64_mov (code, IA64_R10, out_reg);
2838
2839                         ia64_begin_bundle (code);
2840                         ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2841
2842                         ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2843
2844                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2845
2846                         /*
2847                          * This nop will tell get_vcall_slot_addr that this is a virtual 
2848                          * call.
2849                          */
2850                         ia64_nop_i (code, 0x12345);
2851
2852                         ia64_br_call_reg (code, IA64_B0, IA64_B6);
2853
2854                         ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2855
2856                         code = emit_move_return_value (cfg, ins, code);
2857                         break;
2858                 }
2859                 case OP_JMP: {
2860                         /*
2861                          * Keep in sync with the code in emit_epilog.
2862                          */
2863
2864                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2865                                 NOT_IMPLEMENTED;
2866
2867                         g_assert (!cfg->method->save_lmf);
2868
2869                         /* Load arguments into their original registers */
2870                         code = emit_load_volatile_arguments (cfg, code);
2871
2872                         if (cfg->arch.stack_alloc_size) {
2873                                 if (cfg->arch.omit_fp) {
2874                                         if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2875                                                 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2876                                         else {
2877                                                 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2878                                                 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2879                                         }
2880                                 }
2881                                 else
2882                                         ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2883                         }
2884                         ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2885                         ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2886
2887                         add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2888                         ia64_movl (code, GP_SCRATCH_REG, 0);
2889                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2890                         ia64_br_cond_reg (code, IA64_B6);
2891
2892                         break;
2893                 }
2894                 case OP_BREAK:
2895                         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2896                         break;
2897
2898                 case OP_LOCALLOC: {
2899                         gint32 abi_offset;
2900
2901                         /* FIXME: Sigaltstack support */
2902
2903                         /* keep alignment */
2904                         ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2905                         ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2906                         ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2907
2908                         ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2909
2910                         ia64_mov (code, ins->dreg, IA64_SP);
2911
2912                         /* An area at sp is reserved by the ABI for parameter passing */
2913                         abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2914                         if (ia64_is_adds_imm (abi_offset))
2915                                 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2916                         else {
2917                                 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2918                                 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2919                         }
2920
2921                         if (ins->flags & MONO_INST_INIT) {
2922                                 /* Upper limit */
2923                                 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2924
2925                                 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2926
2927                                 /* Init loop */
2928                                 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2929                                 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2930                                 ia64_br_cond_pred (code, 8, -2);
2931
2932                                 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2933
2934                                 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2935                         }
2936
2937                         break;
2938                 }
2939                 case OP_TLS_GET:
2940                         ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2941                         ia64_ld8 (code, ins->dreg, ins->dreg);
2942                         break;
2943
2944                         /* Synchronization */
2945                 case OP_MEMORY_BARRIER:
2946                         ia64_mf (code);
2947                         break;
2948                 case OP_ATOMIC_ADD_IMM_NEW_I4:
2949                         g_assert (ins->inst_offset == 0);
2950                         ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2951                         ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2952                         break;
2953                 case OP_ATOMIC_ADD_IMM_NEW_I8:
2954                         g_assert (ins->inst_offset == 0);
2955                         ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2956                         ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2957                         break;
2958                 case OP_ATOMIC_EXCHANGE_I4:
2959                         ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2960                         ia64_sxt4 (code, ins->dreg, ins->dreg);
2961                         break;
2962                 case OP_ATOMIC_EXCHANGE_I8:
2963                         ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2964                         break;
2965                 case OP_ATOMIC_ADD_NEW_I4: {
2966                         guint8 *label, *buf;
2967
2968                         /* From libatomic_ops */
2969                         ia64_mf (code);
2970
2971                         ia64_begin_bundle (code);
2972                         label = code.buf + code.nins;
2973                         ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2974                         ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2975                         ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2976                         ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2977                         ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2978                         buf = code.buf + code.nins;
2979                         ia64_br_cond_pred (code, 7, 0);
2980                         ia64_begin_bundle (code);
2981                         ia64_patch (buf, label);
2982                         ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2983                         break;
2984                 }
2985                 case OP_ATOMIC_ADD_NEW_I8: {
2986                         guint8 *label, *buf;
2987
2988                         /* From libatomic_ops */
2989                         ia64_mf (code);
2990
2991                         ia64_begin_bundle (code);
2992                         label = code.buf + code.nins;
2993                         ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2994                         ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2995                         ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2996                         ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2997                         ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2998                         buf = code.buf + code.nins;
2999                         ia64_br_cond_pred (code, 7, 0);
3000                         ia64_begin_bundle (code);
3001                         ia64_patch (buf, label);
3002                         ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
3003                         break;
3004                 }
3005
3006                         /* Exception handling */
3007                 case OP_CALL_HANDLER:
3008                         /*
3009                          * Using a call instruction would mess up the register stack, so
3010                          * save the return address to a register and use a
3011                          * branch.
3012                          */
3013                         ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3014                         ia64_mov (code, IA64_R15, IA64_R0);
3015                         ia64_mov_from_ip (code, GP_SCRATCH_REG);
3016                         /* Add the length of OP_CALL_HANDLER */
3017                         ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
3018                         add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3019                         ia64_movl (code, GP_SCRATCH_REG2, 0);
3020                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
3021                         ia64_br_cond_reg (code, IA64_B6);
3022                         ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3023                         break;
3024                 case OP_START_HANDLER: {
3025                         /*
3026                          * We receive the return address in GP_SCRATCH_REG.
3027                          */
3028                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3029
3030                         /* 
3031                          * R15 determines our caller. It is used since it is writable using
3032                          * libunwind.
3033                          * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3034                          * R15 != 0 means we are called by call_filter ().
3035                          */
3036                         ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3037                         ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3038
3039                         ia64_br_cond_pred (code, 6, 6);
3040
3041                         /*
3042                          * Called by call_filter:
3043                          * Allocate a new stack frame, and set the fp register from the 
3044                          * value passed in by the caller.
3045                          * We allocate a similar frame as is done by the prolog, so
3046                          * if an exception is thrown while executing the filter, the
3047                          * unwinder can unwind through the filter frame using the unwind
3048                          * info for the prolog. 
3049                          */
3050                         ia64_alloc (code, cfg->arch.reg_saved_ar_pfs, cfg->arch.reg_local0 - cfg->arch.reg_in0, cfg->arch.reg_out0 - cfg->arch.reg_local0, cfg->arch.n_out_regs, 0);
3051                         ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3052                         ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3053                         ia64_mov (code, cfg->frame_reg, IA64_R15);
3054                         /* Signal to endfilter that we are called by call_filter */
3055                         ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3056
3057                         /* Save the return address */
3058                         ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3059                         ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3060                         ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3061
3062                         break;
3063                 }
3064                 case OP_ENDFINALLY:
3065                 case OP_ENDFILTER: {
3066                         /* FIXME: Return the value in ENDFILTER */
3067                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3068
3069                         /* Load the return address */
3070                         ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3071                         ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3072
3073                         /* Test caller */
3074                         ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3075                         ia64_br_cond_pred (code, 7, 4);
3076
3077                         /* Called by call_filter */
3078                         /* Pop frame */
3079                         ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3080                         ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3081                         ia64_br_ret_reg (code, IA64_B0);                        
3082
3083                         /* Called by CALL_HANDLER */
3084                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3085                         ia64_br_cond_reg (code, IA64_B6);
3086                         break;
3087                 }
3088                 case OP_THROW:
3089                         ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3090                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3091                                                           (gpointer)"mono_arch_throw_exception");
3092
3093                         /* 
3094                          * This might be the last instruction in the method, so add a dummy
3095                          * instruction so the unwinder will work.
3096                          */
3097                         ia64_break_i (code, 0);
3098                         break;
3099                 case OP_RETHROW:
3100                         ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3101                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3102                                                           (gpointer)"mono_arch_rethrow_exception");
3103
3104                         ia64_break_i (code, 0);
3105                         break;
3106
3107                 default:
3108                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3109                         g_assert_not_reached ();
3110                 }
3111
3112                 if ((code.buf - cfg->native_code - offset) > max_len) {
3113                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3114                                    mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3115                         g_assert_not_reached ();
3116                 }
3117                
3118                 cpos += max_len;
3119
3120                 last_ins = ins;
3121                 last_offset = offset;
3122                 
3123                 ins = ins->next;
3124         }
3125
3126         ia64_codegen_close (code);
3127
3128         cfg->code_len = code.buf - cfg->native_code;
3129 }
3130
3131 void
3132 mono_arch_register_lowlevel_calls (void)
3133 {
3134         mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3135 }
3136
3137 static Ia64InsType ins_types_in_template [32][3] = {
3138         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3139         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3140         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3141         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
3142         {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3143         {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3144         {0, 0, 0},
3145         {0, 0, 0},
3146         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3147         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3148         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3149         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
3150         {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3151         {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_I},
3152         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3153         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3154         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3155         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3156         {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3157         {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3158         {0, 0, 0},
3159         {0, 0, 0},
3160         {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3161         {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3162         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3163         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3164         {0, 0, 0},
3165         {0, 0, 0},
3166         {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3167         {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3168         {0, 0, 0},
3169         {0, 0, 0}
3170 };
3171
3172 static gboolean stops_in_template [32][3] = {
3173         { FALSE, FALSE, FALSE },
3174         { FALSE, FALSE, TRUE },
3175         { FALSE, TRUE, FALSE },
3176         { FALSE, TRUE, TRUE },
3177         { FALSE, FALSE, FALSE },
3178         { FALSE, FALSE, TRUE },
3179         { FALSE, FALSE, FALSE },
3180         { FALSE, FALSE, FALSE },
3181
3182         { FALSE, FALSE, FALSE },
3183         { FALSE, FALSE, TRUE },
3184         { TRUE, FALSE, FALSE },
3185         { TRUE, FALSE, TRUE },
3186         { FALSE, FALSE, FALSE },
3187         { FALSE, FALSE, TRUE },
3188         { FALSE, FALSE, FALSE },
3189         { FALSE, FALSE, TRUE },
3190
3191         { FALSE, FALSE, FALSE },
3192         { FALSE, FALSE, TRUE },
3193         { FALSE, FALSE, FALSE },
3194         { FALSE, FALSE, TRUE },
3195         { FALSE, FALSE, FALSE },
3196         { FALSE, FALSE, FALSE },
3197         { FALSE, FALSE, FALSE },
3198         { FALSE, FALSE, TRUE },
3199
3200         { FALSE, FALSE, FALSE },
3201         { FALSE, FALSE, TRUE },
3202         { FALSE, FALSE, FALSE },
3203         { FALSE, FALSE, FALSE },
3204         { FALSE, FALSE, FALSE },
3205         { FALSE, FALSE, TRUE },
3206         { FALSE, FALSE, FALSE },
3207         { FALSE, FALSE, FALSE }
3208 };
3209
3210 static int last_stop_in_template [32] = {
3211         -1, 2, 1, 2, -1, 2, -1, -1,
3212         -1, 2, 0, 2, -1, 2, -1, 2,
3213         -1, 2, -1, 2, -1, -1, -1, 2,
3214         -1, 2, -1, -1, -1, 2, -1, -1
3215 };
3216
3217 static guint64 nops_for_ins_types [6] = {
3218         IA64_NOP_I,
3219         IA64_NOP_I,
3220         IA64_NOP_M,
3221         IA64_NOP_F,
3222         IA64_NOP_B,
3223         IA64_NOP_X
3224 };
3225
3226 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3227
3228 /* 
3229  * Debugging support
3230  */
3231
3232 #if 0
3233 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3234 #else
3235 #define DEBUG_INS_SCHED(a)
3236 #endif
3237
3238 static void
3239 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3240 {
3241         int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3242         guint8 *deps = code->dep_info;
3243         gboolean need_stop, no_stop;
3244
3245         for (i = 0; i < code->nins; ++i)
3246                 stops [i] = FALSE;
3247         
3248         ins_index = 0;
3249         current_deps_start = 0;
3250         current_ins_start = 0;
3251         deps_start [ins_index] = current_ins_start;
3252         pos = 0;
3253         no_stop = FALSE;
3254         DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3255         while (pos < code->dep_info_pos) {
3256                 need_stop = FALSE;
3257                 switch (deps [pos]) {
3258                 case IA64_END_OF_INS:
3259                         ins_index ++;
3260                         current_ins_start = pos + 2;
3261                         deps_start [ins_index] = current_ins_start;
3262                         no_stop = FALSE;
3263                         DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3264                         break;
3265                 case IA64_NONE:
3266                         break;
3267                 case IA64_READ_GR:
3268                         reg = deps [pos + 1];
3269
3270                         DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3271                         for (i = current_deps_start; i < current_ins_start; i += 2)
3272                                 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3273                                         need_stop = TRUE;
3274                         break;
3275                 case IA64_WRITE_GR:
3276                         reg = code->dep_info [pos + 1];
3277
3278                         DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3279                         for (i = current_deps_start; i < current_ins_start; i += 2)
3280                                 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3281                                         need_stop = TRUE;
3282                         break;
3283                 case IA64_READ_PR:
3284                         reg = deps [pos + 1];
3285
3286                         DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3287                         for (i = current_deps_start; i < current_ins_start; i += 2)
3288                                 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3289                                         need_stop = TRUE;
3290                         break;
3291                 case IA64_READ_PR_BRANCH:
3292                         reg = deps [pos + 1];
3293
3294                         /* Writes to prs by non-float instructions are visible to branches */
3295                         DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3296                         for (i = current_deps_start; i < current_ins_start; i += 2)
3297                                 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3298                                         need_stop = TRUE;
3299                         break;
3300                 case IA64_WRITE_PR:
3301                         reg = code->dep_info [pos + 1];
3302
3303                         DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3304                         for (i = current_deps_start; i < current_ins_start; i += 2)
3305                                 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3306                                         need_stop = TRUE;
3307                         break;
3308                 case IA64_WRITE_PR_FLOAT:
3309                         reg = code->dep_info [pos + 1];
3310
3311                         DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3312                         for (i = current_deps_start; i < current_ins_start; i += 2)
3313                                 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3314                                         need_stop = TRUE;
3315                         break;
3316                 case IA64_READ_BR:
3317                         reg = deps [pos + 1];
3318
3319                         DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3320                         for (i = current_deps_start; i < current_ins_start; i += 2)
3321                                 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3322                                         need_stop = TRUE;
3323                         break;
3324                 case IA64_WRITE_BR:
3325                         reg = code->dep_info [pos + 1];
3326
3327                         DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3328                         for (i = current_deps_start; i < current_ins_start; i += 2)
3329                                 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3330                                         need_stop = TRUE;
3331                         break;
3332                 case IA64_READ_BR_BRANCH:
3333                         reg = deps [pos + 1];
3334
3335                         /* Writes to brs are visible to branches */
3336                         DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3337                         break;
3338                 case IA64_READ_FR:
3339                         reg = deps [pos + 1];
3340
3341                         DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3342                         for (i = current_deps_start; i < current_ins_start; i += 2)
3343                                 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3344                                         need_stop = TRUE;
3345                         break;
3346                 case IA64_WRITE_FR:
3347                         reg = code->dep_info [pos + 1];
3348
3349                         DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3350                         for (i = current_deps_start; i < current_ins_start; i += 2)
3351                                 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3352                                         need_stop = TRUE;
3353                         break;
3354                 case IA64_READ_AR:
3355                         reg = deps [pos + 1];
3356
3357                         DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3358                         for (i = current_deps_start; i < current_ins_start; i += 2)
3359                                 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3360                                         need_stop = TRUE;
3361                         break;
3362                 case IA64_WRITE_AR:
3363                         reg = code->dep_info [pos + 1];
3364
3365                         DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3366                         for (i = current_deps_start; i < current_ins_start; i += 2)
3367                                 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3368                                         need_stop = TRUE;
3369                         break;
3370                 case IA64_NO_STOP:
3371                         /* 
3372                          * Explicitly indicate that a stop is not required. Useful for
3373                          * example when two predicated instructions with negated predicates
3374                          * write the same registers.
3375                          */
3376                         no_stop = TRUE;
3377                         break;
3378                 default:
3379                         g_assert_not_reached ();
3380                 }
3381                 pos += 2;
3382
3383                 if (need_stop && !no_stop) {
3384                         g_assert (ins_index > 0);
3385                         stops [ins_index - 1] = 1;
3386
3387                         DEBUG_INS_SCHED (printf ("STOP\n"));
3388                         current_deps_start = current_ins_start;
3389
3390                         /* Skip remaining deps for this instruction */
3391                         while (deps [pos] != IA64_END_OF_INS)
3392                                 pos += 2;
3393                 }
3394         }
3395
3396         if (code->nins > 0) {
3397                 /* No dependency info for the last instruction */
3398                 stops [code->nins - 1] = 1;
3399         }
3400
3401         deps_start [code->nins] = code->dep_info_pos;
3402 }
3403
3404 static void
3405 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3406 {
3407         int stop_pos, i, deps_to_shift, dep_shift;
3408
3409         g_assert (n <= code->nins);
3410
3411         // if (n > 1) printf ("FOUND: %ld.\n", template);
3412
3413         ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3414
3415         stop_pos = last_stop_in_template [template] + 1;
3416         if (stop_pos > n)
3417                 stop_pos = n;
3418
3419         /* Compute the number of 'real' instructions before the stop */
3420         deps_to_shift = stop_pos;
3421         if (stop_pos >= 3 && (nops & (1 << 2)))
3422                 deps_to_shift --;
3423         if (stop_pos >= 2 && (nops & (1 << 1)))
3424                 deps_to_shift --;
3425         if (stop_pos >= 1 && (nops & (1 << 0)))
3426                 deps_to_shift --;
3427
3428         /* 
3429          * We have to keep some dependencies whose instructions have been shifted
3430          * out of the buffer. So nullify the end_of_ins markers in the dependency
3431          * array.
3432          */
3433         for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3434                 if (code->dep_info [i] == IA64_END_OF_INS)
3435                         code->dep_info [i] = IA64_NONE;
3436
3437         g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3438         memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3439         code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3440
3441         dep_shift = deps_start [deps_to_shift];
3442         for (i = 0; i < code->nins + 1 - n; ++i)
3443                 deps_start [i] = deps_start [n + i] - dep_shift;
3444
3445         /* Determine the exact positions of instructions with unwind ops */
3446         if (code->unw_op_count) {
3447                 int ins_pos [16];
3448                 int curr_ins, curr_ins_pos;
3449
3450                 curr_ins = 0;
3451                 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3452                 for (i = 0; i < 3; ++i) {
3453                         if (! (nops & (1 << i))) {
3454                                 ins_pos [curr_ins] = curr_ins_pos + i;
3455                                 curr_ins ++;
3456                         }
3457                 }
3458
3459                 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3460                         if (code->unw_ops_pos [i] < n) {
3461                                 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3462                                 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3463                         }
3464                 }
3465                 if (code->unw_op_pos < code->unw_op_count)
3466                         code->unw_op_pos += n;
3467         }
3468
3469         if (n == code->nins) {
3470                 code->template = 0;
3471                 code->nins = 0;
3472         }               
3473         else {
3474                 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3475                 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3476                 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3477                 code->nins -= n;
3478         }
3479 }
3480
3481 void
3482 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3483 {
3484         int i, ins_type, template, nins_to_emit;
3485         int deps_start [16];
3486         int stops [16];
3487         gboolean found;
3488
3489         /*
3490          * We implement a simple scheduler which tries to put three instructions 
3491          * per bundle, then two, then one.
3492          */
3493         ia64_analyze_deps (code, deps_start, stops);
3494
3495         if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3496                 /* Find a suitable template */
3497                 for (template = 0; template < 32; ++template) {
3498                         if (stops_in_template [template][0] != stops [0] ||
3499                                 stops_in_template [template][1] != stops [1] ||
3500                                 stops_in_template [template][2] != stops [2])
3501                                 continue;
3502
3503                         found = TRUE;
3504                         for (i = 0; i < 3; ++i) {
3505                                 ins_type = ins_types_in_template [template][i];
3506                                 switch (code->itypes [i]) {
3507                                 case IA64_INS_TYPE_A:
3508                                         found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3509                                         break;
3510                                 default:
3511                                         found &= (ins_type == code->itypes [i]);
3512                                         break;
3513                                 }
3514                         }
3515
3516                         if (found)
3517                                 found = debug_ins_sched ();
3518
3519                         if (found) {
3520                                 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3521                                 break;
3522                         }
3523                 }
3524         }
3525
3526         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3527                 /* Wait for more instructions */
3528                 return;
3529
3530         /* If it didn't work out, try putting two instructions into one bundle */
3531         if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3532                 /* Try a nop at the end */
3533                 for (template = 0; template < 32; ++template) {
3534                         if (stops_in_template [template][0] != stops [0] ||
3535                                 ((stops_in_template [template][1] != stops [1]) &&
3536                                  (stops_in_template [template][2] != stops [1])))
3537                                  
3538                                 continue;
3539
3540                         if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3541                                 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3542                                 continue;
3543
3544                         if (!debug_ins_sched ())
3545                                 continue;
3546
3547                         ia64_real_emit_bundle (code, deps_start, stops, 2, template, code->instructions [0], code->instructions [1], nops_for_ins_types [ins_types_in_template [template][2]], 1 << 2);
3548                         break;
3549                 }
3550         }
3551
3552         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3553                 /* Wait for more instructions */
3554                 return;
3555
3556         if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3557                 /* Try a nop in the middle */
3558                 for (template = 0; template < 32; ++template) {
3559                         if (((stops_in_template [template][0] != stops [0]) &&
3560                                  (stops_in_template [template][1] != stops [0])) ||
3561                                 stops_in_template [template][2] != stops [1])
3562                                 continue;
3563
3564                         if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3565                                 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3566                                 continue;
3567
3568                         if (!debug_ins_sched ())
3569                                 continue;
3570
3571                         ia64_real_emit_bundle (code, deps_start, stops, 2, template, code->instructions [0], nops_for_ins_types [ins_types_in_template [template][1]], code->instructions [1], 1 << 1);
3572                         break;
3573                 }
3574         }
3575
3576         if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3577                 /* Try a nop at the beginning */
3578                 for (template = 0; template < 32; ++template) {
3579                         if ((stops_in_template [template][1] != stops [0]) ||
3580                                 (stops_in_template [template][2] != stops [1]))
3581                                 continue;
3582
3583                         if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3584                                 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3585                                 continue;
3586
3587                         if (!debug_ins_sched ())
3588                                 continue;
3589
3590                         ia64_real_emit_bundle (code, deps_start, stops, 2, template, nops_for_ins_types [ins_types_in_template [template][0]], code->instructions [0], code->instructions [1], 1 << 0);
3591                         break;
3592                 }
3593         }
3594
3595         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3596                 /* Wait for more instructions */
3597                 return;
3598
3599         if (flush)
3600                 nins_to_emit = code->nins;
3601         else
3602                 nins_to_emit = 1;
3603
3604         while (nins_to_emit > 0) {
3605                 if (!debug_ins_sched ())
3606                         stops [0] = 1;
3607                 switch (code->itypes [0]) {
3608                 case IA64_INS_TYPE_A:
3609                         if (stops [0])
3610                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3611                         else
3612                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3613                         break;
3614                 case IA64_INS_TYPE_I:
3615                         if (stops [0])
3616                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3617                         else
3618                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3619                         break;
3620                 case IA64_INS_TYPE_M:
3621                         if (stops [0])
3622                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3623                         else
3624                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3625                         break;
3626                 case IA64_INS_TYPE_B:
3627                         if (stops [0])
3628                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3629                         else
3630                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3631                         break;
3632                 case IA64_INS_TYPE_F:
3633                         if (stops [0])
3634                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3635                         else
3636                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3637                         break;
3638                 case IA64_INS_TYPE_LX:
3639                         if (stops [0] || stops [1])
3640                                 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3641                         else
3642                                 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3643                         nins_to_emit --;
3644                         break;
3645                 default:
3646                         g_assert_not_reached ();
3647                 }
3648                 nins_to_emit --;
3649         }
3650 }
3651
3652 unw_dyn_region_info_t*
3653 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3654 {
3655         unw_dyn_region_info_t *r;
3656
3657         g_assert (code->nins == 0);
3658         r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3659         memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3660         r->op_count = code->unw_op_count;
3661         r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3662         code->unw_op_count = 0;
3663         code->unw_op_pos = 0;
3664         code->region_start = code->buf;
3665
3666         return r;
3667 }
3668
3669 static void 
3670 ia64_patch (unsigned char* code, gpointer target)
3671 {
3672         int template, i;
3673         guint64 instructions [3];
3674         guint8 gen_buf [16];
3675         Ia64CodegenState gen;
3676         int ins_to_skip;
3677         gboolean found;
3678
3679         /* 
3680          * code encodes both the position inside the buffer and code.nins when
3681          * the instruction was emitted.
3682          */
3683         ins_to_skip = (guint64)code % 16;
3684         code = (unsigned char*)((guint64)code & ~15);
3685
3686         /*
3687          * Search for the first instruction which is 'patchable', skipping
3688          * ins_to_skip instructions.
3689          */
3690
3691         while (TRUE) {
3692
3693         template = ia64_bundle_template (code);
3694         instructions [0] = ia64_bundle_ins1 (code);
3695         instructions [1] = ia64_bundle_ins2 (code);
3696         instructions [2] = ia64_bundle_ins3 (code);
3697
3698         ia64_codegen_init (gen, gen_buf);
3699
3700         found = FALSE;
3701         for (i = 0; i < 3; ++i) {
3702                 guint64 ins = instructions [i];
3703                 int opcode = ia64_ins_opcode (ins);
3704
3705                 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3706                         continue;
3707
3708                 if (ins_to_skip) {
3709                         ins_to_skip --;
3710                         continue;
3711                 }
3712
3713                 switch (ins_types_in_template [template][i]) {
3714                 case IA64_INS_TYPE_A:
3715                 case IA64_INS_TYPE_M:
3716                         if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3717                                 /* adds */
3718                                 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3719                                 instructions [i] = gen.instructions [0];
3720                                 found = TRUE;
3721                         }
3722                         else
3723                                 NOT_IMPLEMENTED;
3724                         break;
3725                 case IA64_INS_TYPE_B:
3726                         if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3727                                 /* br.cond */
3728                                 gint64 disp = ((guint8*)target - code) >> 4;
3729
3730                                 /* FIXME: hints */
3731                                 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3732                                 
3733                                 instructions [i] = gen.instructions [0];
3734                                 found = TRUE;
3735                         }
3736                         else if (opcode == 5) {
3737                                 /* br.call */
3738                                 gint64 disp = ((guint8*)target - code) >> 4;
3739
3740                                 /* FIXME: hints */
3741                                 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3742                                 instructions [i] = gen.instructions [0];
3743                                 found = TRUE;
3744                         }
3745                         else
3746                                 NOT_IMPLEMENTED;
3747                         break;
3748                 case IA64_INS_TYPE_LX:
3749                         if (i == 1)
3750                                 break;
3751
3752                         if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3753                                 /* movl */
3754                                 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3755                                 instructions [1] = gen.instructions [0];
3756                                 instructions [2] = gen.instructions [1];
3757                                 found = TRUE;
3758                         }
3759                         else
3760                                 NOT_IMPLEMENTED;
3761
3762                         break;
3763                 default:
3764                         NOT_IMPLEMENTED;
3765                 }
3766
3767                 if (found) {
3768                         /* Rewrite code */
3769                         ia64_codegen_init (gen, code);
3770                         ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3771                         return;
3772                 }
3773         }
3774
3775         code += 16;
3776         }
3777 }
3778
3779 void
3780 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3781 {
3782         MonoJumpInfo *patch_info;
3783
3784         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3785                 unsigned char *ip = patch_info->ip.i + code;
3786                 const unsigned char *target;
3787
3788                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3789
3790                 if (patch_info->type == MONO_PATCH_INFO_NONE)
3791                         continue;
3792                 if (mono_compile_aot) {
3793                         NOT_IMPLEMENTED;
3794                 }
3795
3796                 ia64_patch (ip, (gpointer)target);
3797         }
3798 }
3799
3800 guint8 *
3801 mono_arch_emit_prolog (MonoCompile *cfg)
3802 {
3803         MonoMethod *method = cfg->method;
3804         MonoMethodSignature *sig;
3805         MonoInst *inst;
3806         int alloc_size, pos, i;
3807         Ia64CodegenState code;
3808         CallInfo *cinfo;
3809         
3810         sig = mono_method_signature (method);
3811         pos = 0;
3812
3813         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
3814
3815         cfg->code_size =  MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3816
3817         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3818                 cfg->code_size += 1024;
3819         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3820                 cfg->code_size += 1024;
3821
3822         cfg->native_code = g_malloc (cfg->code_size);
3823
3824         ia64_codegen_init (code, cfg->native_code);
3825
3826         alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3827         if (cfg->param_area)
3828                 alloc_size += cfg->param_area;
3829         if (alloc_size)
3830                 /* scratch area */
3831                 alloc_size += 16;
3832         alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3833
3834         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3835                 /* Force sp to be saved/restored */
3836                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3837
3838         cfg->arch.stack_alloc_size = alloc_size;
3839
3840         pos = 0;
3841
3842         if (method->save_lmf) {
3843                 /* No LMF on IA64 */
3844         }
3845
3846         alloc_size -= pos;
3847
3848         ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3849         ia64_alloc (code, cfg->arch.reg_saved_ar_pfs, cfg->arch.reg_local0 - cfg->arch.reg_in0, cfg->arch.reg_out0 - cfg->arch.reg_local0, cfg->arch.n_out_regs, 0);
3850         ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3851         ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3852
3853         if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3854                 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3855                 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3856                 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3857                         ia64_mov (code, cfg->frame_reg, IA64_SP);
3858         }
3859
3860         if (alloc_size) {
3861 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3862                 int pagesize = getpagesize ();
3863
3864                 if (alloc_size >= pagesize) {
3865                         gint32 remaining_size = alloc_size;
3866
3867                         /* Generate stack touching code */
3868                         ia64_mov (code, GP_SCRATCH_REG, IA64_SP);                       
3869                         while (remaining_size >= pagesize) {
3870                                 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3871                                 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3872                                 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3873                                 remaining_size -= pagesize;
3874                         }
3875                 }
3876 #endif
3877                 if (ia64_is_imm14 (-alloc_size)) {
3878                         if (cfg->arch.omit_fp)
3879                                 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3880                         ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3881                 }
3882                 else {
3883                         ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3884                         if (cfg->arch.omit_fp)
3885                                 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3886                         ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3887                 }
3888         }
3889
3890         ia64_begin_bundle (code);
3891
3892         /* Initialize unwind info */
3893         cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3894
3895         if (sig->ret->type != MONO_TYPE_VOID) {
3896                 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3897                         /* Save volatile arguments to the stack */
3898                         NOT_IMPLEMENTED;
3899                 }
3900         }
3901
3902         /* Keep this in sync with emit_load_volatile_arguments */
3903         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3904                 ArgInfo *ainfo = cinfo->args + i;
3905                 gint32 stack_offset;
3906                 MonoType *arg_type;
3907                 inst = cfg->args [i];
3908
3909                 if (sig->hasthis && (i == 0))
3910                         arg_type = &mono_defaults.object_class->byval_arg;
3911                 else
3912                         arg_type = sig->params [i - sig->hasthis];
3913
3914                 arg_type = mono_type_get_underlying_type (arg_type);
3915
3916                 stack_offset = ainfo->offset + ARGS_OFFSET;
3917
3918                 /* Save volatile arguments to the stack */
3919                 if (inst->opcode != OP_REGVAR) {
3920                         switch (ainfo->storage) {
3921                         case ArgInIReg:
3922                         case ArgInFloatReg:
3923                                 g_assert (inst->opcode == OP_REGOFFSET);
3924                                 if (ia64_is_adds_imm (inst->inst_offset))
3925                                         ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3926                                 else {
3927                                         ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3928                                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3929                                 }
3930                                 if (arg_type->byref)
3931                                         ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3932                                 else {
3933                                         switch (arg_type->type) {
3934                                         case MONO_TYPE_R4:
3935                                                 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3936                                                 break;
3937                                         case MONO_TYPE_R8:
3938                                                 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3939                                                 break;
3940                                         default:
3941                                                 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3942                                                 break;
3943                                         }
3944                                 }
3945                                 break;
3946                         case ArgOnStack:
3947                                 break;
3948                         case ArgAggregate:
3949                                 if (ainfo->nslots != ainfo->nregs)
3950                                         NOT_IMPLEMENTED;
3951
3952                                 g_assert (inst->opcode == OP_REGOFFSET);
3953                                 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3954                                 for (i = 0; i < ainfo->nregs; ++i) {
3955                                         switch (ainfo->atype) {
3956                                         case AggregateNormal:
3957                                                 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3958                                                 break;
3959                                         case AggregateSingleHFA:
3960                                                 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3961                                                 break;
3962                                         case AggregateDoubleHFA:
3963                                                 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3964                                                 break;
3965                                         default:
3966                                                 NOT_IMPLEMENTED;
3967                                         }
3968                                 }
3969                                 break;
3970                         default:
3971                                 g_assert_not_reached ();
3972                         }
3973                 }
3974
3975                 if (inst->opcode == OP_REGVAR) {
3976                         /* Argument allocated to (non-volatile) register */
3977                         switch (ainfo->storage) {
3978                         case ArgInIReg:
3979                                 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3980                                         ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3981                                 break;
3982                         case ArgOnStack:
3983                                 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3984                                 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3985                                 break;
3986                         default:
3987                                 NOT_IMPLEMENTED;
3988                         }
3989                 }
3990         }
3991
3992         if (method->save_lmf) {
3993                 /* No LMF on IA64 */
3994         }
3995
3996         ia64_codegen_close (code);
3997
3998         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3999                 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
4000
4001         cfg->code_len = code.buf - cfg->native_code;
4002
4003         g_assert (cfg->code_len < cfg->code_size);
4004
4005         cfg->arch.prolog_end_offset = cfg->code_len;
4006
4007         return code.buf;
4008 }
4009
4010 void
4011 mono_arch_emit_epilog (MonoCompile *cfg)
4012 {
4013         MonoMethod *method = cfg->method;
4014         int i, pos;
4015         int max_epilog_size = 16 * 4;
4016         Ia64CodegenState code;
4017         guint8 *buf;
4018         CallInfo *cinfo;
4019         ArgInfo *ainfo;
4020
4021         if (mono_jit_trace_calls != NULL)
4022                 max_epilog_size += 1024;
4023
4024         cfg->arch.epilog_begin_offset = cfg->code_len;
4025
4026         while (cfg->code_len + max_epilog_size > cfg->code_size) {
4027                 cfg->code_size *= 2;
4028                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4029                 mono_jit_stats.code_reallocs++;
4030         }
4031
4032         /* FIXME: Emit unwind info */
4033
4034         buf = cfg->native_code + cfg->code_len;
4035
4036         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4037                 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4038
4039         ia64_codegen_init (code, buf);
4040
4041         /* the code restoring the registers must be kept in sync with OP_JMP */
4042         pos = 0;
4043         
4044         if (method->save_lmf) {
4045                 /* No LMF on IA64 */
4046         }
4047
4048         /* Load returned vtypes into registers if needed */
4049         cinfo = get_call_info (cfg, cfg->mempool, mono_method_signature (method), FALSE);
4050         ainfo = &cinfo->ret;
4051         switch (ainfo->storage) {
4052         case ArgAggregate:
4053                 if (ainfo->nslots != ainfo->nregs)
4054                         NOT_IMPLEMENTED;
4055
4056                 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4057                 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4058                 for (i = 0; i < ainfo->nregs; ++i) {
4059                         switch (ainfo->atype) {
4060                         case AggregateNormal:
4061                                 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4062                                 break;
4063                         case AggregateSingleHFA:
4064                                 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4065                                 break;
4066                         case AggregateDoubleHFA:
4067                                 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4068                                 break;
4069                         default:
4070                                 g_assert_not_reached ();
4071                         }
4072                 }
4073                 break;
4074         default:
4075                 break;
4076         }
4077
4078         ia64_begin_bundle (code);
4079
4080         code.region_start = cfg->native_code;
4081
4082         /* Label the unwind state at the start of the exception throwing region */
4083         //ia64_unw_label_state (code, 1234);
4084
4085         if (cfg->arch.stack_alloc_size) {
4086                 if (cfg->arch.omit_fp) {
4087                         if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4088                                 ia64_unw_pop_frames (code, 1);
4089                                 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4090                         } else {
4091                                 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4092                                 ia64_unw_pop_frames (code, 1);
4093                                 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4094                         }
4095                 }
4096                 else {
4097                         ia64_unw_pop_frames (code, 1);
4098                         ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4099                 }
4100         }
4101         ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4102         ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4103         ia64_br_ret_reg (code, IA64_B0);
4104
4105         ia64_codegen_close (code);
4106
4107         cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4108         cfg->arch.r_pro->next = cfg->arch.r_epilog;
4109
4110         cfg->code_len = code.buf - cfg->native_code;
4111
4112         g_assert (cfg->code_len < cfg->code_size);
4113 }
4114
4115 void
4116 mono_arch_emit_exceptions (MonoCompile *cfg)
4117 {
4118         MonoJumpInfo *patch_info;
4119         int i, nthrows;
4120         Ia64CodegenState code;
4121         gboolean empty = TRUE;
4122         //unw_dyn_region_info_t *r_exceptions;
4123         MonoClass *exc_classes [16];
4124         guint8 *exc_throw_start [16], *exc_throw_end [16];
4125         guint32 code_size = 0;
4126
4127         /* Compute needed space */
4128         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4129                 if (patch_info->type == MONO_PATCH_INFO_EXC)
4130                         code_size += 256;
4131                 if (patch_info->type == MONO_PATCH_INFO_R8)
4132                         code_size += 8 + 7; /* sizeof (double) + alignment */
4133                 if (patch_info->type == MONO_PATCH_INFO_R4)
4134                         code_size += 4 + 7; /* sizeof (float) + alignment */
4135         }
4136
4137         if (code_size == 0)
4138                 return;
4139
4140         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4141                 cfg->code_size *= 2;
4142                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4143                 mono_jit_stats.code_reallocs++;
4144         }
4145
4146         ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4147
4148         /* The unwind state here is the same as before the epilog */
4149         //ia64_unw_copy_state (code, 1234);
4150
4151         /* add code to raise exceptions */
4152         /* FIXME: Optimize this */
4153         nthrows = 0;
4154         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4155                 switch (patch_info->type) {
4156                 case MONO_PATCH_INFO_EXC: {
4157                         MonoClass *exc_class;
4158                         guint8* throw_ip;
4159                         guint8* buf;
4160                         guint64 exc_token_index;
4161
4162                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4163                         g_assert (exc_class);
4164                         exc_token_index = mono_metadata_token_index (exc_class->type_token);
4165                         throw_ip = cfg->native_code + patch_info->ip.i;
4166
4167                         ia64_begin_bundle (code);
4168
4169                         ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4170
4171                         /* Find a throw sequence for the same exception class */
4172                         for (i = 0; i < nthrows; ++i)
4173                                 if (exc_classes [i] == exc_class)
4174                                         break;
4175
4176                         if (i < nthrows) {
4177                                 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4178
4179                                 if (ia64_is_adds_imm (offset))
4180                                         ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4181                                 else
4182                                         ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4183
4184                                 buf = code.buf + code.nins;
4185                                 ia64_br_cond_pred (code, 0, 0);
4186                                 ia64_begin_bundle (code);
4187                                 ia64_patch (buf, exc_throw_start [i]);
4188
4189                                 patch_info->type = MONO_PATCH_INFO_NONE;
4190                         }
4191                         else {
4192                                 /* Arg1 */
4193                                 buf = code.buf;
4194                                 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4195
4196                                 ia64_begin_bundle (code);
4197
4198                                 if (nthrows < 16) {
4199                                         exc_classes [nthrows] = exc_class;
4200                                         exc_throw_start [nthrows] = code.buf;
4201                                 }
4202
4203                                 /* Arg2 */
4204                                 if (ia64_is_adds_imm (exc_token_index))
4205                                         ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4206                                 else
4207                                         ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4208
4209                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
4210                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4211                                 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4212
4213                                 /* Indirect call */
4214                                 ia64_movl (code, GP_SCRATCH_REG, 0);
4215                                 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4216                                 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4217                                 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4218
4219                                 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4220
4221                                 /* Patch up the throw offset */
4222                                 ia64_begin_bundle (code);
4223
4224                                 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4225
4226                                 if (nthrows < 16) {
4227                                         exc_throw_end [nthrows] = code.buf;
4228                                         nthrows ++;
4229                                 }
4230                         }
4231
4232                         empty = FALSE;
4233                         break;
4234                 }
4235                 default:
4236                         break;
4237                 }
4238         }
4239
4240         if (!empty)
4241                 /* The unwinder needs this to work */
4242                 ia64_break_i (code, 0);
4243
4244         ia64_codegen_close (code);
4245
4246         /* FIXME: */
4247         //r_exceptions = mono_ia64_create_unwind_region (&code);
4248         //cfg->arch.r_epilog = r_exceptions;
4249
4250         cfg->code_len = code.buf - cfg->native_code;
4251
4252         g_assert (cfg->code_len < cfg->code_size);
4253 }
4254
4255 void*
4256 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4257 {
4258         Ia64CodegenState code;
4259         CallInfo *cinfo = NULL;
4260         MonoMethodSignature *sig;
4261         MonoInst *ins;
4262         int i, n, stack_area = 0;
4263
4264         ia64_codegen_init (code, p);
4265
4266         /* Keep this in sync with mono_arch_get_argument_info */
4267
4268         if (enable_arguments) {
4269                 /* Allocate a new area on the stack and save arguments there */
4270                 sig = mono_method_signature (cfg->method);
4271
4272                 cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4273
4274                 n = sig->param_count + sig->hasthis;
4275
4276                 stack_area = ALIGN_TO (n * 8, 16);
4277
4278                 if (n) {
4279                         ia64_movl (code, GP_SCRATCH_REG, stack_area);
4280
4281                         ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4282
4283                         /* FIXME: Allocate out registers */
4284
4285                         ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4286
4287                         /* Required by the ABI */
4288                         ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4289
4290                         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4291                         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4292
4293                         /* Save arguments to the stack */
4294                         for (i = 0; i < n; ++i) {
4295                                 ins = cfg->args [i];
4296
4297                                 if (ins->opcode == OP_REGVAR) {
4298                                         ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4299                                         ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4300                                         ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4301                                 }
4302                                 else {
4303                                         ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4304                                         ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4305                                         ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4306                                         ia64_movl (code, GP_SCRATCH_REG, (i * 8));                              
4307                                         ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4308                                         ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4309                                 }
4310                         }
4311                 }
4312                 else
4313                         ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4314         }
4315         else
4316                 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4317
4318         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4319         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4320
4321         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4322
4323         if (enable_arguments && stack_area) {
4324                 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4325
4326                 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4327
4328                 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4329         }
4330
4331         ia64_codegen_close (code);
4332
4333         return code.buf;
4334 }
4335
4336 void*
4337 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4338 {
4339         Ia64CodegenState code;
4340         CallInfo *cinfo = NULL;
4341         MonoMethod *method = cfg->method;
4342         MonoMethodSignature *sig = mono_method_signature (cfg->method);
4343
4344         ia64_codegen_init (code, p);
4345
4346         cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
4347
4348         /* Save return value + pass it to func */
4349         switch (cinfo->ret.storage) {
4350         case ArgNone:
4351                 break;
4352         case ArgInIReg:
4353                 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4354                 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4355                 break;
4356         case ArgInFloatReg:
4357                 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4358                 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4359                 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4360                 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4361                 break;
4362         case ArgValuetypeAddrInIReg:
4363                 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4364                 break;
4365         case ArgAggregate:
4366                 NOT_IMPLEMENTED;
4367                 break;
4368         default:
4369                 break;
4370         }
4371
4372         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4373         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4374         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4375
4376         /* Restore return value */
4377         switch (cinfo->ret.storage) {
4378         case ArgNone:
4379                 break;
4380         case ArgInIReg:
4381                 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4382                 break;
4383         case ArgInFloatReg:
4384                 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4385                 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4386                 break;
4387         case ArgValuetypeAddrInIReg:
4388                 break;
4389         case ArgAggregate:
4390                 break;
4391         default:
4392                 break;
4393         }
4394
4395         ia64_codegen_close (code);
4396
4397         return code.buf;
4398 }
4399
4400 void
4401 mono_arch_save_unwind_info (MonoCompile *cfg)
4402 {
4403         unw_dyn_info_t *di;
4404
4405         /* FIXME: Unregister this for dynamic methods */
4406
4407         di = g_malloc0 (sizeof (unw_dyn_info_t));
4408         di->start_ip = (unw_word_t) cfg->native_code;
4409         di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4410         di->gp = 0;
4411         di->format = UNW_INFO_FORMAT_DYNAMIC;
4412         di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4413         di->u.pi.regions = cfg->arch.r_pro;
4414
4415         _U_dyn_register (di);
4416
4417         /*
4418         {
4419                 unw_dyn_region_info_t *region = di->u.pi.regions;
4420
4421                 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4422                 while (region) {
4423                         printf ("    [Region: %d]\n", region->insn_count);
4424                         region = region->next;
4425                 }
4426         }
4427         */
4428 }
4429
4430 void
4431 mono_arch_flush_icache (guint8 *code, gint size)
4432 {
4433         guint8* p = (guint8*)((guint64)code & ~(0x3f));
4434         guint8* end = (guint8*)((guint64)code + size);
4435
4436 #ifdef __INTEL_COMPILER
4437         /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4438         while (p < end) {
4439                 __fc ((guint64)p);
4440                 p += 32;
4441         }
4442 #else
4443         while (p < end) {
4444                 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4445                 /* FIXME: This could be increased to 128 on some cpus */
4446                 p += 32;
4447         }
4448 #endif
4449 }
4450
4451 void
4452 mono_arch_flush_register_windows (void)
4453 {
4454         /* Not needed because of libunwind */
4455 }
4456
4457 gboolean 
4458 mono_arch_is_inst_imm (gint64 imm)
4459 {
4460         /* The lowering pass will take care of it */
4461
4462         return TRUE;
4463 }
4464
4465 /*
4466  * Determine whenever the trap whose info is in SIGINFO is caused by
4467  * integer overflow.
4468  */
4469 gboolean
4470 mono_arch_is_int_overflow (void *sigctx, void *info)
4471 {
4472         /* Division is emulated with explicit overflow checks */
4473         return FALSE;
4474 }
4475
4476 guint32
4477 mono_arch_get_patch_offset (guint8 *code)
4478 {
4479         NOT_IMPLEMENTED;
4480
4481         return 0;
4482 }
4483
4484 gpointer
4485 mono_arch_get_vcall_slot (guint8* code, gpointer *regs, int *displacement)
4486 {
4487         guint8 *bundle2 = code - 48;
4488         guint8 *bundle3 = code - 32;
4489         guint8 *bundle4 = code - 16;
4490         guint64 ins21 = ia64_bundle_ins1 (bundle2);
4491         guint64 ins22 = ia64_bundle_ins2 (bundle2);
4492         guint64 ins23 = ia64_bundle_ins3 (bundle2);
4493         guint64 ins31 = ia64_bundle_ins1 (bundle3);
4494         guint64 ins32 = ia64_bundle_ins2 (bundle3);
4495         guint64 ins33 = ia64_bundle_ins3 (bundle3);
4496         guint64 ins41 = ia64_bundle_ins1 (bundle4);
4497         guint64 ins42 = ia64_bundle_ins2 (bundle4);
4498         guint64 ins43 = ia64_bundle_ins3 (bundle4);
4499
4500         /* 
4501          * Virtual calls are made with:
4502          *
4503          * [MII]       ld8 r31=[r8]
4504          *             nop.i 0x0
4505          *             nop.i 0x0;;
4506          * [MII]       nop.m 0x0
4507          *             mov.sptk b6=r31,0x2000000000f32a80
4508          *             nop.i 0x0
4509          * [MII]       nop.m 0x0
4510          *             nop.i 0x123456
4511          *             nop.i 0x0
4512          * [MIB]       nop.m 0x0
4513          *             nop.i 0x0
4514          *             br.call.sptk.few b0=b6;;
4515          */
4516
4517         if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4518                  (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4519                 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4520                 (ins31 == IA64_NOP_M) && 
4521                 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4522                 (ins33 == IA64_NOP_I) &&
4523                 (ins41 == IA64_NOP_M) &&
4524                 (ins42 == IA64_NOP_I) &&
4525                 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4526                 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4527                 g_assert (ins21 == IA64_NOP_M);
4528                 g_assert (ins23 == IA64_NOP_I);
4529                 g_assert (ia64_ins_opcode (ins22) == 0);
4530                 g_assert (ia64_ins_x3 (ins22) == 7);
4531                 g_assert (ia64_ins_x (ins22) == 0);
4532                 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4533
4534                 *displacement = (gssize)regs [IA64_R8] - (gssize)regs [IA64_R11];
4535
4536                 return regs [IA64_R11];
4537         }
4538
4539         return NULL;
4540 }
4541
4542 gpointer*
4543 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4544 {
4545         gpointer vt;
4546         int displacement;
4547         vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4548         if (!vt)
4549                 return NULL;
4550         return (gpointer*)(gpointer)((char*)vt + displacement);
4551 }
4552
4553 gpointer*
4554 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4555 {
4556         NOT_IMPLEMENTED;
4557
4558         return NULL;
4559 }
4560
4561 static gboolean tls_offset_inited = FALSE;
4562
4563 void
4564 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4565 {
4566         if (!tls_offset_inited) {
4567                 tls_offset_inited = TRUE;
4568
4569                 appdomain_tls_offset = mono_domain_get_tls_offset ();
4570                 thread_tls_offset = mono_thread_get_tls_offset ();
4571         }               
4572 }
4573
4574 void
4575 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4576 {
4577 }
4578
4579 void
4580 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4581 {
4582         MonoCallInst *call = (MonoCallInst*)inst;
4583         int out_reg = cfg->arch.reg_out0;
4584
4585         if (vt_reg != -1) {
4586                 CallInfo * cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
4587                 MonoInst *vtarg;
4588
4589                 if (cinfo->ret.storage == ArgAggregate) {
4590                         MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4591
4592                         /* 
4593                          * The valuetype is in registers after the call, need to be copied 
4594                          * to the stack. Save the address to a local here, so the call 
4595                          * instruction can access it.
4596                          */
4597                         g_assert (local->opcode == OP_REGOFFSET);
4598                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4599                 }
4600                 else {
4601                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4602                         vtarg->sreg1 = vt_reg;
4603                         vtarg->dreg = mono_regstate_next_int (cfg->rs);
4604                         mono_bblock_add_inst (cfg->cbb, vtarg);
4605
4606                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4607
4608                         out_reg ++;
4609                 }
4610         }
4611
4612         /* add the this argument */
4613         if (this_reg != -1) {
4614                 MonoInst *this;
4615                 MONO_INST_NEW (cfg, this, OP_MOVE);
4616                 this->type = this_type;
4617                 this->sreg1 = this_reg;
4618                 this->dreg = mono_regstate_next_int (cfg->rs);
4619                 mono_bblock_add_inst (cfg->cbb, this);
4620
4621                 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4622         }
4623 }
4624
4625
4626 #ifdef MONO_ARCH_HAVE_IMT
4627
4628 /*
4629  * LOCKING: called with the domain lock held
4630  */
4631 gpointer
4632 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4633 {
4634         int i;
4635         int size = 0;
4636         guint8 *start, *buf;
4637         Ia64CodegenState code;
4638
4639         size = count * 256;
4640         buf = g_malloc0 (size);
4641         ia64_codegen_init (code, buf);
4642
4643         /* IA64_R9 contains the IMT method */
4644
4645         for (i = 0; i < count; ++i) {
4646                 MonoIMTCheckItem *item = imt_entries [i];
4647                 ia64_begin_bundle (code);
4648                 item->code_target = (guint8*)code.buf + code.nins;
4649                 if (item->is_equals) {
4650                         if (item->check_target_idx) {
4651                                 if (!item->compare_done) {
4652                                         ia64_movl (code, GP_SCRATCH_REG, item->method);
4653                                         ia64_cmp_eq (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4654                                 }
4655                                 item->jmp_code = (guint8*)code.buf + code.nins;
4656                                 ia64_br_cond_pred (code, 7, 0);
4657
4658                                 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4659                                 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4660                                 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4661                                 ia64_br_cond_reg (code, IA64_B6);
4662                         } else {
4663                                 /* enable the commented code to assert on wrong method */
4664 #if ENABLE_WRONG_METHOD_CHECK
4665                                 g_assert_not_reached ();
4666 #endif
4667                                 ia64_movl (code, GP_SCRATCH_REG, &(vtable->vtable [item->vtable_slot]));
4668                                 ia64_ld8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG);
4669                                 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
4670                                 ia64_br_cond_reg (code, IA64_B6);
4671 #if ENABLE_WRONG_METHOD_CHECK
4672                                 g_assert_not_reached ();
4673 #endif
4674                         }
4675                 } else {
4676                         ia64_movl (code, GP_SCRATCH_REG, item->method);
4677                         ia64_cmp_geu (code, 6, 7, IA64_R9, GP_SCRATCH_REG);
4678                         item->jmp_code = (guint8*)code.buf + code.nins;
4679                         ia64_br_cond_pred (code, 6, 0);
4680                 }
4681         }
4682         /* patch the branches to get to the target items */
4683         for (i = 0; i < count; ++i) {
4684                 MonoIMTCheckItem *item = imt_entries [i];
4685                 if (item->jmp_code) {
4686                         if (item->check_target_idx) {
4687                                 ia64_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4688                         }
4689                 }
4690         }
4691
4692         ia64_codegen_close (code);
4693         g_assert (code.buf - buf <= size);
4694
4695         size = code.buf - buf;
4696         start = mono_code_manager_reserve (domain->code_mp, size);
4697         memcpy (start, buf, size);
4698
4699         mono_arch_flush_icache (start, size);
4700
4701         mono_stats.imt_thunks_size += size;
4702
4703         return start;
4704 }
4705
4706 MonoMethod*
4707 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4708 {
4709         return regs [IA64_R9];
4710 }
4711
4712 MonoObject*
4713 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
4714 {
4715         return regs [IA64_R10];
4716 }
4717
4718 void
4719 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
4720 {
4721         /* Done by the implementation of the CALL_MEMBASE opcodes */
4722 }
4723 #endif
4724
4725 MonoInst*
4726 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4727 {
4728         MonoInst *ins = NULL;
4729
4730         if(cmethod->klass->image == mono_defaults.corlib &&
4731                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4732                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4733                 /* 
4734                  * We don't use the generic version in mini_get_inst_for_method () since the
4735                  * ia64 has atomic_add_imm opcodes.
4736                  */
4737                 if (strcmp (cmethod->name, "Increment") == 0) {
4738                         guint32 opcode;
4739
4740                         if (fsig->params [0]->type == MONO_TYPE_I4)
4741                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4742                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4743                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4744                         else
4745                                 g_assert_not_reached ();
4746                         MONO_INST_NEW (cfg, ins, opcode);
4747                         ins->inst_imm = 1;
4748                         ins->inst_i0 = args [0];
4749                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4750                         guint32 opcode;
4751
4752                         if (fsig->params [0]->type == MONO_TYPE_I4)
4753                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4754                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4755                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4756                         else
4757                                 g_assert_not_reached ();
4758                         MONO_INST_NEW (cfg, ins, opcode);
4759                         ins->inst_imm = -1;
4760                         ins->inst_i0 = args [0];
4761                 } else if (strcmp (cmethod->name, "Add") == 0) {
4762                         guint32 opcode;
4763
4764                         if (fsig->params [0]->type == MONO_TYPE_I4)
4765                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4766                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4767                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4768                         else
4769                                 g_assert_not_reached ();
4770                         
4771                         MONO_INST_NEW (cfg, ins, opcode);
4772
4773                         ins->inst_i0 = args [0];
4774                         ins->inst_i1 = args [1];
4775                 }
4776         }
4777
4778         return ins;
4779 }
4780
4781 gboolean
4782 mono_arch_print_tree (MonoInst *tree, int arity)
4783 {
4784         return 0;
4785 }
4786
4787 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4788 {
4789         MonoInst* ins;
4790         
4791         if (appdomain_tls_offset == -1)
4792                 return NULL;
4793         
4794         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4795         ins->inst_offset = appdomain_tls_offset;
4796         return ins;
4797 }
4798
4799 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4800 {
4801         MonoInst* ins;
4802         
4803         if (thread_tls_offset == -1)
4804                 return NULL;
4805         
4806         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4807         ins->inst_offset = thread_tls_offset;
4808         return ins;
4809 }