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