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