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