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