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