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