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