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