4c5e0d8caf26d3be94ca07ad295445d6d9b53b40
[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->args [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->args [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->args [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                         ia64_sxt4 (code, ins->dreg, ins->sreg1);
2637                         break;
2638                 case CEE_CONV_U8:
2639                 case CEE_CONV_U:
2640                         ia64_zxt4 (code, ins->dreg, ins->sreg1);
2641                         break;
2642
2643                         /*
2644                          * FLOAT OPCODES
2645                          */
2646                 case OP_R8CONST: {
2647                         double d = *(double *)ins->inst_p0;
2648
2649                         if ((d == 0.0) && (mono_signbit (d) == 0))
2650                                 ia64_fmov (code, ins->dreg, 0);
2651                         else if (d == 1.0)
2652                                 ia64_fmov (code, ins->dreg, 1);
2653                         else {
2654                                 add_patch_info (cfg, code, MONO_PATCH_INFO_R8, ins->inst_p0);
2655                                 ia64_movl (code, GP_SCRATCH_REG, 0);
2656                                 ia64_ldfd (code, ins->dreg, GP_SCRATCH_REG);
2657                         }
2658                         break;
2659                 }
2660                 case OP_R4CONST: {
2661                         float f = *(float *)ins->inst_p0;
2662
2663                         if ((f == 0.0) && (mono_signbit (f) == 0))
2664                                 ia64_fmov (code, ins->dreg, 0);
2665                         else if (f == 1.0)
2666                                 ia64_fmov (code, ins->dreg, 1);
2667                         else {
2668                                 add_patch_info (cfg, code, MONO_PATCH_INFO_R4, ins->inst_p0);
2669                                 ia64_movl (code, GP_SCRATCH_REG, 0);
2670                                 ia64_ldfs (code, ins->dreg, GP_SCRATCH_REG);
2671                         }
2672                         break;
2673                 }
2674                 case OP_FMOVE:
2675                         ia64_fmov (code, ins->dreg, ins->sreg1);
2676                         break;
2677                 case OP_STORER8_MEMBASE_REG:
2678                         ia64_stfd_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
2679                         break;
2680                 case OP_STORER4_MEMBASE_REG:
2681                         ia64_fnorm_s_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2682                         ia64_stfs_hint (code, ins->inst_destbasereg, FP_SCRATCH_REG, 0);
2683                         break;
2684                 case OP_LOADR8_MEMBASE:
2685                         ia64_ldfd (code, ins->dreg, ins->inst_basereg);
2686                         break;
2687                 case OP_LOADR4_MEMBASE:
2688                         ia64_ldfs (code, ins->dreg, ins->inst_basereg);
2689                         ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2690                         break;
2691                 case CEE_CONV_R4:
2692                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2693                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2694                         ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2695                         break;
2696                 case CEE_CONV_R8:
2697                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2698                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2699                         ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2700                         break;
2701                 case OP_LCONV_TO_R8:
2702                         /* FIXME: Difference with CEE_CONV_R8 ? */
2703                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2704                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2705                         ia64_fnorm_d_sf (code, ins->dreg, ins->dreg, 0);
2706                         break;
2707                 case OP_LCONV_TO_R4:
2708                         /* FIXME: Difference with CEE_CONV_R4 ? */
2709                         ia64_setf_sig (code, ins->dreg, ins->sreg1);
2710                         ia64_fcvt_xf (code, ins->dreg, ins->dreg);
2711                         ia64_fnorm_s_sf (code, ins->dreg, ins->dreg, 0);
2712                         break;
2713                 case OP_FCONV_TO_R4:
2714                         ia64_fnorm_s_sf (code, ins->dreg, ins->sreg1, 0);
2715                         break;
2716                 case OP_FCONV_TO_I8:
2717                         ia64_fcvt_fx_trunc_sf (code, FP_SCRATCH_REG, ins->sreg1, 0);
2718                         ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
2719                         break;
2720                 case OP_FADD:
2721                         ia64_fma_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2722                         break;
2723                 case OP_FSUB:
2724                         ia64_fms_d_sf (code, ins->dreg, ins->sreg1, 1, ins->sreg2, 0);
2725                         break;
2726                 case OP_FMUL:
2727                         ia64_fma_d_sf (code, ins->dreg, ins->sreg1, ins->sreg2, 0, 0);
2728                         break;
2729                 case OP_FNEG:
2730                         ia64_fmerge_ns (code, ins->dreg, ins->sreg1, ins->sreg1);
2731                         break;
2732                 case OP_CKFINITE:
2733                         /* Quiet NaN */
2734                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x080);
2735                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2736                         /* Signaling NaN */
2737                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x040);
2738                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2739                         /* Positive infinity */
2740                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x021);
2741                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2742                         /* Negative infinity */
2743                         ia64_fclass_m (code, 6, 7, ins->sreg1, 0x022);
2744                         emit_cond_system_exception (cfg, code, "ArithmeticException", 6);
2745                         break;
2746
2747                 /* Calls */
2748                 case OP_CHECK_THIS:
2749                         /* ensure ins->sreg1 is not NULL */
2750                         ia64_ld8 (code, GP_SCRATCH_REG, ins->sreg1);
2751                         break;
2752                 case OP_ARGLIST:
2753                         ia64_adds_imm (code, GP_SCRATCH_REG, cfg->sig_cookie, cfg->frame_reg);
2754                         ia64_st8 (code, ins->sreg1, GP_SCRATCH_REG);
2755                         break;
2756                 case OP_FCALL:
2757                 case OP_LCALL:
2758                 case OP_VCALL:
2759                 case OP_VOIDCALL:
2760                 case CEE_CALL:
2761                         call = (MonoCallInst*)ins;
2762
2763                         if (ins->flags & MONO_INST_HAS_METHOD)
2764                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2765                         else
2766                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2767
2768                         code = emit_move_return_value (cfg, ins, code);
2769                         break;
2770
2771                 case OP_CALL_REG:
2772                 case OP_FCALL_REG:
2773                 case OP_LCALL_REG:
2774                 case OP_VCALL_REG:
2775                 case OP_VOIDCALL_REG:
2776                         call = (MonoCallInst*)ins;
2777
2778                         /* Indirect call */
2779                         /* 
2780                          * mono_arch_patch_delegate_trampoline will patch this, this is why R8 is 
2781                          * used.
2782                          */
2783                         ia64_mov (code, IA64_R8, ins->sreg1);
2784                         ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, IA64_R8, 8);
2785                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2786                         ia64_ld8 (code, IA64_GP, IA64_R8);
2787                         ia64_br_call_reg (code, IA64_B0, IA64_B6);
2788
2789                         code = emit_move_return_value (cfg, ins, code);
2790                         break;
2791
2792                 case OP_FCALL_MEMBASE:
2793                 case OP_LCALL_MEMBASE:
2794                 case OP_VCALL_MEMBASE:
2795                 case OP_VOIDCALL_MEMBASE:
2796                 case OP_CALL_MEMBASE:
2797                         /* 
2798                          * There are no membase instructions on ia64, but we can't 
2799                          * lower this since get_vcall_slot_addr () needs to decode it.
2800                          */
2801
2802                         /* Keep this in synch with get_vcall_slot_addr */
2803                         if (ia64_is_imm14 (ins->inst_offset))
2804                                 ia64_adds_imm (code, IA64_R8, ins->inst_offset, ins->sreg1);
2805                         else {
2806                                 ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
2807                                 ia64_add (code, IA64_R8, GP_SCRATCH_REG, ins->sreg1);
2808                         }
2809
2810                         ia64_begin_bundle (code);
2811                         ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2812
2813                         ia64_ld8 (code, GP_SCRATCH_REG, IA64_R8);
2814
2815                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2816
2817                         /*
2818                          * This nop will tell get_vcall_slot_addr that this is a virtual 
2819                          * call.
2820                          */
2821                         ia64_nop_i (code, 0x12345);
2822
2823                         ia64_br_call_reg (code, IA64_B0, IA64_B6);
2824
2825                         ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2826
2827                         code = emit_move_return_value (cfg, ins, code);
2828                         break;
2829                 case OP_JMP: {
2830                         /*
2831                          * Keep in sync with the code in emit_epilog.
2832                          */
2833
2834                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2835                                 NOT_IMPLEMENTED;
2836
2837                         g_assert (!cfg->method->save_lmf);
2838
2839                         /* Load arguments into their original registers */
2840                         code = emit_load_volatile_arguments (cfg, code);
2841
2842                         if (cfg->arch.stack_alloc_size) {
2843                                 if (cfg->arch.omit_fp) {
2844                                         if (ia64_is_imm14 (cfg->arch.stack_alloc_size))
2845                                                 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
2846                                         else {
2847                                                 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
2848                                                 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
2849                                         }
2850                                 }
2851                                 else
2852                                         ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
2853                         }
2854                         ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
2855                         ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
2856
2857                         add_patch_info (cfg, code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2858                         ia64_movl (code, GP_SCRATCH_REG, 0);
2859                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
2860                         ia64_br_cond_reg (code, IA64_B6);
2861
2862                         break;
2863                 }
2864                 case OP_BREAK:
2865                         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, mono_arch_break);
2866                         break;
2867
2868                 case OP_LOCALLOC: {
2869                         gint32 abi_offset;
2870
2871                         /* FIXME: Sigaltstack support */
2872
2873                         /* keep alignment */
2874                         ia64_adds_imm (code, GP_SCRATCH_REG, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1);
2875                         ia64_movl (code, GP_SCRATCH_REG2, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2876                         ia64_and (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2877
2878                         ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
2879
2880                         ia64_mov (code, ins->dreg, IA64_SP);
2881
2882                         /* An area at sp is reserved by the ABI for parameter passing */
2883                         abi_offset = - ALIGN_TO (cfg->param_area + 16, MONO_ARCH_LOCALLOC_ALIGNMENT);
2884                         if (ia64_is_adds_imm (abi_offset))
2885                                 ia64_adds_imm (code, IA64_SP, abi_offset, IA64_SP);
2886                         else {
2887                                 ia64_movl (code, GP_SCRATCH_REG2, abi_offset);
2888                                 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG2);
2889                         }
2890
2891                         if (ins->flags & MONO_INST_INIT) {
2892                                 /* Upper limit */
2893                                 ia64_add (code, GP_SCRATCH_REG2, ins->dreg, GP_SCRATCH_REG);
2894
2895                                 ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2896
2897                                 /* Init loop */
2898                                 ia64_st8_inc_imm_hint (code, ins->dreg, IA64_R0, 8, 0);
2899                                 ia64_cmp_lt (code, 8, 9, ins->dreg, GP_SCRATCH_REG2);
2900                                 ia64_br_cond_pred (code, 8, -2);
2901
2902                                 ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2903
2904                                 ia64_sub (code, ins->dreg, GP_SCRATCH_REG2, GP_SCRATCH_REG);
2905                         }
2906
2907                         break;
2908                 }
2909                 case OP_TLS_GET:
2910                         ia64_adds_imm (code, ins->dreg, ins->inst_offset, IA64_TP);
2911                         ia64_ld8 (code, ins->dreg, ins->dreg);
2912                         break;
2913
2914                         /* Synchronization */
2915                 case OP_MEMORY_BARRIER:
2916                         ia64_mf (code);
2917                         break;
2918                 case OP_ATOMIC_ADD_IMM_NEW_I4:
2919                         g_assert (ins->inst_offset == 0);
2920                         ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2921                         ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2922                         break;
2923                 case OP_ATOMIC_ADD_IMM_NEW_I8:
2924                         g_assert (ins->inst_offset == 0);
2925                         ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
2926                         ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
2927                         break;
2928                 case OP_ATOMIC_EXCHANGE_I4:
2929                         ia64_xchg4_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2930                         ia64_sxt4 (code, ins->dreg, ins->dreg);
2931                         break;
2932                 case OP_ATOMIC_EXCHANGE_I8:
2933                         ia64_xchg8_hint (code, ins->dreg, ins->inst_basereg, ins->sreg2, 0);
2934                         break;
2935                 case OP_ATOMIC_ADD_NEW_I4: {
2936                         guint8 *label, *buf;
2937
2938                         /* From libatomic_ops */
2939                         ia64_mf (code);
2940
2941                         ia64_begin_bundle (code);
2942                         label = code.buf + code.nins;
2943                         ia64_ld4_acq (code, GP_SCRATCH_REG, ins->sreg1);
2944                         ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2945                         ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2946                         ia64_cmpxchg4_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2947                         ia64_cmp4_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2948                         buf = code.buf + code.nins;
2949                         ia64_br_cond_pred (code, 7, 0);
2950                         ia64_begin_bundle (code);
2951                         ia64_patch (buf, label);
2952                         ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2953                         break;
2954                 }
2955                 case OP_ATOMIC_ADD_NEW_I8: {
2956                         guint8 *label, *buf;
2957
2958                         /* From libatomic_ops */
2959                         ia64_mf (code);
2960
2961                         ia64_begin_bundle (code);
2962                         label = code.buf + code.nins;
2963                         ia64_ld8_acq (code, GP_SCRATCH_REG, ins->sreg1);
2964                         ia64_add (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, ins->sreg2);
2965                         ia64_mov_to_ar_m (code, IA64_CCV, GP_SCRATCH_REG);
2966                         ia64_cmpxchg8_acq_hint (code, GP_SCRATCH_REG2, ins->sreg1, GP_SCRATCH_REG2, 0);
2967                         ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, GP_SCRATCH_REG2);
2968                         buf = code.buf + code.nins;
2969                         ia64_br_cond_pred (code, 7, 0);
2970                         ia64_begin_bundle (code);
2971                         ia64_patch (buf, label);
2972                         ia64_add (code, ins->dreg, GP_SCRATCH_REG, ins->sreg2);
2973                         break;
2974                 }
2975
2976                         /* Exception handling */
2977                 case OP_CALL_HANDLER:
2978                         /*
2979                          * Using a call instruction would mess up the register stack, so
2980                          * save the return address to a register and use a
2981                          * branch.
2982                          */
2983                         ia64_codegen_set_one_ins_per_bundle (code, TRUE);
2984                         ia64_mov (code, IA64_R15, IA64_R0);
2985                         ia64_mov_from_ip (code, GP_SCRATCH_REG);
2986                         /* Add the length of OP_CALL_HANDLER */
2987                         ia64_adds_imm (code, GP_SCRATCH_REG, 5 * 16, GP_SCRATCH_REG);
2988                         add_patch_info (cfg, code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2989                         ia64_movl (code, GP_SCRATCH_REG2, 0);
2990                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
2991                         ia64_br_cond_reg (code, IA64_B6);
2992                         ia64_codegen_set_one_ins_per_bundle (code, FALSE);
2993                         break;
2994                 case OP_START_HANDLER: {
2995                         /*
2996                          * We receive the return address in GP_SCRATCH_REG.
2997                          */
2998                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2999
3000                         /* 
3001                          * R15 determines our caller. It is used since it is writable using
3002                          * libunwind.
3003                          * R15 == 0 means we are called by OP_CALL_HANDLER or via resume_context ()
3004                          * R15 != 0 means we are called by call_filter ().
3005                          */
3006                         ia64_codegen_set_one_ins_per_bundle (code, TRUE);
3007                         ia64_cmp_eq (code, 6, 7, IA64_R15, IA64_R0);
3008
3009                         ia64_br_cond_pred (code, 6, 6);
3010
3011                         /*
3012                          * Called by call_filter:
3013                          * Allocate a new stack frame, and set the fp register from the 
3014                          * value passed in by the caller.
3015                          * We allocate a similar frame as is done by the prolog, so
3016                          * if an exception is thrown while executing the filter, the
3017                          * unwinder can unwind through the filter frame using the unwind
3018                          * info for the prolog. 
3019                          */
3020                         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);
3021                         ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3022                         ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3023                         ia64_mov (code, cfg->frame_reg, IA64_R15);
3024                         /* Signal to endfilter that we are called by call_filter */
3025                         ia64_mov (code, GP_SCRATCH_REG, IA64_R0);
3026
3027                         /* Save the return address */
3028                         ia64_adds_imm (code, GP_SCRATCH_REG2, spvar->inst_offset, cfg->frame_reg);
3029                         ia64_st8_hint (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 0);
3030                         ia64_codegen_set_one_ins_per_bundle (code, FALSE);
3031
3032                         break;
3033                 }
3034                 case OP_ENDFINALLY:
3035                 case OP_ENDFILTER: {
3036                         /* FIXME: Return the value in ENDFILTER */
3037                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3038
3039                         /* Load the return address */
3040                         ia64_adds_imm (code, GP_SCRATCH_REG, spvar->inst_offset, cfg->frame_reg);
3041                         ia64_ld8_hint (code, GP_SCRATCH_REG, GP_SCRATCH_REG, 0);
3042
3043                         /* Test caller */
3044                         ia64_cmp_eq (code, 6, 7, GP_SCRATCH_REG, IA64_R0);
3045                         ia64_br_cond_pred (code, 7, 4);
3046
3047                         /* Called by call_filter */
3048                         /* Pop frame */
3049                         ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
3050                         ia64_mov_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
3051                         ia64_br_ret_reg (code, IA64_B0);                        
3052
3053                         /* Called by CALL_HANDLER */
3054                         ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG);
3055                         ia64_br_cond_reg (code, IA64_B6);
3056                         break;
3057                 }
3058                 case OP_THROW:
3059                         ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3060                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3061                                                           (gpointer)"mono_arch_throw_exception");
3062
3063                         /* 
3064                          * This might be the last instruction in the method, so add a dummy
3065                          * instruction so the unwinder will work.
3066                          */
3067                         ia64_break_i (code, 0);
3068                         break;
3069                 case OP_RETHROW:
3070                         ia64_mov (code, cfg->arch.reg_out0, ins->sreg1);
3071                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3072                                                           (gpointer)"mono_arch_rethrow_exception");
3073
3074                         ia64_break_i (code, 0);
3075                         break;
3076
3077                 default:
3078                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3079                         g_assert_not_reached ();
3080                 }
3081
3082                 if ((code.buf - cfg->native_code - offset) > max_len) {
3083                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3084                                    mono_inst_name (ins->opcode), max_len, code.buf - cfg->native_code - offset);
3085                         g_assert_not_reached ();
3086                 }
3087                
3088                 cpos += max_len;
3089
3090                 last_ins = ins;
3091                 last_offset = offset;
3092                 
3093                 ins = ins->next;
3094         }
3095
3096         ia64_codegen_close (code);
3097
3098         cfg->code_len = code.buf - cfg->native_code;
3099 }
3100
3101 void
3102 mono_arch_register_lowlevel_calls (void)
3103 {
3104         mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
3105 }
3106
3107 static Ia64InsType ins_types_in_template [32][3] = {
3108         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_I},
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_LX, IA64_INS_TYPE_LX},
3113         {IA64_INS_TYPE_M, IA64_INS_TYPE_LX, IA64_INS_TYPE_LX},
3114         {0, 0, 0},
3115         {0, 0, 0},
3116         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_I},
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_F, 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_M, IA64_INS_TYPE_F},
3123         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_F},
3124         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3125         {IA64_INS_TYPE_M, IA64_INS_TYPE_I, IA64_INS_TYPE_B},
3126         {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3127         {IA64_INS_TYPE_M, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3128         {0, 0, 0},
3129         {0, 0, 0},
3130         {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3131         {IA64_INS_TYPE_B, IA64_INS_TYPE_B, IA64_INS_TYPE_B},
3132         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3133         {IA64_INS_TYPE_M, IA64_INS_TYPE_M, IA64_INS_TYPE_B},
3134         {0, 0, 0},
3135         {0, 0, 0},
3136         {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3137         {IA64_INS_TYPE_M, IA64_INS_TYPE_F, IA64_INS_TYPE_B},
3138         {0, 0, 0},
3139         {0, 0, 0}
3140 };
3141
3142 static gboolean stops_in_template [32][3] = {
3143         { FALSE, FALSE, FALSE },
3144         { FALSE, FALSE, TRUE },
3145         { FALSE, TRUE, FALSE },
3146         { FALSE, TRUE, TRUE },
3147         { FALSE, FALSE, FALSE },
3148         { FALSE, FALSE, TRUE },
3149         { FALSE, FALSE, FALSE },
3150         { FALSE, FALSE, FALSE },
3151
3152         { FALSE, FALSE, FALSE },
3153         { FALSE, FALSE, TRUE },
3154         { TRUE, FALSE, FALSE },
3155         { TRUE, FALSE, TRUE },
3156         { FALSE, FALSE, FALSE },
3157         { FALSE, FALSE, TRUE },
3158         { FALSE, FALSE, FALSE },
3159         { FALSE, FALSE, TRUE },
3160
3161         { FALSE, FALSE, FALSE },
3162         { FALSE, FALSE, TRUE },
3163         { FALSE, FALSE, FALSE },
3164         { FALSE, FALSE, TRUE },
3165         { FALSE, FALSE, FALSE },
3166         { FALSE, FALSE, FALSE },
3167         { FALSE, FALSE, FALSE },
3168         { FALSE, FALSE, TRUE },
3169
3170         { FALSE, FALSE, FALSE },
3171         { FALSE, FALSE, TRUE },
3172         { FALSE, FALSE, FALSE },
3173         { FALSE, FALSE, FALSE },
3174         { FALSE, FALSE, FALSE },
3175         { FALSE, FALSE, TRUE },
3176         { FALSE, FALSE, FALSE },
3177         { FALSE, FALSE, FALSE }
3178 };
3179
3180 static int last_stop_in_template [32] = {
3181         -1, 2, 1, 2, -1, 2, -1, -1,
3182         -1, 2, 0, 2, -1, 2, -1, 2,
3183         -1, 2, -1, 2, -1, -1, -1, 2,
3184         -1, 2, -1, -1, -1, 2, -1, -1
3185 };
3186
3187 static guint64 nops_for_ins_types [6] = {
3188         IA64_NOP_I,
3189         IA64_NOP_I,
3190         IA64_NOP_M,
3191         IA64_NOP_F,
3192         IA64_NOP_B,
3193         IA64_NOP_X
3194 };
3195
3196 #define ITYPE_MATCH(itype1, itype2) (((itype1) == (itype2)) || (((itype2) == IA64_INS_TYPE_A) && (((itype1) == IA64_INS_TYPE_I) || ((itype1) == IA64_INS_TYPE_M))))
3197
3198 /* 
3199  * Debugging support
3200  */
3201
3202 #if 0
3203 #define DEBUG_INS_SCHED(a) do { a; } while (0)
3204 #else
3205 #define DEBUG_INS_SCHED(a)
3206 #endif
3207
3208 static void
3209 ia64_analyze_deps (Ia64CodegenState *code, int *deps_start, int *stops)
3210 {
3211         int i, pos, ins_index, current_deps_start, current_ins_start, reg;
3212         guint8 *deps = code->dep_info;
3213         gboolean need_stop, no_stop;
3214
3215         for (i = 0; i < code->nins; ++i)
3216                 stops [i] = FALSE;
3217         
3218         ins_index = 0;
3219         current_deps_start = 0;
3220         current_ins_start = 0;
3221         deps_start [ins_index] = current_ins_start;
3222         pos = 0;
3223         no_stop = FALSE;
3224         DEBUG_INS_SCHED (printf ("BEGIN.\n"));
3225         while (pos < code->dep_info_pos) {
3226                 need_stop = FALSE;
3227                 switch (deps [pos]) {
3228                 case IA64_END_OF_INS:
3229                         ins_index ++;
3230                         current_ins_start = pos + 2;
3231                         deps_start [ins_index] = current_ins_start;
3232                         no_stop = FALSE;
3233                         DEBUG_INS_SCHED (printf ("(%d) END INS.\n", ins_index - 1));
3234                         break;
3235                 case IA64_NONE:
3236                         break;
3237                 case IA64_READ_GR:
3238                         reg = deps [pos + 1];
3239
3240                         DEBUG_INS_SCHED (printf ("READ GR: %d\n", reg));
3241                         for (i = current_deps_start; i < current_ins_start; i += 2)
3242                                 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3243                                         need_stop = TRUE;
3244                         break;
3245                 case IA64_WRITE_GR:
3246                         reg = code->dep_info [pos + 1];
3247
3248                         DEBUG_INS_SCHED (printf ("WRITE GR: %d\n", reg));
3249                         for (i = current_deps_start; i < current_ins_start; i += 2)
3250                                 if (deps [i] == IA64_WRITE_GR && deps [i + 1] == reg)
3251                                         need_stop = TRUE;
3252                         break;
3253                 case IA64_READ_PR:
3254                         reg = deps [pos + 1];
3255
3256                         DEBUG_INS_SCHED (printf ("READ PR: %d\n", reg));
3257                         for (i = current_deps_start; i < current_ins_start; i += 2)
3258                                 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3259                                         need_stop = TRUE;
3260                         break;
3261                 case IA64_READ_PR_BRANCH:
3262                         reg = deps [pos + 1];
3263
3264                         /* Writes to prs by non-float instructions are visible to branches */
3265                         DEBUG_INS_SCHED (printf ("READ PR BRANCH: %d\n", reg));
3266                         for (i = current_deps_start; i < current_ins_start; i += 2)
3267                                 if (deps [i] == IA64_WRITE_PR_FLOAT && deps [i + 1] == reg)
3268                                         need_stop = TRUE;
3269                         break;
3270                 case IA64_WRITE_PR:
3271                         reg = code->dep_info [pos + 1];
3272
3273                         DEBUG_INS_SCHED (printf ("WRITE PR: %d\n", reg));
3274                         for (i = current_deps_start; i < current_ins_start; i += 2)
3275                                 if (((deps [i] == IA64_WRITE_PR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3276                                         need_stop = TRUE;
3277                         break;
3278                 case IA64_WRITE_PR_FLOAT:
3279                         reg = code->dep_info [pos + 1];
3280
3281                         DEBUG_INS_SCHED (printf ("WRITE PR FP: %d\n", reg));
3282                         for (i = current_deps_start; i < current_ins_start; i += 2)
3283                                 if (((deps [i] == IA64_WRITE_GR) || (deps [i] == IA64_WRITE_PR_FLOAT)) && deps [i + 1] == reg)
3284                                         need_stop = TRUE;
3285                         break;
3286                 case IA64_READ_BR:
3287                         reg = deps [pos + 1];
3288
3289                         DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3290                         for (i = current_deps_start; i < current_ins_start; i += 2)
3291                                 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3292                                         need_stop = TRUE;
3293                         break;
3294                 case IA64_WRITE_BR:
3295                         reg = code->dep_info [pos + 1];
3296
3297                         DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3298                         for (i = current_deps_start; i < current_ins_start; i += 2)
3299                                 if (deps [i] == IA64_WRITE_BR && deps [i + 1] == reg)
3300                                         need_stop = TRUE;
3301                         break;
3302                 case IA64_READ_BR_BRANCH:
3303                         reg = deps [pos + 1];
3304
3305                         /* Writes to brs are visible to branches */
3306                         DEBUG_INS_SCHED (printf ("READ BR BRACH: %d\n", reg));
3307                         break;
3308                 case IA64_READ_FR:
3309                         reg = deps [pos + 1];
3310
3311                         DEBUG_INS_SCHED (printf ("READ BR: %d\n", reg));
3312                         for (i = current_deps_start; i < current_ins_start; i += 2)
3313                                 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3314                                         need_stop = TRUE;
3315                         break;
3316                 case IA64_WRITE_FR:
3317                         reg = code->dep_info [pos + 1];
3318
3319                         DEBUG_INS_SCHED (printf ("WRITE BR: %d\n", reg));
3320                         for (i = current_deps_start; i < current_ins_start; i += 2)
3321                                 if (deps [i] == IA64_WRITE_FR && deps [i + 1] == reg)
3322                                         need_stop = TRUE;
3323                         break;
3324                 case IA64_READ_AR:
3325                         reg = deps [pos + 1];
3326
3327                         DEBUG_INS_SCHED (printf ("READ AR: %d\n", reg));
3328                         for (i = current_deps_start; i < current_ins_start; i += 2)
3329                                 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3330                                         need_stop = TRUE;
3331                         break;
3332                 case IA64_WRITE_AR:
3333                         reg = code->dep_info [pos + 1];
3334
3335                         DEBUG_INS_SCHED (printf ("WRITE AR: %d\n", reg));
3336                         for (i = current_deps_start; i < current_ins_start; i += 2)
3337                                 if (deps [i] == IA64_WRITE_AR && deps [i + 1] == reg)
3338                                         need_stop = TRUE;
3339                         break;
3340                 case IA64_NO_STOP:
3341                         /* 
3342                          * Explicitly indicate that a stop is not required. Useful for
3343                          * example when two predicated instructions with negated predicates
3344                          * write the same registers.
3345                          */
3346                         no_stop = TRUE;
3347                         break;
3348                 default:
3349                         g_assert_not_reached ();
3350                 }
3351                 pos += 2;
3352
3353                 if (need_stop && !no_stop) {
3354                         g_assert (ins_index > 0);
3355                         stops [ins_index - 1] = 1;
3356
3357                         DEBUG_INS_SCHED (printf ("STOP\n"));
3358                         current_deps_start = current_ins_start;
3359
3360                         /* Skip remaining deps for this instruction */
3361                         while (deps [pos] != IA64_END_OF_INS)
3362                                 pos += 2;
3363                 }
3364         }
3365
3366         if (code->nins > 0) {
3367                 /* No dependency info for the last instruction */
3368                 stops [code->nins - 1] = 1;
3369         }
3370
3371         deps_start [code->nins] = code->dep_info_pos;
3372 }
3373
3374 static void
3375 ia64_real_emit_bundle (Ia64CodegenState *code, int *deps_start, int *stops, int n, guint64 template, guint64 ins1, guint64 ins2, guint64 ins3, guint8 nops)
3376 {
3377         int stop_pos, i, deps_to_shift, dep_shift;
3378
3379         g_assert (n <= code->nins);
3380
3381         // if (n > 1) printf ("FOUND: %ld.\n", template);
3382
3383         ia64_emit_bundle_template (code, template, ins1, ins2, ins3);
3384
3385         stop_pos = last_stop_in_template [template] + 1;
3386         if (stop_pos > n)
3387                 stop_pos = n;
3388
3389         /* Compute the number of 'real' instructions before the stop */
3390         deps_to_shift = stop_pos;
3391         if (stop_pos >= 3 && (nops & (1 << 2)))
3392                 deps_to_shift --;
3393         if (stop_pos >= 2 && (nops & (1 << 1)))
3394                 deps_to_shift --;
3395         if (stop_pos >= 1 && (nops & (1 << 0)))
3396                 deps_to_shift --;
3397
3398         /* 
3399          * We have to keep some dependencies whose instructions have been shifted
3400          * out of the buffer. So nullify the end_of_ins markers in the dependency
3401          * array.
3402          */
3403         for (i = deps_start [deps_to_shift]; i < deps_start [n]; i += 2)
3404                 if (code->dep_info [i] == IA64_END_OF_INS)
3405                         code->dep_info [i] = IA64_NONE;
3406
3407         g_assert (deps_start [deps_to_shift] <= code->dep_info_pos);
3408         memcpy (code->dep_info, &code->dep_info [deps_start [deps_to_shift]], code->dep_info_pos - deps_start [deps_to_shift]);
3409         code->dep_info_pos = code->dep_info_pos - deps_start [deps_to_shift];
3410
3411         dep_shift = deps_start [deps_to_shift];
3412         for (i = 0; i < code->nins + 1 - n; ++i)
3413                 deps_start [i] = deps_start [n + i] - dep_shift;
3414
3415         /* Determine the exact positions of instructions with unwind ops */
3416         if (code->unw_op_count) {
3417                 int ins_pos [16];
3418                 int curr_ins, curr_ins_pos;
3419
3420                 curr_ins = 0;
3421                 curr_ins_pos = ((code->buf - code->region_start - 16) / 16) * 3;
3422                 for (i = 0; i < 3; ++i) {
3423                         if (! (nops & (1 << i))) {
3424                                 ins_pos [curr_ins] = curr_ins_pos + i;
3425                                 curr_ins ++;
3426                         }
3427                 }
3428
3429                 for (i = code->unw_op_pos; i < code->unw_op_count; ++i) {
3430                         if (code->unw_ops_pos [i] < n) {
3431                                 code->unw_ops [i].when = ins_pos [code->unw_ops_pos [i]];
3432                                 //printf ("UNW-OP: %d -> %d\n", code->unw_ops_pos [i], code->unw_ops [i].when);
3433                         }
3434                 }
3435                 if (code->unw_op_pos < code->unw_op_count)
3436                         code->unw_op_pos += n;
3437         }
3438
3439         if (n == code->nins) {
3440                 code->template = 0;
3441                 code->nins = 0;
3442         }               
3443         else {
3444                 memcpy (&code->instructions [0], &code->instructions [n], (code->nins - n) * sizeof (guint64));
3445                 memcpy (&code->itypes [0], &code->itypes [n], (code->nins - n) * sizeof (int));
3446                 memcpy (&stops [0], &stops [n], (code->nins - n) * sizeof (int));
3447                 code->nins -= n;
3448         }
3449 }
3450
3451 void
3452 ia64_emit_bundle (Ia64CodegenState *code, gboolean flush)
3453 {
3454         int i, ins_type, template, nins_to_emit;
3455         int deps_start [16];
3456         int stops [16];
3457         gboolean found;
3458
3459         /*
3460          * We implement a simple scheduler which tries to put three instructions 
3461          * per bundle, then two, then one.
3462          */
3463         ia64_analyze_deps (code, deps_start, stops);
3464
3465         if ((code->nins >= 3) && !code->one_ins_per_bundle) {
3466                 /* Find a suitable template */
3467                 for (template = 0; template < 32; ++template) {
3468                         if (stops_in_template [template][0] != stops [0] ||
3469                                 stops_in_template [template][1] != stops [1] ||
3470                                 stops_in_template [template][2] != stops [2])
3471                                 continue;
3472
3473                         found = TRUE;
3474                         for (i = 0; i < 3; ++i) {
3475                                 ins_type = ins_types_in_template [template][i];
3476                                 switch (code->itypes [i]) {
3477                                 case IA64_INS_TYPE_A:
3478                                         found &= (ins_type == IA64_INS_TYPE_I) || (ins_type == IA64_INS_TYPE_M);
3479                                         break;
3480                                 default:
3481                                         found &= (ins_type == code->itypes [i]);
3482                                         break;
3483                                 }
3484                         }
3485
3486                         if (found)
3487                                 found = debug_ins_sched ();
3488
3489                         if (found) {
3490                                 ia64_real_emit_bundle (code, deps_start, stops, 3, template, code->instructions [0], code->instructions [1], code->instructions [2], 0);
3491                                 break;
3492                         }
3493                 }
3494         }
3495
3496         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3497                 /* Wait for more instructions */
3498                 return;
3499
3500         /* If it didn't work out, try putting two instructions into one bundle */
3501         if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3502                 /* Try a nop at the end */
3503                 for (template = 0; template < 32; ++template) {
3504                         if (stops_in_template [template][0] != stops [0] ||
3505                                 ((stops_in_template [template][1] != stops [1]) &&
3506                                  (stops_in_template [template][2] != stops [1])))
3507                                  
3508                                 continue;
3509
3510                         if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3511                                 !ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [1]))
3512                                 continue;
3513
3514                         if (!debug_ins_sched ())
3515                                 continue;
3516
3517                         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);
3518                         break;
3519                 }
3520         }
3521
3522         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3523                 /* Wait for more instructions */
3524                 return;
3525
3526         if ((code->nins >= 2) && !code->one_ins_per_bundle) {
3527                 /* Try a nop in the middle */
3528                 for (template = 0; template < 32; ++template) {
3529                         if (((stops_in_template [template][0] != stops [0]) &&
3530                                  (stops_in_template [template][1] != stops [0])) ||
3531                                 stops_in_template [template][2] != stops [1])
3532                                 continue;
3533
3534                         if (!ITYPE_MATCH (ins_types_in_template [template][0], code->itypes [0]) ||
3535                                 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3536                                 continue;
3537
3538                         if (!debug_ins_sched ())
3539                                 continue;
3540
3541                         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);
3542                         break;
3543                 }
3544         }
3545
3546         if ((code->nins >= 2) && flush && !code->one_ins_per_bundle) {
3547                 /* Try a nop at the beginning */
3548                 for (template = 0; template < 32; ++template) {
3549                         if ((stops_in_template [template][1] != stops [0]) ||
3550                                 (stops_in_template [template][2] != stops [1]))
3551                                 continue;
3552
3553                         if (!ITYPE_MATCH (ins_types_in_template [template][1], code->itypes [0]) ||
3554                                 !ITYPE_MATCH (ins_types_in_template [template][2], code->itypes [1]))
3555                                 continue;
3556
3557                         if (!debug_ins_sched ())
3558                                 continue;
3559
3560                         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);
3561                         break;
3562                 }
3563         }
3564
3565         if (code->nins < IA64_INS_BUFFER_SIZE && !flush)
3566                 /* Wait for more instructions */
3567                 return;
3568
3569         if (flush)
3570                 nins_to_emit = code->nins;
3571         else
3572                 nins_to_emit = 1;
3573
3574         while (nins_to_emit > 0) {
3575                 if (!debug_ins_sched ())
3576                         stops [0] = 1;
3577                 switch (code->itypes [0]) {
3578                 case IA64_INS_TYPE_A:
3579                         if (stops [0])
3580                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3581                         else
3582                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3583                         break;
3584                 case IA64_INS_TYPE_I:
3585                         if (stops [0])
3586                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3587                         else
3588                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3589                         break;
3590                 case IA64_INS_TYPE_M:
3591                         if (stops [0])
3592                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIIS, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3593                         else
3594                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MII, code->instructions [0], IA64_NOP_I, IA64_NOP_I, 0);
3595                         break;
3596                 case IA64_INS_TYPE_B:
3597                         if (stops [0])
3598                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIBS, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3599                         else
3600                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MIB, IA64_NOP_M, IA64_NOP_I, code->instructions [0], 0);
3601                         break;
3602                 case IA64_INS_TYPE_F:
3603                         if (stops [0])
3604                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFIS, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3605                         else
3606                                 ia64_real_emit_bundle (code, deps_start, stops, 1, IA64_TEMPLATE_MFI, IA64_NOP_M, code->instructions [0], IA64_NOP_I, 0);
3607                         break;
3608                 case IA64_INS_TYPE_LX:
3609                         if (stops [0] || stops [1])
3610                                 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLXS, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3611                         else
3612                                 ia64_real_emit_bundle (code, deps_start, stops, 2, IA64_TEMPLATE_MLX, IA64_NOP_M, code->instructions [0], code->instructions [1], 0);
3613                         nins_to_emit --;
3614                         break;
3615                 default:
3616                         g_assert_not_reached ();
3617                 }
3618                 nins_to_emit --;
3619         }
3620 }
3621
3622 unw_dyn_region_info_t*
3623 mono_ia64_create_unwind_region (Ia64CodegenState *code)
3624 {
3625         unw_dyn_region_info_t *r;
3626
3627         g_assert (code->nins == 0);
3628         r = g_malloc0 (_U_dyn_region_info_size (code->unw_op_count));
3629         memcpy (&r->op, &code->unw_ops, sizeof (unw_dyn_op_t) * code->unw_op_count);
3630         r->op_count = code->unw_op_count;
3631         r->insn_count = ((code->buf - code->region_start) >> 4) * 3;
3632         code->unw_op_count = 0;
3633         code->unw_op_pos = 0;
3634         code->region_start = code->buf;
3635
3636         return r;
3637 }
3638
3639 static void 
3640 ia64_patch (unsigned char* code, gpointer target)
3641 {
3642         int template, i;
3643         guint64 instructions [3];
3644         guint8 gen_buf [16];
3645         Ia64CodegenState gen;
3646         int ins_to_skip;
3647         gboolean found;
3648
3649         /* 
3650          * code encodes both the position inside the buffer and code.nins when
3651          * the instruction was emitted.
3652          */
3653         ins_to_skip = (guint64)code % 16;
3654         code = (unsigned char*)((guint64)code & ~15);
3655
3656         /*
3657          * Search for the first instruction which is 'patchable', skipping
3658          * ins_to_skip instructions.
3659          */
3660
3661         while (TRUE) {
3662
3663         template = ia64_bundle_template (code);
3664         instructions [0] = ia64_bundle_ins1 (code);
3665         instructions [1] = ia64_bundle_ins2 (code);
3666         instructions [2] = ia64_bundle_ins3 (code);
3667
3668         ia64_codegen_init (gen, gen_buf);
3669
3670         found = FALSE;
3671         for (i = 0; i < 3; ++i) {
3672                 guint64 ins = instructions [i];
3673                 int opcode = ia64_ins_opcode (ins);
3674
3675                 if (ins == nops_for_ins_types [ins_types_in_template [template][i]])
3676                         continue;
3677
3678                 if (ins_to_skip) {
3679                         ins_to_skip --;
3680                         continue;
3681                 }
3682
3683                 switch (ins_types_in_template [template][i]) {
3684                 case IA64_INS_TYPE_A:
3685                 case IA64_INS_TYPE_M:
3686                         if ((opcode == 8) && (ia64_ins_x2a (ins) == 2) && (ia64_ins_ve (ins) == 0)) {
3687                                 /* adds */
3688                                 ia64_adds_imm_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), (guint64)target, ia64_ins_r3 (ins));
3689                                 instructions [i] = gen.instructions [0];
3690                                 found = TRUE;
3691                         }
3692                         else
3693                                 NOT_IMPLEMENTED;
3694                         break;
3695                 case IA64_INS_TYPE_B:
3696                         if ((opcode == 4) && (ia64_ins_btype (ins) == 0)) {
3697                                 /* br.cond */
3698                                 gint64 disp = ((guint8*)target - code) >> 4;
3699
3700                                 /* FIXME: hints */
3701                                 ia64_br_cond_hint_pred (gen, ia64_ins_qp (ins), disp, 0, 0, 0);
3702                                 
3703                                 instructions [i] = gen.instructions [0];
3704                                 found = TRUE;
3705                         }
3706                         else if (opcode == 5) {
3707                                 /* br.call */
3708                                 gint64 disp = ((guint8*)target - code) >> 4;
3709
3710                                 /* FIXME: hints */
3711                                 ia64_br_call_hint_pred (gen, ia64_ins_qp (ins), ia64_ins_b1 (ins), disp, 0, 0, 0);
3712                                 instructions [i] = gen.instructions [0];
3713                                 found = TRUE;
3714                         }
3715                         else
3716                                 NOT_IMPLEMENTED;
3717                         break;
3718                 case IA64_INS_TYPE_LX:
3719                         if (i == 1)
3720                                 break;
3721
3722                         if ((opcode == 6) && (ia64_ins_vc (ins) == 0)) {
3723                                 /* movl */
3724                                 ia64_movl_pred (gen, ia64_ins_qp (ins), ia64_ins_r1 (ins), target);
3725                                 instructions [1] = gen.instructions [0];
3726                                 instructions [2] = gen.instructions [1];
3727                                 found = TRUE;
3728                         }
3729                         else
3730                                 NOT_IMPLEMENTED;
3731
3732                         break;
3733                 default:
3734                         NOT_IMPLEMENTED;
3735                 }
3736
3737                 if (found) {
3738                         /* Rewrite code */
3739                         ia64_codegen_init (gen, code);
3740                         ia64_emit_bundle_template (&gen, template, instructions [0], instructions [1], instructions [2]);
3741                         return;
3742                 }
3743         }
3744
3745         code += 16;
3746         }
3747 }
3748
3749 void
3750 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3751 {
3752         MonoJumpInfo *patch_info;
3753
3754         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3755                 unsigned char *ip = patch_info->ip.i + code;
3756                 const unsigned char *target;
3757
3758                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3759
3760                 if (patch_info->type == MONO_PATCH_INFO_NONE)
3761                         continue;
3762                 if (mono_compile_aot) {
3763                         NOT_IMPLEMENTED;
3764                 }
3765
3766                 ia64_patch (ip, (gpointer)target);
3767         }
3768 }
3769
3770 guint8 *
3771 mono_arch_emit_prolog (MonoCompile *cfg)
3772 {
3773         MonoMethod *method = cfg->method;
3774         MonoMethodSignature *sig;
3775         MonoInst *inst;
3776         int alloc_size, pos, i;
3777         Ia64CodegenState code;
3778         CallInfo *cinfo;
3779         
3780         sig = mono_method_signature (method);
3781         pos = 0;
3782
3783         cinfo = get_call_info (sig, FALSE);
3784
3785         cfg->code_size =  MAX (((MonoMethodNormal *)method)->header->code_size * 4, 512);
3786
3787         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3788                 cfg->code_size += 1024;
3789         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3790                 cfg->code_size += 1024;
3791
3792         cfg->native_code = g_malloc (cfg->code_size);
3793
3794         ia64_codegen_init (code, cfg->native_code);
3795
3796         alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
3797         if (cfg->param_area)
3798                 alloc_size += cfg->param_area;
3799         if (alloc_size)
3800                 /* scratch area */
3801                 alloc_size += 16;
3802         alloc_size = ALIGN_TO (alloc_size, MONO_ARCH_FRAME_ALIGNMENT);
3803
3804         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3805                 /* Force sp to be saved/restored */
3806                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT;
3807
3808         cfg->arch.stack_alloc_size = alloc_size;
3809
3810         pos = 0;
3811
3812         if (method->save_lmf) {
3813                 /* No LMF on IA64 */
3814         }
3815
3816         alloc_size -= pos;
3817
3818         ia64_unw_save_reg (code, UNW_IA64_AR_PFS, UNW_IA64_GR + cfg->arch.reg_saved_ar_pfs);
3819         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);
3820         ia64_unw_save_reg (code, UNW_IA64_RP, UNW_IA64_GR + cfg->arch.reg_saved_b0);
3821         ia64_mov_from_br (code, cfg->arch.reg_saved_b0, IA64_B0);
3822
3823         if ((alloc_size || cinfo->stack_usage) && !cfg->arch.omit_fp) {
3824                 ia64_unw_save_reg (code, UNW_IA64_SP, UNW_IA64_GR + cfg->arch.reg_saved_sp);
3825                 ia64_mov (code, cfg->arch.reg_saved_sp, IA64_SP);
3826                 if (cfg->frame_reg != cfg->arch.reg_saved_sp)
3827                         ia64_mov (code, cfg->frame_reg, IA64_SP);
3828         }
3829
3830         if (alloc_size) {
3831                 int pagesize = getpagesize ();
3832
3833 #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3834                 if (alloc_size >= pagesize) {
3835                         gint32 remaining_size = alloc_size;
3836
3837                         /* Generate stack touching code */
3838                         ia64_mov (code, GP_SCRATCH_REG, IA64_SP);                       
3839                         while (remaining_size >= pagesize) {
3840                                 ia64_movl (code, GP_SCRATCH_REG2, pagesize);
3841                                 ia64_sub (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3842                                 ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
3843                                 remaining_size -= pagesize;
3844                         }
3845                 }
3846 #endif
3847                 if (ia64_is_imm14 (-alloc_size)) {
3848                         if (cfg->arch.omit_fp)
3849                                 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3850                         ia64_adds_imm (code, IA64_SP, (-alloc_size), IA64_SP);
3851                 }
3852                 else {
3853                         ia64_movl (code, GP_SCRATCH_REG, -alloc_size);
3854                         if (cfg->arch.omit_fp)
3855                                 ia64_unw_add (code, UNW_IA64_SP, (-alloc_size));
3856                         ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
3857                 }
3858         }
3859
3860         ia64_begin_bundle (code);
3861
3862         /* Initialize unwind info */
3863         cfg->arch.r_pro = mono_ia64_create_unwind_region (&code);
3864
3865         if (sig->ret->type != MONO_TYPE_VOID) {
3866                 if ((cinfo->ret.storage == ArgInIReg) && (cfg->ret->opcode != OP_REGVAR)) {
3867                         /* Save volatile arguments to the stack */
3868                         NOT_IMPLEMENTED;
3869                 }
3870         }
3871
3872         /* Keep this in sync with emit_load_volatile_arguments */
3873         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3874                 ArgInfo *ainfo = cinfo->args + i;
3875                 gint32 stack_offset;
3876                 MonoType *arg_type;
3877                 inst = cfg->args [i];
3878
3879                 if (sig->hasthis && (i == 0))
3880                         arg_type = &mono_defaults.object_class->byval_arg;
3881                 else
3882                         arg_type = sig->params [i - sig->hasthis];
3883
3884                 arg_type = mono_type_get_underlying_type (arg_type);
3885
3886                 stack_offset = ainfo->offset + ARGS_OFFSET;
3887
3888                 /* Save volatile arguments to the stack */
3889                 if (inst->opcode != OP_REGVAR) {
3890                         switch (ainfo->storage) {
3891                         case ArgInIReg:
3892                         case ArgInFloatReg:
3893                                 g_assert (inst->opcode == OP_REGOFFSET);
3894                                 if (ia64_is_adds_imm (inst->inst_offset))
3895                                         ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3896                                 else {
3897                                         ia64_movl (code, GP_SCRATCH_REG2, inst->inst_offset);
3898                                         ia64_add (code, GP_SCRATCH_REG, GP_SCRATCH_REG, GP_SCRATCH_REG2);
3899                                 }
3900                                 if (arg_type->byref)
3901                                         ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3902                                 else {
3903                                         switch (arg_type->type) {
3904                                         case MONO_TYPE_R4:
3905                                                 ia64_stfs_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3906                                                 break;
3907                                         case MONO_TYPE_R8:
3908                                                 ia64_stfd_hint (code, GP_SCRATCH_REG, ainfo->reg, 0);
3909                                                 break;
3910                                         default:
3911                                                 ia64_st8_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg, 0);
3912                                                 break;
3913                                         }
3914                                 }
3915                                 break;
3916                         case ArgOnStack:
3917                                 break;
3918                         case ArgAggregate:
3919                                 if (ainfo->nslots != ainfo->nregs)
3920                                         NOT_IMPLEMENTED;
3921
3922                                 g_assert (inst->opcode == OP_REGOFFSET);
3923                                 ia64_adds_imm (code, GP_SCRATCH_REG, inst->inst_offset, inst->inst_basereg);
3924                                 for (i = 0; i < ainfo->nregs; ++i) {
3925                                         switch (ainfo->atype) {
3926                                         case AggregateNormal:
3927                                                 ia64_st8_inc_imm_hint (code, GP_SCRATCH_REG, cfg->arch.reg_in0 + ainfo->reg + i, sizeof (gpointer), 0);
3928                                                 break;
3929                                         case AggregateSingleHFA:
3930                                                 ia64_stfs_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, 4, 0);
3931                                                 break;
3932                                         case AggregateDoubleHFA:
3933                                                 ia64_stfd_inc_imm_hint (code, GP_SCRATCH_REG, ainfo->reg + i, sizeof (gpointer), 0);
3934                                                 break;
3935                                         default:
3936                                                 NOT_IMPLEMENTED;
3937                                         }
3938                                 }
3939                                 break;
3940                         default:
3941                                 g_assert_not_reached ();
3942                         }
3943                 }
3944
3945                 if (inst->opcode == OP_REGVAR) {
3946                         /* Argument allocated to (non-volatile) register */
3947                         switch (ainfo->storage) {
3948                         case ArgInIReg:
3949                                 if (inst->dreg != cfg->arch.reg_in0 + ainfo->reg)
3950                                         ia64_mov (code, inst->dreg, cfg->arch.reg_in0 + ainfo->reg);
3951                                 break;
3952                         case ArgOnStack:
3953                                 ia64_adds_imm (code, GP_SCRATCH_REG, 16 + ainfo->offset, cfg->frame_reg);
3954                                 ia64_ld8 (code, inst->dreg, GP_SCRATCH_REG);
3955                                 break;
3956                         default:
3957                                 NOT_IMPLEMENTED;
3958                         }
3959                 }
3960         }
3961
3962         if (method->save_lmf) {
3963                 /* No LMF on IA64 */
3964         }
3965
3966         ia64_codegen_close (code);
3967
3968         g_free (cinfo);
3969
3970         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3971                 code.buf = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code.buf, TRUE);
3972
3973         cfg->code_len = code.buf - cfg->native_code;
3974
3975         g_assert (cfg->code_len < cfg->code_size);
3976
3977         cfg->arch.prolog_end_offset = cfg->code_len;
3978
3979         return code.buf;
3980 }
3981
3982 void
3983 mono_arch_emit_epilog (MonoCompile *cfg)
3984 {
3985         MonoMethod *method = cfg->method;
3986         int i, pos;
3987         int max_epilog_size = 16 * 4;
3988         Ia64CodegenState code;
3989         guint8 *buf;
3990         CallInfo *cinfo;
3991         ArgInfo *ainfo;
3992
3993         if (mono_jit_trace_calls != NULL)
3994                 max_epilog_size += 1024;
3995
3996         cfg->arch.epilog_begin_offset = cfg->code_len;
3997
3998         while (cfg->code_len + max_epilog_size > cfg->code_size) {
3999                 cfg->code_size *= 2;
4000                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4001                 mono_jit_stats.code_reallocs++;
4002         }
4003
4004         /* FIXME: Emit unwind info */
4005
4006         buf = cfg->native_code + cfg->code_len;
4007
4008         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4009                 buf = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, buf, TRUE);
4010
4011         ia64_codegen_init (code, buf);
4012
4013         /* the code restoring the registers must be kept in sync with OP_JMP */
4014         pos = 0;
4015         
4016         if (method->save_lmf) {
4017                 /* No LMF on IA64 */
4018         }
4019
4020         /* Load returned vtypes into registers if needed */
4021         cinfo = get_call_info (mono_method_signature (method), FALSE);
4022         ainfo = &cinfo->ret;
4023         switch (ainfo->storage) {
4024         case ArgAggregate:
4025                 if (ainfo->nslots != ainfo->nregs)
4026                         NOT_IMPLEMENTED;
4027
4028                 g_assert (cfg->ret->opcode == OP_REGOFFSET);
4029                 ia64_adds_imm (code, GP_SCRATCH_REG, cfg->ret->inst_offset, cfg->ret->inst_basereg);
4030                 for (i = 0; i < ainfo->nregs; ++i) {
4031                         switch (ainfo->atype) {
4032                         case AggregateNormal:
4033                                 ia64_ld8_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4034                                 break;
4035                         case AggregateSingleHFA:
4036                                 ia64_ldfs_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, 4, 0);
4037                                 break;
4038                         case AggregateDoubleHFA:
4039                                 ia64_ldfd_inc_imm_hint (code, ainfo->reg + i, GP_SCRATCH_REG, sizeof (gpointer), 0);
4040                                 break;
4041                         default:
4042                                 g_assert_not_reached ();
4043                         }
4044                 }
4045                 break;
4046         default:
4047                 break;
4048         }
4049         g_free (cinfo);
4050
4051         ia64_begin_bundle (code);
4052
4053         code.region_start = cfg->native_code;
4054
4055         /* Label the unwind state at the start of the exception throwing region */
4056         //ia64_unw_label_state (code, 1234);
4057
4058         if (cfg->arch.stack_alloc_size) {
4059                 if (cfg->arch.omit_fp) {
4060                         if (ia64_is_imm14 (cfg->arch.stack_alloc_size)) {
4061                                 ia64_unw_pop_frames (code, 1);
4062                                 ia64_adds_imm (code, IA64_SP, (cfg->arch.stack_alloc_size), IA64_SP);
4063                         } else {
4064                                 ia64_movl (code, GP_SCRATCH_REG, cfg->arch.stack_alloc_size);
4065                                 ia64_unw_pop_frames (code, 1);
4066                                 ia64_add (code, IA64_SP, GP_SCRATCH_REG, IA64_SP);
4067                         }
4068                 }
4069                 else {
4070                         ia64_unw_pop_frames (code, 1);
4071                         ia64_mov (code, IA64_SP, cfg->arch.reg_saved_sp);
4072                 }
4073         }
4074         ia64_mov_to_ar_i (code, IA64_PFS, cfg->arch.reg_saved_ar_pfs);
4075         ia64_mov_ret_to_br (code, IA64_B0, cfg->arch.reg_saved_b0);
4076         ia64_br_ret_reg (code, IA64_B0);
4077
4078         ia64_codegen_close (code);
4079
4080         cfg->arch.r_epilog = mono_ia64_create_unwind_region (&code);
4081         cfg->arch.r_pro->next = cfg->arch.r_epilog;
4082
4083         cfg->code_len = code.buf - cfg->native_code;
4084
4085         g_assert (cfg->code_len < cfg->code_size);
4086 }
4087
4088 void
4089 mono_arch_emit_exceptions (MonoCompile *cfg)
4090 {
4091         MonoJumpInfo *patch_info;
4092         int i, nthrows;
4093         Ia64CodegenState code;
4094         gboolean empty = TRUE;
4095         //unw_dyn_region_info_t *r_exceptions;
4096         MonoClass *exc_classes [16];
4097         guint8 *exc_throw_start [16], *exc_throw_end [16];
4098         guint32 code_size = 0;
4099
4100         /* Compute needed space */
4101         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4102                 if (patch_info->type == MONO_PATCH_INFO_EXC)
4103                         code_size += 256;
4104                 if (patch_info->type == MONO_PATCH_INFO_R8)
4105                         code_size += 8 + 7; /* sizeof (double) + alignment */
4106                 if (patch_info->type == MONO_PATCH_INFO_R4)
4107                         code_size += 4 + 7; /* sizeof (float) + alignment */
4108         }
4109
4110         if (code_size == 0)
4111                 return;
4112
4113         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4114                 cfg->code_size *= 2;
4115                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4116                 mono_jit_stats.code_reallocs++;
4117         }
4118
4119         ia64_codegen_init (code, cfg->native_code + cfg->code_len);
4120
4121         /* The unwind state here is the same as before the epilog */
4122         //ia64_unw_copy_state (code, 1234);
4123
4124         /* add code to raise exceptions */
4125         /* FIXME: Optimize this */
4126         nthrows = 0;
4127         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4128                 switch (patch_info->type) {
4129                 case MONO_PATCH_INFO_EXC: {
4130                         MonoClass *exc_class;
4131                         guint8* throw_ip;
4132                         guint8* buf;
4133                         guint64 exc_token_index;
4134
4135                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4136                         g_assert (exc_class);
4137                         exc_token_index = mono_metadata_token_index (exc_class->type_token);
4138                         throw_ip = cfg->native_code + patch_info->ip.i;
4139
4140                         ia64_begin_bundle (code);
4141
4142                         ia64_patch (cfg->native_code + patch_info->ip.i, code.buf);
4143
4144                         /* Find a throw sequence for the same exception class */
4145                         for (i = 0; i < nthrows; ++i)
4146                                 if (exc_classes [i] == exc_class)
4147                                         break;
4148
4149                         if (i < nthrows) {
4150                                 gint64 offset = exc_throw_end [i] - 16 - throw_ip;
4151
4152                                 if (ia64_is_adds_imm (offset))
4153                                         ia64_adds_imm (code, cfg->arch.reg_out0 + 1, offset, IA64_R0);
4154                                 else
4155                                         ia64_movl (code, cfg->arch.reg_out0 + 1, offset);
4156
4157                                 buf = code.buf + code.nins;
4158                                 ia64_br_cond_pred (code, 0, 0);
4159                                 ia64_begin_bundle (code);
4160                                 ia64_patch (buf, exc_throw_start [i]);
4161
4162                                 patch_info->type = MONO_PATCH_INFO_NONE;
4163                         }
4164                         else {
4165                                 /* Arg1 */
4166                                 buf = code.buf;
4167                                 ia64_movl (code, cfg->arch.reg_out0 + 1, 0);
4168
4169                                 ia64_begin_bundle (code);
4170
4171                                 if (nthrows < 16) {
4172                                         exc_classes [nthrows] = exc_class;
4173                                         exc_throw_start [nthrows] = code.buf;
4174                                 }
4175
4176                                 /* Arg2 */
4177                                 if (ia64_is_adds_imm (exc_token_index))
4178                                         ia64_adds_imm (code, cfg->arch.reg_out0 + 0, exc_token_index, IA64_R0);
4179                                 else
4180                                         ia64_movl (code, cfg->arch.reg_out0 + 0, exc_token_index);
4181
4182                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
4183                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4184                                 patch_info->ip.i = code.buf + code.nins - cfg->native_code;
4185
4186                                 /* Indirect call */
4187                                 ia64_movl (code, GP_SCRATCH_REG, 0);
4188                                 ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8);
4189                                 ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2);
4190                                 ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG);
4191
4192                                 ia64_br_call_reg (code, IA64_B0, IA64_B6);
4193
4194                                 /* Patch up the throw offset */
4195                                 ia64_begin_bundle (code);
4196
4197                                 ia64_patch (buf, (gpointer)(code.buf - 16 - throw_ip));
4198
4199                                 if (nthrows < 16) {
4200                                         exc_throw_end [nthrows] = code.buf;
4201                                         nthrows ++;
4202                                 }
4203                         }
4204
4205                         empty = FALSE;
4206                         break;
4207                 }
4208                 default:
4209                         break;
4210                 }
4211         }
4212
4213         if (!empty)
4214                 /* The unwinder needs this to work */
4215                 ia64_break_i (code, 0);
4216
4217         ia64_codegen_close (code);
4218
4219         /* FIXME: */
4220         //r_exceptions = mono_ia64_create_unwind_region (&code);
4221         //cfg->arch.r_epilog = r_exceptions;
4222
4223         cfg->code_len = code.buf - cfg->native_code;
4224
4225         g_assert (cfg->code_len < cfg->code_size);
4226 }
4227
4228 void*
4229 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4230 {
4231         Ia64CodegenState code;
4232         CallInfo *cinfo = NULL;
4233         MonoMethodSignature *sig;
4234         MonoInst *ins;
4235         int i, n, stack_area = 0;
4236
4237         ia64_codegen_init (code, p);
4238
4239         /* Keep this in sync with mono_arch_get_argument_info */
4240
4241         if (enable_arguments) {
4242                 /* Allocate a new area on the stack and save arguments there */
4243                 sig = mono_method_signature (cfg->method);
4244
4245                 cinfo = get_call_info (sig, FALSE);
4246
4247                 n = sig->param_count + sig->hasthis;
4248
4249                 stack_area = ALIGN_TO (n * 8, 16);
4250
4251                 if (n) {
4252                         ia64_movl (code, GP_SCRATCH_REG, stack_area);
4253
4254                         ia64_sub (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4255
4256                         /* FIXME: Allocate out registers */
4257
4258                         ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_SP);
4259
4260                         /* Required by the ABI */
4261                         ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4262
4263                         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4264                         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4265
4266                         /* Save arguments to the stack */
4267                         for (i = 0; i < n; ++i) {
4268                                 ins = cfg->args [i];
4269
4270                                 if (ins->opcode == OP_REGVAR) {
4271                                         ia64_movl (code, GP_SCRATCH_REG, (i * 8));
4272                                         ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4273                                         ia64_st8 (code, GP_SCRATCH_REG, ins->dreg);
4274                                 }
4275                                 else {
4276                                         ia64_movl (code, GP_SCRATCH_REG, ins->inst_offset);
4277                                         ia64_add (code, GP_SCRATCH_REG, ins->inst_basereg, GP_SCRATCH_REG);
4278                                         ia64_ld8 (code, GP_SCRATCH_REG2, GP_SCRATCH_REG);
4279                                         ia64_movl (code, GP_SCRATCH_REG, (i * 8));                              
4280                                         ia64_add (code, GP_SCRATCH_REG, cfg->arch.reg_out0 + 1, GP_SCRATCH_REG);
4281                                         ia64_st8 (code, GP_SCRATCH_REG, GP_SCRATCH_REG2);
4282                                 }
4283                         }
4284                 }
4285                 else
4286                         ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4287         }
4288         else
4289                 ia64_mov (code, cfg->arch.reg_out0 + 1, IA64_R0);
4290
4291         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, cfg->method);
4292         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4293
4294         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4295
4296         if (enable_arguments && stack_area) {
4297                 ia64_movl (code, GP_SCRATCH_REG, stack_area);
4298
4299                 ia64_add (code, IA64_SP, IA64_SP, GP_SCRATCH_REG);
4300
4301                 ia64_adds_imm (code, IA64_SP, 16, IA64_SP);
4302
4303                 g_free (cinfo);
4304         }
4305
4306         ia64_codegen_close (code);
4307
4308         return code.buf;
4309 }
4310
4311 void*
4312 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4313 {
4314         Ia64CodegenState code;
4315         CallInfo *cinfo = NULL;
4316         MonoMethod *method = cfg->method;
4317         MonoMethodSignature *sig = mono_method_signature (cfg->method);
4318
4319         ia64_codegen_init (code, p);
4320
4321         cinfo = get_call_info (sig, FALSE);
4322
4323         /* Save return value + pass it to func */
4324         switch (cinfo->ret.storage) {
4325         case ArgNone:
4326                 break;
4327         case ArgInIReg:
4328                 ia64_mov (code, cfg->arch.reg_saved_return_val, cinfo->ret.reg);
4329                 ia64_mov (code, cfg->arch.reg_out0 + 1, cinfo->ret.reg);
4330                 break;
4331         case ArgInFloatReg:
4332                 ia64_adds_imm (code, IA64_SP, -16, IA64_SP);
4333                 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4334                 ia64_stfd_hint (code, GP_SCRATCH_REG, cinfo->ret.reg, 0);
4335                 ia64_fmov (code, 8 + 1, cinfo->ret.reg);
4336                 break;
4337         case ArgValuetypeAddrInIReg:
4338                 ia64_mov (code, cfg->arch.reg_out0 + 1, cfg->arch.reg_in0 + cinfo->ret.reg);
4339                 break;
4340         case ArgAggregate:
4341                 NOT_IMPLEMENTED;
4342                 break;
4343         default:
4344                 break;
4345         }
4346
4347         g_free (cinfo);
4348
4349         add_patch_info (cfg, code, MONO_PATCH_INFO_METHODCONST, method);
4350         ia64_movl (code, cfg->arch.reg_out0 + 0, 0);
4351         code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
4352
4353         /* Restore return value */
4354         switch (cinfo->ret.storage) {
4355         case ArgNone:
4356                 break;
4357         case ArgInIReg:
4358                 ia64_mov (code, cinfo->ret.reg, cfg->arch.reg_saved_return_val);
4359                 break;
4360         case ArgInFloatReg:
4361                 ia64_adds_imm (code, GP_SCRATCH_REG, 16, IA64_SP);
4362                 ia64_ldfd (code, cinfo->ret.reg, GP_SCRATCH_REG);
4363                 break;
4364         case ArgValuetypeAddrInIReg:
4365                 break;
4366         case ArgAggregate:
4367                 break;
4368         default:
4369                 break;
4370         }
4371
4372         ia64_codegen_close (code);
4373
4374         return code.buf;
4375 }
4376
4377 void
4378 mono_arch_save_unwind_info (MonoCompile *cfg)
4379 {
4380         unw_dyn_info_t *di;
4381
4382         /* FIXME: Unregister this for dynamic methods */
4383
4384         di = g_malloc0 (sizeof (unw_dyn_info_t));
4385         di->start_ip = (unw_word_t) cfg->native_code;
4386         di->end_ip = (unw_word_t) cfg->native_code + cfg->code_len;
4387         di->gp = 0;
4388         di->format = UNW_INFO_FORMAT_DYNAMIC;
4389         di->u.pi.name_ptr = (unw_word_t)mono_method_full_name (cfg->method, TRUE);
4390         di->u.pi.regions = cfg->arch.r_pro;
4391
4392         _U_dyn_register (di);
4393
4394         /*
4395         {
4396                 unw_dyn_region_info_t *region = di->u.pi.regions;
4397
4398                 printf ("Unwind info for method %s:\n", mono_method_full_name (cfg->method, TRUE));
4399                 while (region) {
4400                         printf ("    [Region: %d]\n", region->insn_count);
4401                         region = region->next;
4402                 }
4403         }
4404         */
4405 }
4406
4407 void
4408 mono_arch_flush_icache (guint8 *code, gint size)
4409 {
4410         guint8* p = (guint8*)((guint64)code & ~(0x3f));
4411         guint8* end = (guint8*)((guint64)code + size);
4412
4413 #ifdef __INTEL_COMPILER
4414         /* icc doesn't define an fc.i instrinsic, but fc==fc.i on itanium 2 */
4415         while (p < end) {
4416                 __fc ((guint64)p);
4417                 p += 32;
4418         }
4419 #else
4420         while (p < end) {
4421                 __asm__ __volatile__ ("fc.i %0"::"r"(p));
4422                 /* FIXME: This could be increased to 128 on some cpus */
4423                 p += 32;
4424         }
4425 #endif
4426 }
4427
4428 void
4429 mono_arch_flush_register_windows (void)
4430 {
4431         /* Not needed because of libunwind */
4432 }
4433
4434 gboolean 
4435 mono_arch_is_inst_imm (gint64 imm)
4436 {
4437         /* The lowering pass will take care of it */
4438
4439         return TRUE;
4440 }
4441
4442 /*
4443  * Determine whenever the trap whose info is in SIGINFO is caused by
4444  * integer overflow.
4445  */
4446 gboolean
4447 mono_arch_is_int_overflow (void *sigctx, void *info)
4448 {
4449         /* Division is emulated with explicit overflow checks */
4450         return FALSE;
4451 }
4452
4453 guint32
4454 mono_arch_get_patch_offset (guint8 *code)
4455 {
4456         NOT_IMPLEMENTED;
4457
4458         return 0;
4459 }
4460
4461 gpointer*
4462 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
4463 {
4464         guint8 *bundle2 = code - 48;
4465         guint8 *bundle3 = code - 32;
4466         guint8 *bundle4 = code - 16;
4467         guint64 ins21 = ia64_bundle_ins1 (bundle2);
4468         guint64 ins22 = ia64_bundle_ins2 (bundle2);
4469         guint64 ins23 = ia64_bundle_ins3 (bundle2);
4470         guint64 ins31 = ia64_bundle_ins1 (bundle3);
4471         guint64 ins32 = ia64_bundle_ins2 (bundle3);
4472         guint64 ins33 = ia64_bundle_ins3 (bundle3);
4473         guint64 ins41 = ia64_bundle_ins1 (bundle4);
4474         guint64 ins42 = ia64_bundle_ins2 (bundle4);
4475         guint64 ins43 = ia64_bundle_ins3 (bundle4);
4476         int reg;
4477
4478         /* 
4479          * Virtual calls are made with:
4480          *
4481          * [MII]       ld8 r31=[r8]
4482          *             nop.i 0x0
4483          *             nop.i 0x0;;
4484          * [MII]       nop.m 0x0
4485          *             mov.sptk b6=r31,0x2000000000f32a80
4486          *             nop.i 0x0
4487          * [MII]       nop.m 0x0
4488          *             nop.i 0x123456
4489          *             nop.i 0x0
4490          * [MIB]       nop.m 0x0
4491          *             nop.i 0x0
4492          *             br.call.sptk.few b0=b6;;
4493          */
4494
4495         if (((ia64_bundle_template (bundle3) == IA64_TEMPLATE_MII) ||
4496                  (ia64_bundle_template (bundle3) == IA64_TEMPLATE_MIIS)) &&
4497                 (ia64_bundle_template (bundle4) == IA64_TEMPLATE_MIBS) &&
4498                 (ins31 == IA64_NOP_M) && 
4499                 (ia64_ins_opcode (ins32) == 0) && (ia64_ins_x3 (ins32) == 0) && (ia64_ins_x6 (ins32) == 0x1) && (ia64_ins_y (ins32) == 0) &&
4500                 (ins33 == IA64_NOP_I) &&
4501                 (ins41 == IA64_NOP_M) &&
4502                 (ins42 == IA64_NOP_I) &&
4503                 (ia64_ins_opcode (ins43) == 1) && (ia64_ins_b1 (ins43) == 0) && (ia64_ins_b2 (ins43) == 6) &&
4504                 ((ins32 >> 6) & 0xfffff) == 0x12345) {
4505                 g_assert (ins21 == IA64_NOP_M);
4506                 g_assert (ins23 == IA64_NOP_I);
4507                 g_assert (ia64_ins_opcode (ins22) == 0);
4508                 g_assert (ia64_ins_x3 (ins22) == 7);
4509                 g_assert (ia64_ins_x (ins22) == 0);
4510                 g_assert (ia64_ins_b1 (ins22) == IA64_B6);
4511
4512                 reg = IA64_R8;
4513
4514                 /* 
4515                  * Must be a scratch register, since only those are saved by the trampoline
4516                  */
4517                 g_assert ((1 << reg) & MONO_ARCH_CALLEE_REGS);
4518
4519                 g_assert (regs [reg]);
4520
4521                 return regs [reg];
4522         }
4523
4524         return NULL;
4525 }
4526
4527 gpointer*
4528 mono_arch_get_delegate_method_ptr_addr (guint8* code, gpointer *regs)
4529 {
4530         NOT_IMPLEMENTED;
4531
4532         return NULL;
4533 }
4534
4535 static gboolean tls_offset_inited = FALSE;
4536
4537 void
4538 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4539 {
4540         if (!tls_offset_inited) {
4541                 tls_offset_inited = TRUE;
4542
4543                 appdomain_tls_offset = mono_domain_get_tls_offset ();
4544                 thread_tls_offset = mono_thread_get_tls_offset ();
4545         }               
4546 }
4547
4548 void
4549 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4550 {
4551 }
4552
4553 void
4554 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4555 {
4556         MonoCallInst *call = (MonoCallInst*)inst;
4557         int out_reg = cfg->arch.reg_out0;
4558
4559         if (vt_reg != -1) {
4560                 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4561                 MonoInst *vtarg;
4562
4563                 if (cinfo->ret.storage == ArgAggregate) {
4564                         MonoInst *local = (MonoInst*)cfg->arch.ret_var_addr_local;
4565
4566                         /* 
4567                          * The valuetype is in registers after the call, need to be copied 
4568                          * to the stack. Save the address to a local here, so the call 
4569                          * instruction can access it.
4570                          */
4571                         g_assert (local->opcode == OP_REGOFFSET);
4572                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, local->inst_basereg, local->inst_offset, vt_reg);
4573                 }
4574                 else {
4575                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4576                         vtarg->sreg1 = vt_reg;
4577                         vtarg->dreg = mono_regstate_next_int (cfg->rs);
4578                         mono_bblock_add_inst (cfg->cbb, vtarg);
4579
4580                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, out_reg, FALSE);
4581
4582                         out_reg ++;
4583                 }
4584
4585                 g_free (cinfo);
4586         }
4587
4588         /* add the this argument */
4589         if (this_reg != -1) {
4590                 MonoInst *this;
4591                 MONO_INST_NEW (cfg, this, OP_MOVE);
4592                 this->type = this_type;
4593                 this->sreg1 = this_reg;
4594                 this->dreg = mono_regstate_next_int (cfg->rs);
4595                 mono_bblock_add_inst (cfg->cbb, this);
4596
4597                 mono_call_inst_add_outarg_reg (cfg, call, this->dreg, out_reg, FALSE);
4598         }
4599 }
4600
4601 MonoInst*
4602 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4603 {
4604         MonoInst *ins = NULL;
4605
4606         if (cmethod->klass == mono_defaults.thread_class &&
4607                 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4608                 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4609         } else if(cmethod->klass->image == mono_defaults.corlib &&
4610                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4611                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4612
4613                 if (strcmp (cmethod->name, "Increment") == 0) {
4614                         guint32 opcode;
4615
4616                         if (fsig->params [0]->type == MONO_TYPE_I4)
4617                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4618                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4619                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4620                         else
4621                                 g_assert_not_reached ();
4622                         MONO_INST_NEW (cfg, ins, opcode);
4623                         ins->inst_imm = 1;
4624                         ins->inst_i0 = args [0];
4625                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4626                         guint32 opcode;
4627
4628                         if (fsig->params [0]->type == MONO_TYPE_I4)
4629                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
4630                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4631                                 opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
4632                         else
4633                                 g_assert_not_reached ();
4634                         MONO_INST_NEW (cfg, ins, opcode);
4635                         ins->inst_imm = -1;
4636                         ins->inst_i0 = args [0];
4637                 } else if (strcmp (cmethod->name, "Exchange") == 0) {
4638                         guint32 opcode;
4639
4640                         if (fsig->params [0]->type == MONO_TYPE_I4)
4641                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4642                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4643                                          (fsig->params [0]->type == MONO_TYPE_I) ||
4644                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
4645                                 opcode = OP_ATOMIC_EXCHANGE_I8;
4646                         else
4647                                 return NULL;
4648
4649                         MONO_INST_NEW (cfg, ins, opcode);
4650
4651                         ins->inst_i0 = args [0];
4652                         ins->inst_i1 = args [1];
4653                 } else if (strcmp (cmethod->name, "Add") == 0) {
4654                         guint32 opcode;
4655
4656                         if (fsig->params [0]->type == MONO_TYPE_I4)
4657                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4658                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4659                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4660                         else
4661                                 g_assert_not_reached ();
4662                         
4663                         MONO_INST_NEW (cfg, ins, opcode);
4664
4665                         ins->inst_i0 = args [0];
4666                         ins->inst_i1 = args [1];
4667                 } else if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4668                         /* 64 bit reads are already atomic */
4669                         MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4670                         ins->inst_i0 = args [0];
4671                 }
4672         }
4673
4674         return ins;
4675 }
4676
4677 gboolean
4678 mono_arch_print_tree (MonoInst *tree, int arity)
4679 {
4680         return 0;
4681 }
4682
4683 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4684 {
4685         MonoInst* ins;
4686         
4687         if (appdomain_tls_offset == -1)
4688                 return NULL;
4689         
4690         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4691         ins->inst_offset = appdomain_tls_offset;
4692         return ins;
4693 }
4694
4695 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4696 {
4697         MonoInst* ins;
4698         
4699         if (thread_tls_offset == -1)
4700                 return NULL;
4701         
4702         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4703         ins->inst_offset = thread_tls_offset;
4704         return ins;
4705 }