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