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