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