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