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