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