2008-10-03 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / mini / mini-hppa.c
1 /*
2  * mini-hppa.c: HPPA backend for the Mono code generator
3  *
4  * Copyright (c) 2007 Randolph Chung
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  */
25 #include "mini.h"
26 #include <string.h>
27 #include <pthread.h>
28 #include <unistd.h>
29
30 #include <unistd.h>
31 #include <sys/mman.h>
32
33 #include <mono/metadata/appdomain.h>
34 #include <mono/metadata/debug-helpers.h>
35 #include <mono/metadata/tokentype.h>
36 #include <mono/utils/mono-math.h>
37
38 #include "mini-hppa.h"
39 #include "inssel.h"
40 #include "trace.h"
41 #include "cpu-hppa.h"
42
43 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
44 #define SIGNAL_STACK_SIZE (64 * 1024)
45
46 #define DEBUG(a) // a
47 #define DEBUG_FUNC_ENTER() // printf("Entering %s\n", __FUNCTION__)
48 #define DEBUG_FUNC_EXIT() // printf("Exiting %s\n", __FUNCTION__)
49
50 static const guchar 
51 branch_b0_table [] = {
52         TRUE, /* OP_HPPA_BEQ */
53         FALSE, /* OP_HPPA_BGE */
54         FALSE, /* OP_HPPA_BGT */
55         TRUE, /* OP_HPPA_BLE */
56         TRUE, /* OP_HPPA_BLT */
57         FALSE, /* OP_HPPA_BNE */
58         FALSE, /* OP_HPPA_BGE_UN */
59         FALSE, /* OP_HPPA_BGT_UN */
60         TRUE, /* OP_HPPA_BLE_UN */
61         TRUE, /* OP_HPPA_BLT_UN */
62 };
63
64 static const guchar 
65 branch_b1_table [] = {
66         HPPA_CMP_COND_EQ, /* OP_HPPA_BEQ */
67         HPPA_CMP_COND_SLT, /* OP_HPPA_BGE */
68         HPPA_CMP_COND_SLE, /* OP_HPPA_BGT */
69         HPPA_CMP_COND_SLE, /* OP_HPPA_BLE */
70         HPPA_CMP_COND_SLT, /* OP_HPPA_BLT */
71         HPPA_CMP_COND_EQ, /* OP_HPPA_BNE_UN */
72         HPPA_CMP_COND_ULT, /* OP_HPPA_BGE_UN */
73         HPPA_CMP_COND_ULE, /* OP_HPPA_BGT_UN */
74         HPPA_CMP_COND_ULE, /* OP_HPPA_BLE_UN */
75         HPPA_CMP_COND_ULT, /* OP_HPPA_BLT_UN */
76 };
77
78 /* Note that these are inverted from the OP_xxx, because we nullify
79  * the branch if the condition is met
80  */
81 static const guchar
82 float_branch_table [] = {
83         26, /* OP_FBEQ */
84         11, /* OP_FBGE */
85         15, /* OP_FBGT */
86         19, /* OP_FBLE */
87         23, /* OP_FBLT */
88         4, /* OP_FBNE_UN */
89         8, /* OP_FBGE_UN */
90         13, /* OP_FBGT_UN */
91         17, /* OP_FBLE_UN */
92         20, /* OP_FBLT_UN */
93 };
94
95 static const guchar
96 float_ceq_table [] = {
97         26, /* OP_FCEQ */
98         15, /* OP_FCGT */
99         13, /* OP_FCGT_UN */
100         23, /* OP_FCLT */
101         21, /* OP_FCLT_UN */
102 };
103
104 /*
105  * Branches have short (14 or 17 bit) targets on HPPA. To make longer jumps,
106  * we will need to rely on stubs - basically we create stub structures in
107  * the epilogue that uses a long branch to the destination, and any short
108  * jumps inside a method that cannot reach the destination directly will
109  * branch first to the stub.
110  */
111 typedef struct MonoOvfJump {
112         union {
113                 MonoBasicBlock *bb;
114                 const char *exception;
115         } data;
116         guint32 ip_offset;
117 } MonoOvfJump;
118
119 /* Create a literal 0.0 double for FNEG */
120 double hppa_zero = 0;
121
122 const char*
123 mono_arch_regname (int reg) 
124 {
125         static const char * rnames[] = {
126                 "hppa_r0", "hppa_r1", "hppa_rp", "hppa_r3", "hppa_r4",
127                 "hppa_r5", "hppa_r6", "hppa_r7", "hppa_r8", "hppa_r9",
128                 "hppa_r10", "hppa_r11", "hppa_r12", "hppa_r13", "hppa_r14",
129                 "hppa_r15", "hppa_r16", "hppa_r17", "hppa_r18", "hppa_r19",
130                 "hppa_r20", "hppa_r21", "hppa_r22", "hppa_r23", "hppa_r24",
131                 "hppa_r25", "hppa_r26", "hppa_r27", "hppa_r28", "hppa_r29",
132                 "hppa_sp", "hppa_r31"
133         };
134         if (reg >= 0 && reg < MONO_MAX_IREGS)
135                 return rnames [reg];
136         return "unknown";
137 }
138
139 const char*
140 mono_arch_fregname (int reg) 
141 {
142         static const char *rnames [] = {
143                 "hppa_fr0", "hppa_fr1", "hppa_fr2", "hppa_fr3", "hppa_fr4", 
144                 "hppa_fr5", "hppa_fr6", "hppa_fr7", "hppa_fr8", "hppa_fr9",
145                 "hppa_fr10", "hppa_fr11", "hppa_fr12", "hppa_fr13", "hppa_fr14", 
146                 "hppa_fr15", "hppa_fr16", "hppa_fr17", "hppa_fr18", "hppa_fr19",
147                 "hppa_fr20", "hppa_fr21", "hppa_fr22", "hppa_fr23", "hppa_fr24", 
148                 "hppa_fr25", "hppa_fr26", "hppa_fr27", "hppa_fr28", "hppa_fr29",
149                 "hppa_fr30", "hppa_fr31",
150         };
151
152         if (reg >= 0 && reg < MONO_MAX_FREGS)
153                 return rnames [reg];
154         else
155                 return "unknown";
156 }
157
158 /*
159  * Initialize the cpu to execute managed code.
160  */
161 void
162 mono_arch_cpu_init (void)
163 {
164         guint32 dummy;
165         mono_arch_cpu_optimizazions(&dummy);
166 }
167
168 /*
169  * Initialize architecture specific code.
170  */
171 void
172 mono_arch_init (void)
173 {
174 }
175
176 /*
177  * Cleanup architecture specific code.
178  */
179 void
180 mono_arch_cleanup (void)
181 {
182 }
183
184 /*
185  * This function returns the optimizations supported on this cpu.
186  */
187 guint32
188 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
189 {
190         guint32 opts = 0;
191         *exclude_mask = 0;
192         return opts;
193 }
194
195 void
196 mono_arch_flush_icache (guint8 *code, gint size)
197 {
198         guint8* p = (guint8*)((guint32)code & ~(0x3f));
199         guint8* end = (guint8*)((guint32)code + size);
200         while (p < end) {
201                 __asm__ __volatile__ ("fdc %%r0(%%sr3, %0)\n"
202                         "sync\n"
203                         "fic %%r0(%%sr3, %0)\n"
204                         "sync\n"
205                         : : "r"(p));
206                 p += 32; /* can be 64 on pa20 cpus */
207         }
208 }
209
210 void
211 mono_arch_flush_register_windows (void)
212 {
213         /* No register windows on hppa */
214 }
215
216 typedef enum {
217         ArgInIReg,
218         ArgInIRegPair,
219         ArgInFReg,
220         ArgInDReg,
221         ArgOnStack,
222 } ArgStorage;
223
224 typedef struct {
225         gint16 offset;
226         gint16 size;
227         guint8 type;
228         gint8  reg;
229         ArgStorage storage;
230 } ArgInfo;
231
232 typedef struct {
233         int nargs;
234         guint32 stack_usage;
235         int struct_return;
236         ArgInfo ret;
237         ArgInfo sig_cookie;
238         ArgInfo args [1];
239 } CallInfo;
240
241 #define PARAM_REGS 4
242 #define ARGS_OFFSET 36
243
244 static void
245 add_parameter (CallInfo *cinfo, ArgInfo *ainfo, MonoType *type)
246 {
247         int is_fp = (type->type == MONO_TYPE_R4 || type->type == MONO_TYPE_R8);
248         int ofs, align;
249
250         DEBUG_FUNC_ENTER ();
251         ainfo->reg = -1;
252         ainfo->size = mono_type_size (type, &align);
253         ainfo->type = type->type;
254
255         if (ainfo->size <= 4) {
256                 cinfo->stack_usage += 4;
257                 ainfo->offset = cinfo->stack_usage - (4 - ainfo->size);
258         }
259         else if (ainfo->size <= 8)
260         {
261                 cinfo->stack_usage += 8;
262                 cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, 8);
263                 ainfo->offset = cinfo->stack_usage - (8 - ainfo->size);
264         }
265         else
266         {
267                 cinfo->stack_usage += ainfo->size;
268                 cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, align);
269                 ainfo->offset = cinfo->stack_usage;
270         }
271
272         ofs = (ALIGN_TO (ainfo->offset, 4) - ARGS_OFFSET) / 4;
273         if (ofs < PARAM_REGS) {
274                 if (!is_fp) {
275                         if (ainfo->size <= 4)
276                                 ainfo->storage = ArgInIReg;
277                         else
278                                 ainfo->storage = ArgInIRegPair;
279                         ainfo->reg = hppa_r26 - ofs;
280                 } else if (type->type == MONO_TYPE_R4) {
281                         ainfo->storage = ArgInFReg;
282                         ainfo->reg = hppa_fr4 + ofs;
283                 } else { /* type->type == MONO_TYPE_R8 */
284                         ainfo->storage = ArgInDReg;
285                         ainfo->reg = hppa_fr4 + ofs;
286                 }
287         }
288         else {
289                 /* frame pointer based offset */
290                 ainfo->reg = hppa_r3;
291                 ainfo->storage = ArgOnStack;
292         }
293
294         /* All offsets are negative relative to the frame pointer */
295         ainfo->offset = -ainfo->offset;
296
297         DEBUG_FUNC_EXIT ();
298 }
299
300 static void 
301 analyze_return (CallInfo *cinfo, MonoMethodSignature *sig)
302 {
303         MonoType *type;
304         int align;
305         int size;
306
307         type = sig->ret;
308         size = mono_type_size (type, &align);
309
310         /* ref: mono_type_to_stind */
311         cinfo->ret.type = type->type;
312         if (type->byref) {
313                 cinfo->ret.storage = ArgInIReg;
314                 cinfo->ret.reg = hppa_r28;
315         } else {
316 handle_enum:
317                 switch (type->type) {
318                 case MONO_TYPE_VOID:
319                         break;
320                 case MONO_TYPE_BOOLEAN:
321                 case MONO_TYPE_I1:
322                 case MONO_TYPE_U1:
323                 case MONO_TYPE_I2:
324                 case MONO_TYPE_U2:
325                 case MONO_TYPE_CHAR:
326                 case MONO_TYPE_I4:
327                 case MONO_TYPE_U4:
328                 case MONO_TYPE_I:
329                 case MONO_TYPE_U:
330                 case MONO_TYPE_PTR:
331                 case MONO_TYPE_FNPTR:
332                 case MONO_TYPE_CLASS:
333                 case MONO_TYPE_STRING:
334                 case MONO_TYPE_OBJECT:
335                 case MONO_TYPE_SZARRAY:
336                 case MONO_TYPE_ARRAY:
337                         cinfo->ret.storage = ArgInIReg;
338                         cinfo->ret.reg = hppa_r28;
339                         break;
340                 case MONO_TYPE_U8:
341                 case MONO_TYPE_I8:
342                         cinfo->ret.storage = ArgInIRegPair;
343                         cinfo->ret.reg = hppa_r28;
344                         break;
345                 case MONO_TYPE_R4:
346                         cinfo->ret.storage = ArgInFReg;
347                         cinfo->ret.reg = hppa_fr4;
348                         break;
349                 case MONO_TYPE_R8:
350                         cinfo->ret.storage = ArgInDReg;
351                         cinfo->ret.reg = hppa_fr4;
352                         break;
353                 case MONO_TYPE_GENERICINST:
354                         type = &type->data.generic_class->container_class->byval_arg;
355                         goto handle_enum;
356                         
357                 case MONO_TYPE_VALUETYPE:
358                         if (type->data.klass->enumtype) {
359                                 type = type->data.klass->enum_basetype;
360                                 goto handle_enum;
361                         }
362                         /* Fall through */
363                 case MONO_TYPE_TYPEDBYREF:
364                         cinfo->struct_return = 1;
365                         /* cinfo->ret.storage tells us how the ABI expects 
366                          * the parameter to be returned
367                          */
368                         if (size <= 4) {
369                                 cinfo->ret.storage = ArgInIReg;
370                                 cinfo->ret.reg = hppa_r28;
371                         } else if (size <= 8) {
372                                 cinfo->ret.storage = ArgInIRegPair;
373                                 cinfo->ret.reg = hppa_r28;
374                         } else {
375                                 cinfo->ret.storage = ArgOnStack;
376                                 cinfo->ret.reg = hppa_sp;
377                         }
378
379                         /* We always allocate stack space for this because the
380                          * arch-indep code expects us to
381                          */
382                         cinfo->stack_usage += size;
383                         cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, align);
384                         cinfo->ret.offset = -cinfo->stack_usage;
385                         break;
386
387                 default:
388                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
389                 }
390         }
391 }
392
393 /*
394  * get_call_info:
395  *
396  *  Obtain information about a call according to the calling convention.
397  */
398 static CallInfo*
399 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
400 {
401         guint32 i;
402         int n = sig->hasthis + sig->param_count;
403         CallInfo *cinfo;
404         MonoType *type;
405         MonoType ptrtype;
406         int dummy;
407
408         ptrtype.type = MONO_TYPE_PTR;
409
410         DEBUG_FUNC_ENTER();
411         cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
412
413         /* The area below ARGS_OFFSET is the linkage area... */
414         cinfo->stack_usage = ARGS_OFFSET - 4;
415         /* -4, because the first argument will allocate the area it needs */
416
417         /* this */
418         if (sig->hasthis) {
419                 add_parameter (cinfo, cinfo->args + 0, &ptrtype);
420                 DEBUG (printf ("param <this>: assigned to reg %s offset %d\n", mono_arch_regname (cinfo->args[0].reg), cinfo->args[0].offset));
421         }
422
423         /* TODO: What to do with varargs? */
424
425         for (i = 0; i < sig->param_count; ++i) {
426                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
427                 if (sig->params [i]->byref)
428                         type = &ptrtype;
429                 else
430                         type = mono_type_get_underlying_type (sig->params [i]);
431                 add_parameter (cinfo, ainfo, type);
432
433                 DEBUG (printf ("param %d: type %d size %d assigned to reg %s offset %d\n", i, type->type, mono_type_size (type, &dummy), mono_arch_regname (ainfo->reg), ainfo->offset));
434         }
435
436         analyze_return (cinfo, sig);
437
438         DEBUG_FUNC_EXIT();
439         return cinfo;
440 }
441
442 GList *
443 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
444 {
445         GList *vars = NULL;
446         int i;
447
448         DEBUG_FUNC_ENTER();
449         for (i = 0; i < cfg->num_varinfo; i++) {
450                 MonoInst *ins = cfg->varinfo [i];
451                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
452
453                 /* unused vars */
454                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
455                         continue;
456
457                 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || 
458                     (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
459                         continue;
460
461                 if (mono_is_regsize_var (ins->inst_vtype)) {
462                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
463                         g_assert (i == vmv->idx);
464                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
465                 }
466         }
467         DEBUG_FUNC_EXIT();
468
469         return vars;
470 }
471
472 GList *
473 mono_arch_get_global_int_regs (MonoCompile *cfg)
474 {
475         GList *regs = NULL;
476         int i;
477
478         /* r3 is sometimes used as our frame pointer, so don't allocate it
479          * r19 is the GOT pointer, don't allocate it either
480          */
481
482         DEBUG_FUNC_ENTER();
483         for (i = 4; i <= 18; i++)
484                 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
485         DEBUG_FUNC_EXIT();
486
487         return regs;
488 }
489
490 /*
491  * mono_arch_regalloc_cost:
492  *
493  *  Return the cost, in number of memory references, of the action of 
494  * allocating the variable VMV into a register during global register
495  * allocation.
496  */
497 guint32
498 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
499 {
500         /* FIXME */
501         return 0;
502 }
503
504 /*
505  * Set var information according to the calling convention.
506  * The locals var stuff should most likely be split in another method.
507  *
508  * updates m->stack_offset based on the amount of stack space needed for
509  * local vars
510  */
511 void
512 mono_arch_allocate_vars (MonoCompile *m)
513 {
514         MonoMethodSignature *sig;
515         MonoMethodHeader *header;
516         MonoInst *inst;
517         int i, offset, size, align, curinst;
518         guint32 stack_ptr;
519         guint rettype;
520         CallInfo *cinfo;
521
522         DEBUG_FUNC_ENTER();
523         m->flags |= MONO_CFG_HAS_SPILLUP;
524
525         header = mono_method_get_header (m->method);
526
527         sig = mono_method_signature (m->method);
528         DEBUG (printf ("Allocating locals - incoming params:\n"));
529         cinfo = get_call_info (sig, FALSE);
530
531         /*
532          * We use the ABI calling conventions for managed code as well.
533          */
534         if (m->flags & MONO_CFG_HAS_ALLOCA) {
535                 stack_ptr = hppa_r4;
536                 m->used_int_regs |= 1 << hppa_r4;
537         } else {
538                 stack_ptr = hppa_sp;
539         }
540
541         /* Before this function is called, we would have looked at all 
542          * calls from this method and figured out how much space is needed
543          * for the param area.
544          *
545          * Locals are allocated backwards, right before the param area 
546          */
547         /* TODO: in some cases we don't need the frame pointer... */
548         m->frame_reg = hppa_r3;
549         offset = m->param_area;
550
551         /* Return values can be passed back either in four ways:
552          * r28 is used for data <= 4 bytes (32-bit ABI)
553          * r28/r29 are used for data >4 && <= 8 bytes
554          * fr4 is used for floating point data
555          * data larger than 8 bytes is returned on the stack pointed to 
556          *      by r28
557          *
558          * This code needs to be in sync with how CEE_RET is handled
559          * in mono_method_to_ir (). In some cases when we return small
560          * structs, the ABI specifies that they should be returned in
561          * registers, but the code in mono_method_to_ir () always emits
562          * a memcpy for valuetype returns, so we need to make sure we
563          * allocate space on the stack for this copy.
564          */
565         if (cinfo->struct_return) {
566                 /* this is used to stash the incoming r28 pointer */
567                 offset += sizeof (gpointer);
568                 m->ret->opcode = OP_REGOFFSET;
569                 m->ret->inst_basereg = stack_ptr;
570                 m->ret->inst_offset = -offset;
571         } else if (sig->ret->type != MONO_TYPE_VOID) {
572                 m->ret->opcode = OP_REGVAR;
573                 m->ret->inst_c0 = cinfo->ret.reg;
574         }
575
576         curinst = m->locals_start;
577         for (i = curinst; i < m->num_varinfo; ++i) {
578                 inst = m->varinfo [i];
579
580                 if (inst->opcode == OP_REGVAR) {
581                         DEBUG (printf ("allocating local %d to %s\n", i, mono_arch_regname (inst->dreg)));
582                         continue;
583                 }
584
585                 if (inst->flags & MONO_INST_IS_DEAD)
586                         continue;
587
588                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
589                 * pinvoke wrappers when they call functions returning structure */
590                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
591                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
592                 else
593                         size = mini_type_stack_size (cfg->generic_sharing_context, inst->inst_vtype, &align);
594
595                 /* 
596                  * This is needed since structures containing doubles must be doubleword 
597          * aligned.
598                  * FIXME: Do this only if needed.
599                  */
600                 if (MONO_TYPE_ISSTRUCT (inst->inst_vtype))
601                         align = 8;
602
603                 /*
604                  * variables are accessed as negative offsets from hppa_sp
605                  */
606                 inst->opcode = OP_REGOFFSET;
607                 inst->inst_basereg = stack_ptr;
608                 offset += size;
609                 offset = ALIGN_TO (offset, align);
610                 inst->inst_offset = -offset;
611
612                 DEBUG (printf ("allocating local %d (size = %d) to [%s - %d]\n", i, size, mono_arch_regname (inst->inst_basereg), -inst->inst_offset));
613         }
614
615         if (sig->call_convention == MONO_CALL_VARARG) {
616                 /* TODO */
617         }
618
619         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
620                 ArgInfo *ainfo = &cinfo->args [i];
621                 inst = m->args [i];
622                 if (inst->opcode != OP_REGVAR) {
623                         switch (ainfo->storage) {
624                         case ArgInIReg:
625                         case ArgInIRegPair:
626                         case ArgInFReg:
627                         case ArgInDReg:
628                                 /* Currently mono requests all incoming registers
629                                  * be assigned to a stack location :-(
630                                  */
631 #if 0
632                                 if (!(inst->flags & (MONO_INST_VOLATILE | MONO_INST_INDIRECT))) {
633                                         inst->opcode = OP_REGVAR;
634                                         inst->dreg = ainfo->reg;
635                                         DEBUG (printf ("param %d in register %s\n", i, mono_arch_regname (inst->dreg)));
636                                         break;
637                                 }
638 #endif
639                                 /* fallthrough */
640                         case ArgOnStack:
641                                 inst->opcode = OP_REGOFFSET;
642                                 inst->inst_basereg = hppa_r3;
643                                 inst->inst_offset = ainfo->offset;
644                                 DEBUG (printf ("param %d stored on stack [%s - %d]\n", i, mono_arch_regname (hppa_r3), -inst->inst_offset));
645                                 break;
646                         }
647                 }
648         }
649
650         m->stack_offset = offset; /* Includes cfg->param_area */
651
652         g_free (cinfo);
653         DEBUG_FUNC_EXIT();
654 }
655
656 /* 
657  * take the arguments and generate the arch-specific
658  * instructions to properly call the function in call.
659  * This includes pushing, moving arguments to the right register
660  * etc.
661  *
662  * sets call->stack_usage and cfg->param_area
663  */
664 MonoCallInst*
665 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) 
666 {
667         MonoInst *arg, *in;
668         MonoMethodSignature *sig;
669         int i, n;
670         CallInfo *cinfo;
671         ArgInfo *ainfo;
672
673         DEBUG_FUNC_ENTER();
674         DEBUG (printf ("is_virtual = %d\n", is_virtual));
675
676         sig = call->signature;
677         n = sig->param_count + sig->hasthis;
678
679         DEBUG (printf ("Calling method with %d parameters\n", n));
680         
681         cinfo = get_call_info (sig, sig->pinvoke);
682
683         // DEBUG
684         g_assert (sig->call_convention != MONO_CALL_VARARG);
685
686         for (i = 0; i < n; ++i) {
687                 ainfo = &cinfo->args [i];
688
689                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
690                         /* TODO */
691                 }
692
693                 if (is_virtual && i == 0) {
694                         /* the argument will be attached to the call instruction */
695                         in = call->args [i];
696                         call->used_iregs |= 1 << ainfo->reg;
697                 } else {
698                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
699                         in = call->args [i];
700                         arg->cil_code = in->cil_code;
701                         arg->inst_left = in;
702                         arg->inst_call = call;
703                         arg->type = in->type;
704
705                         /* prepend, we'll need to reverse them later */
706                         arg->next = call->out_args;
707                         call->out_args = arg;
708
709                         switch (ainfo->storage) {
710                         case ArgInIReg:
711                         case ArgInIRegPair: {
712                                 MonoHPPAArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoHPPAArgInfo));
713                                 ai->reg = ainfo->reg;
714                                 ai->size = ainfo->size;
715                                 ai->offset = ainfo->offset;
716                                 ai->pass_in_reg = 1;
717                                 arg->backend.data = ai;
718
719                                 call->used_iregs |= 1 << ainfo->reg;
720                                 if (ainfo->storage == ArgInIRegPair)
721                                         call->used_iregs |= 1 << (ainfo->reg + 1);
722                                 if (ainfo->type == MONO_TYPE_VALUETYPE)
723                                         arg->opcode = OP_OUTARG_VT;
724                                 break;
725                         }
726                         case ArgOnStack: {
727                                 MonoHPPAArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoHPPAArgInfo));
728                                 ai->reg = hppa_sp;
729                                 ai->size = ainfo->size;
730                                 ai->offset = ainfo->offset;
731                                 ai->pass_in_reg = 0;
732                                 arg->backend.data = ai;
733                                 if (ainfo->type == MONO_TYPE_VALUETYPE)
734                                         arg->opcode = OP_OUTARG_VT;
735                                 else
736                                         arg->opcode = OP_OUTARG_MEMBASE;
737                                 call->used_iregs |= 1 << ainfo->reg;
738                                 break;
739                         }
740                         case ArgInFReg:
741                                 arg->backend.reg3 = ainfo->reg;
742                                 arg->opcode = OP_OUTARG_R4;
743                                 call->used_fregs |= 1 << ainfo->reg;
744                                 break;
745                         case ArgInDReg:
746                                 arg->backend.reg3 = ainfo->reg;
747                                 arg->opcode = OP_OUTARG_R8;
748                                 call->used_fregs |= 1 << ainfo->reg;
749                                 break;
750                         default:
751                                 NOT_IMPLEMENTED;
752                         }
753                 }
754         }
755
756         /*
757          * Reverse the call->out_args list.
758          */
759         {
760                 MonoInst *prev = NULL, *list = call->out_args, *next;
761                 while (list) {
762                         next = list->next;
763                         list->next = prev;
764                         prev = list;
765                         list = next;
766                 }
767                 call->out_args = prev;
768         }
769         call->stack_usage = cinfo->stack_usage;
770         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
771         cfg->param_area = ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT);
772
773         cfg->flags |= MONO_CFG_HAS_CALLS;
774
775         g_free (cinfo);
776
777         DEBUG_FUNC_EXIT();
778         return call;
779 }
780
781 void
782 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
783 {
784 }
785
786 void
787 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
788 {
789         DEBUG_FUNC_ENTER();
790         DEBUG_FUNC_EXIT();
791 }
792
793 static void
794 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
795 {
796         if (ins == NULL) {
797                 ins = bb->code;
798                 bb->code = to_insert;
799                 to_insert->next = ins;
800         } else {
801                 to_insert->next = ins->next;
802                 ins->next = to_insert;
803         }
804 }
805
806 #define NEW_INS(cfg,dest,op) do {       \
807                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
808                 (dest)->opcode = (op);  \
809                 insert_after_ins (bb, last_ins, (dest)); \
810         } while (0)
811
812 static int
813 map_to_reg_reg_op (int op)
814 {
815         switch (op) {
816         case OP_ADD_IMM:
817                 return CEE_ADD;
818         case OP_SUB_IMM:
819                 return CEE_SUB;
820         case OP_AND_IMM:
821                 return CEE_AND;
822         case OP_COMPARE_IMM:
823                 return OP_COMPARE;
824         case OP_ADDCC_IMM:
825                 return OP_ADDCC;
826         case OP_ADC_IMM:
827                 return OP_ADC;
828         case OP_SUBCC_IMM:
829                 return OP_SUBCC;
830         case OP_SBB_IMM:
831                 return OP_SBB;
832         case OP_OR_IMM:
833                 return CEE_OR;
834         case OP_XOR_IMM:
835                 return CEE_XOR;
836         case OP_MUL_IMM:
837                 return CEE_MUL;
838         case OP_LOAD_MEMBASE:
839                 return OP_LOAD_MEMINDEX;
840         case OP_LOADI4_MEMBASE:
841                 return OP_LOADI4_MEMINDEX;
842         case OP_LOADU4_MEMBASE:
843                 return OP_LOADU4_MEMINDEX;
844         case OP_LOADU1_MEMBASE:
845                 return OP_LOADU1_MEMINDEX;
846         case OP_LOADI2_MEMBASE:
847                 return OP_LOADI2_MEMINDEX;
848         case OP_LOADU2_MEMBASE:
849                 return OP_LOADU2_MEMINDEX;
850         case OP_LOADI1_MEMBASE:
851                 return OP_LOADI1_MEMINDEX;
852         case OP_LOADR4_MEMBASE:
853                 return OP_LOADR4_MEMINDEX;
854         case OP_LOADR8_MEMBASE:
855                 return OP_LOADR8_MEMINDEX;
856         case OP_STOREI1_MEMBASE_REG:
857                 return OP_STOREI1_MEMINDEX;
858         case OP_STOREI2_MEMBASE_REG:
859                 return OP_STOREI2_MEMINDEX;
860         case OP_STOREI4_MEMBASE_REG:
861                 return OP_STOREI4_MEMINDEX;
862         case OP_STORE_MEMBASE_REG:
863                 return OP_STORE_MEMINDEX;
864         case OP_STORER4_MEMBASE_REG:
865                 return OP_STORER4_MEMINDEX;
866         case OP_STORER8_MEMBASE_REG:
867                 return OP_STORER8_MEMINDEX;
868         case OP_STORE_MEMBASE_IMM:
869                 return OP_STORE_MEMBASE_REG;
870         case OP_STOREI1_MEMBASE_IMM:
871                 return OP_STOREI1_MEMBASE_REG;
872         case OP_STOREI2_MEMBASE_IMM:
873                 return OP_STOREI2_MEMBASE_REG;
874         case OP_STOREI4_MEMBASE_IMM:
875                 return OP_STOREI4_MEMBASE_REG;
876         }
877         g_assert_not_reached ();
878 }
879
880 /*
881  * Remove from the instruction list the instructions that can't be
882  * represented with very simple instructions with no register
883  * requirements.
884  */
885 void
886 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
887 {
888         MonoInst *ins, *next, *temp, *last_ins = NULL;
889         int imm;
890
891         /* setup the virtual reg allocator */
892         if (bb->max_vreg > cfg->rs->next_vreg)
893                 cfg->rs->next_vreg = bb->max_vreg;
894
895         MONO_BB_FOR_EACH_INS (bb, ins) {
896 loop_start:
897                 switch (ins->opcode) {
898                 case OP_ADD_IMM:
899                 case OP_ADDCC_IMM:
900                         if (!hppa_check_bits (ins->inst_imm, 11)) {
901                                 NEW_INS (cfg, temp, OP_ICONST);
902                                 temp->inst_c0 = ins->inst_imm;
903                                 temp->dreg = mono_regstate_next_int (cfg->rs);
904                                 ins->sreg2 = temp->dreg;
905                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
906                         }
907                         break;
908                 case OP_SUB_IMM:
909                 case OP_SUBCC_IMM:
910                         if (!hppa_check_bits (ins->inst_imm, 11)) {
911                                 NEW_INS (cfg, temp, OP_ICONST);
912                                 temp->inst_c0 = ins->inst_imm;
913                                 temp->dreg = mono_regstate_next_int (cfg->rs);
914                                 ins->sreg2 = temp->dreg;
915                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
916                         }
917                         break;
918
919                 case OP_MUL_IMM:
920                         if (ins->inst_imm == 1) {
921                                 ins->opcode = OP_MOVE;
922                                 break;
923                         }
924                         if (ins->inst_imm == 0) {
925                                 ins->opcode = OP_ICONST;
926                                 ins->inst_c0 = 0;
927                                 break;
928                         }
929                         imm = mono_is_power_of_two (ins->inst_imm);
930                         if (imm > 0) {
931                                 ins->opcode = OP_SHL_IMM;
932                                 ins->inst_imm = imm;
933                                 break;
934                         }
935                         else {
936                                 int tmp = mono_regstate_next_int (cfg->rs);
937                                 NEW_INS (cfg, temp, OP_ICONST);
938                                 temp->inst_c0 = ins->inst_c0;
939                                 temp->dreg = tmp;
940
941                                 ins->opcode = CEE_MUL;
942                                 ins->sreg2 = tmp;
943                                 /* Need to rewrite the CEE_MUL too... */
944                                 goto loop_start;
945                         }
946                         break;
947
948                 case CEE_MUL: {
949                         int freg1 = mono_regstate_next_float (cfg->rs);
950                         int freg2 = mono_regstate_next_float (cfg->rs);
951
952                         NEW_INS(cfg, temp, OP_STORE_MEMBASE_REG);
953                         temp->sreg1 = ins->sreg1;
954                         temp->inst_destbasereg = hppa_sp;
955                         temp->inst_offset = -16;
956
957                         NEW_INS(cfg, temp, OP_LOADR4_MEMBASE);
958                         temp->dreg = freg1;
959                         temp->inst_basereg = hppa_sp;
960                         temp->inst_offset = -16;
961
962                         NEW_INS(cfg, temp, OP_STORE_MEMBASE_REG);
963                         temp->sreg1 = ins->sreg2;
964                         temp->inst_destbasereg = hppa_sp;
965                         temp->inst_offset = -16;
966
967                         NEW_INS(cfg, temp, OP_LOADR4_MEMBASE);
968                         temp->dreg = freg2;
969                         temp->inst_basereg = hppa_sp;
970                         temp->inst_offset = -16;
971
972                         NEW_INS (cfg, temp, OP_HPPA_XMPYU);
973                         temp->dreg = freg2;
974                         temp->sreg1 = freg1;
975                         temp->sreg2 = freg2;
976
977                         NEW_INS(cfg, temp, OP_HPPA_STORER4_RIGHT);
978                         temp->sreg1 = freg2;
979                         temp->inst_destbasereg = hppa_sp;
980                         temp->inst_offset = -16;
981
982                         ins->opcode = OP_LOAD_MEMBASE;
983                         ins->inst_basereg = hppa_sp;
984                         ins->inst_offset = -16;
985                 }
986                 break;
987
988                 default:
989                         break;
990                 }
991                 last_ins = ins;
992         }
993         bb->last_ins = last_ins;
994         bb->max_vreg = cfg->rs->next_vreg;
995         
996 }
997
998 void
999 hppa_patch (guint32 *code, const gpointer target)
1000 {
1001         guint32 ins = *code;
1002         gint32 val = (gint32)target;
1003         gint32 disp = (val - (gint32)code - 8) >> 2;
1004         int reg1, reg2;
1005
1006         DEBUG (printf ("patching 0x%08x (0x%08x) to point to 0x%08x (disp = %d)\n", code, ins, val, disp));
1007
1008         switch (*code >> 26) {
1009         case 0x08: /* ldil, next insn can be a ldo, ldw, or ble */
1010                 *code = *code & ~0x1fffff;
1011                 *code = *code | hppa_op_imm21 (hppa_lsel (val));
1012                 code++;
1013
1014                 if ((*code >> 26) == 0x0D) { /* ldo */
1015                         *code = *code & ~0x3fff;
1016                         *code = *code | hppa_op_imm14 (hppa_rsel (val));
1017                 } else if ((*code >> 26) == 0x12) { /* ldw */
1018                         *code = *code & ~0x3fff;
1019                         *code = *code | hppa_op_imm14 (hppa_rsel (val));
1020                 } else if ((*code >> 26) == 0x39) { /* ble */
1021                         *code = *code & ~0x1f1ffd;
1022                         *code = *code | hppa_op_imm17 (hppa_rsel (val));
1023                 }
1024
1025                 break;
1026
1027         case 0x3A: /* bl */
1028                 if (disp == 0) {
1029                         hppa_nop (code);
1030                         break;
1031                 }
1032                 if (!hppa_check_bits (disp, 17)) 
1033                         goto jump_overflow;
1034                 reg1 = (*code >> 21) & 0x1f;
1035                 *code = (*code & ~0x1f1ffd) | hppa_op_imm17(disp);
1036                 break;
1037
1038         case 0x20: /* combt */
1039         case 0x22: /* combf */
1040                 if (!hppa_check_bits (disp >> 2, 12))
1041                         goto jump_overflow;
1042                 *code = (*code & ~0x1ffd) | hppa_op_imm12(disp);
1043                 break;
1044
1045         default:
1046                 g_warning ("Unpatched opcode %x\n", *code >> 26);
1047         }
1048
1049         return;
1050
1051 jump_overflow:
1052         g_warning ("cannot branch to target, insn is %08x, displacement is %d\n", (int)*code, (int)disp);
1053         g_assert_not_reached ();
1054 }
1055
1056 static guint32 *
1057 emit_float_to_int (MonoCompile *cfg, guint32 *code, int dreg, int sreg, int size, gboolean is_signed)
1058 {
1059         /* sreg is a float, dreg is an integer reg. */
1060         hppa_fcnvfxt (code, HPPA_FP_FMT_DBL, HPPA_FP_FMT_SGL, sreg, sreg);
1061         hppa_fstws (code, sreg, 0, -16, hppa_sp);
1062         hppa_ldw (code, -16, hppa_sp, dreg);
1063         if (!is_signed) {
1064                 if (size == 1)
1065                         hppa_extru (code, dreg, 31, 8, dreg);
1066                 else if (size == 2)
1067                         hppa_extru (code, dreg, 31, 16, dreg);
1068         } else {
1069                 if (size == 1)
1070                         hppa_extrs (code, dreg, 31, 8, dreg);
1071                 else if (size == 2)
1072                         hppa_extrs (code, dreg, 31, 16, dreg);
1073         }
1074         return code;
1075 }
1076
1077 /* Clobbers r1, r20, r21 */
1078 static guint32 *
1079 emit_memcpy (guint32 *code, int doff, int dreg, int soff, int sreg, int size)
1080 {
1081         /* r20 is the destination */
1082         hppa_set (code, doff, hppa_r20);
1083         hppa_add (code, hppa_r20, dreg, hppa_r20);
1084
1085         /* r21 is the source */
1086         hppa_set (code, soff, hppa_r21);
1087         hppa_add (code, hppa_r21, sreg, hppa_r21);
1088
1089         while (size >= 4) {
1090                 hppa_ldw (code, 0, hppa_r21, hppa_r1);
1091                 hppa_stw (code, hppa_r1, 0, hppa_r20);
1092                 hppa_ldo (code, 4, hppa_r21, hppa_r21);
1093                 hppa_ldo (code, 4, hppa_r20, hppa_r20);
1094                 size -= 4;
1095         }
1096         while (size >= 2) {
1097                 hppa_ldh (code, 0, hppa_r21, hppa_r1);
1098                 hppa_sth (code, hppa_r1, 0, hppa_r20);
1099                 hppa_ldo (code, 2, hppa_r21, hppa_r21);
1100                 hppa_ldo (code, 2, hppa_r20, hppa_r20);
1101                 size -= 2;
1102         }
1103         while (size > 0) {
1104                 hppa_ldb (code, 0, hppa_r21, hppa_r1);
1105                 hppa_stb (code, hppa_r1, 0, hppa_r20);
1106                 hppa_ldo (code, 1, hppa_r21, hppa_r21);
1107                 hppa_ldo (code, 1, hppa_r20, hppa_r20);
1108                 size -= 1;
1109         }
1110
1111         return code;
1112 }
1113
1114 /*
1115  * mono_arch_get_vcall_slot_addr:
1116  *
1117  *  Determine the vtable slot used by a virtual call.
1118  */
1119 gpointer*
1120 mono_arch_get_vcall_slot_addr (guint8 *code8, gpointer *regs)
1121 {
1122         guint32 *code = (guint32*)((unsigned long)code8 & ~3);
1123
1124         DEBUG_FUNC_ENTER();
1125
1126         code -= 2;
1127         /* This is the special virtual call token */
1128         if (code [-1] != 0x34000eee) /* ldo 0x777(r0),r0 */
1129                 return NULL;
1130
1131         if ((code [0] >> 26) == 0x39 &&         /* ble */
1132             (code [-2] >> 26) == 0x12) {        /* ldw */
1133                 guint32 ldw = code [-2];
1134                 guint32 reg = (ldw >> 21) & 0x1f;
1135                 gint32 disp = ((ldw & 1) ? (-1 << 13) : 0) | ((ldw & 0x3fff) >> 1);
1136                 /* FIXME: we are not guaranteed that reg is saved in the LMF.
1137                  * In fact, it probably isn't, since it is allocated as a
1138                  * callee register.  Right now just return an address; this 
1139                  * is sufficient for non-AOT operation
1140                  */
1141                 // return (gpointer)((guint8*)regs [reg] + disp);
1142                 return code;
1143         }
1144         else
1145                 g_assert_not_reached ();
1146
1147         DEBUG_FUNC_EXIT();
1148 }
1149
1150 /* ins->dreg = *(ins->inst_desgbasereg + ins->inst_offset) */
1151 #define EMIT_LOAD_MEMBASE(ins, op) do {                         \
1152         if (!hppa_check_bits (ins->inst_offset, 14)) {          \
1153                 hppa_set (code, ins->inst_offset, hppa_r1);     \
1154                 hppa_ ## op ## x (code, hppa_r1, ins->inst_basereg, ins->dreg); \
1155         }                                                       \
1156         else {                                                  \
1157                 hppa_ ## op (code, ins->inst_offset, ins->inst_basereg, ins->dreg); \
1158         }                                                       \
1159 } while (0)
1160
1161 #define EMIT_COND_BRANCH_FLAGS(ins,r1,r2,b0,b1) do {\
1162         if (ins->flags & MONO_INST_BRLABEL) { \
1163                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1164                 if (b0) \
1165                         hppa_combt (code, r1, r2, b1, 0); \
1166                 else \
1167                         hppa_combf (code, r1, r2, b1, 0); \
1168         } else { \
1169                 if (b0) \
1170                         hppa_combf (code, r1, r2, b1, 2); \
1171                 else \
1172                         hppa_combt (code, r1, r2, b1, 2); \
1173                 hppa_nop (code); \
1174                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1175                 hppa_bl (code, 0, hppa_r0); \
1176         } \
1177         hppa_nop (code); \
1178 } while (0)
1179
1180 #define EMIT_COND_BRANCH(ins,r1,r2,cond) EMIT_COND_BRANCH_FLAGS(ins, r1, r2, branch_b0_table [(cond)], branch_b1_table [(cond)])
1181
1182 #define EMIT_FLOAT_COND_BRANCH_FLAGS(ins,r1,r2,b0) do {\
1183         hppa_fcmp (code, HPPA_FP_FMT_DBL, b0, r1, r2); \
1184         hppa_ftest (code, 0); \
1185         if (ins->flags & MONO_INST_BRLABEL) \
1186                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1187         else \
1188                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1189         hppa_bl (code, 8, hppa_r0); \
1190         hppa_nop (code); \
1191 } while (0)
1192
1193 #define EMIT_FLOAT_COND_BRANCH(ins,r1,r2,cond) EMIT_FLOAT_COND_BRANCH_FLAGS(ins, r1, r2, float_branch_table [cond])
1194
1195 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(r1,r2,b0,b1,exc_name)          \
1196 do {                                                                    \
1197         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1198         ovfj->data.exception = (exc_name);                      \
1199         ovfj->ip_offset = (guint8*)code - cfg->native_code;     \
1200         hppa_bl (code, 8, hppa_r2);                             \
1201         hppa_depi (code, 0, 31, 2, hppa_r2);                    \
1202         hppa_ldo (code, 8, hppa_r2, hppa_r2);                   \
1203         if (b0)                                                 \
1204                 hppa_combf (code, r1, r2, b1, 2);               \
1205         else                                                    \
1206                 hppa_combt (code, r1, r2, b1, 2);               \
1207         hppa_nop (code);                                        \
1208         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1209         hppa_bl (code, 0, hppa_r0);                             \
1210         hppa_nop (code);                                        \
1211 } while (0)
1212
1213 #define EMIT_COND_SYSTEM_EXCEPTION(r1,r2,cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(r1, r2, branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1214
1215 /* TODO: MEM_INDEX_REG - cannot be r1 */
1216 #define MEM_INDEX_REG hppa_r31
1217 /* *(ins->inst_destbasereg + ins->inst_offset) = ins->inst_imm */
1218 #define EMIT_STORE_MEMBASE_IMM(ins, op) do {                    \
1219         guint32 sreg;                                           \
1220         if (ins->inst_imm == 0)                                 \
1221                 sreg = hppa_r0;                                 \
1222         else {                                                  \
1223                 hppa_set (code, ins->inst_imm, hppa_r1);        \
1224                 sreg = hppa_r1;                                 \
1225         }                                                       \
1226         if (!hppa_check_bits (ins->inst_offset, 14)) {          \
1227                 hppa_set (code, ins->inst_offset, MEM_INDEX_REG); \
1228                 hppa_addl (code, ins->inst_destbasereg, MEM_INDEX_REG, MEM_INDEX_REG); \
1229                 hppa_ ## op (code, sreg, 0, MEM_INDEX_REG);     \
1230         }                                                       \
1231         else {                                                  \
1232                 hppa_ ## op (code, sreg, ins->inst_offset, ins->inst_destbasereg); \
1233         }                                                       \
1234 } while (0)
1235
1236 /* *(ins->inst_destbasereg + ins->inst_offset) = ins->sreg1 */
1237 #define EMIT_STORE_MEMBASE_REG(ins, op) do {                    \
1238         if (!hppa_check_bits (ins->inst_offset, 14)) {          \
1239                 hppa_set (code, ins->inst_offset, MEM_INDEX_REG); \
1240                 hppa_addl (code, ins->inst_destbasereg, MEM_INDEX_REG, MEM_INDEX_REG); \
1241                 hppa_ ## op (code, ins->sreg1, 0, MEM_INDEX_REG);       \
1242         }                                                       \
1243         else {                                                  \
1244                 hppa_ ## op (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg); \
1245         }                                                       \
1246 } while (0)
1247
1248 void
1249 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1250 {
1251         MonoInst *ins;
1252         MonoCallInst *call;
1253         guint offset;
1254         guint32 *code = (guint32*)(cfg->native_code + cfg->code_len);
1255         MonoInst *last_ins = NULL;
1256         int max_len, cpos;
1257         const char *spec;
1258
1259         DEBUG_FUNC_ENTER();
1260
1261         if (cfg->verbose_level > 2)
1262                 g_print ("[%s::%s] Basic block %d starting at offset 0x%x\n", cfg->method->klass->name, cfg->method->name, bb->block_num, bb->native_offset);
1263
1264         cpos = bb->max_offset;
1265
1266         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1267                 NOT_IMPLEMENTED;
1268         }
1269
1270         MONO_BB_FOR_EACH_INS (bb, ins) {
1271                 guint8* code_start;
1272
1273                 offset = (guint8*)code - cfg->native_code;
1274
1275                 spec = ins_get_spec (ins->opcode);
1276
1277                 max_len = ((guint8 *)spec) [MONO_INST_LEN];
1278
1279                 if (offset > (cfg->code_size - max_len - 16)) {
1280                         cfg->code_size *= 2;
1281                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1282                         code = (guint32*)(cfg->native_code + offset);
1283                         mono_jit_stats.code_reallocs++;
1284                 }
1285                 code_start = (guint8*)code;
1286                 //      if (ins->cil_code)
1287                 //              g_print ("cil code\n");
1288                 mono_debug_record_line_number (cfg, ins, offset);
1289
1290                 switch (ins->opcode) {
1291                 case OP_RELAXED_NOP:
1292                         break;
1293                 case OP_STOREI1_MEMBASE_IMM:
1294                         EMIT_STORE_MEMBASE_IMM (ins, stb);
1295                         break;
1296                 case OP_STOREI2_MEMBASE_IMM:
1297                         EMIT_STORE_MEMBASE_IMM (ins, sth);
1298                         break;
1299                 case OP_STORE_MEMBASE_IMM:
1300                 case OP_STOREI4_MEMBASE_IMM:
1301                         EMIT_STORE_MEMBASE_IMM (ins, stw);
1302                         break;
1303                 case OP_STOREI1_MEMBASE_REG:
1304                         EMIT_STORE_MEMBASE_REG (ins, stb);
1305                         break;
1306                 case OP_STOREI2_MEMBASE_REG:
1307                         EMIT_STORE_MEMBASE_REG (ins, sth);
1308                         break;
1309                 case OP_STORE_MEMBASE_REG:
1310                 case OP_STOREI4_MEMBASE_REG:
1311                         EMIT_STORE_MEMBASE_REG (ins, stw);
1312                         break;
1313                 case OP_LOADU1_MEMBASE:
1314                         EMIT_LOAD_MEMBASE (ins, ldb);
1315                         break;
1316                 case OP_LOADI1_MEMBASE:
1317                         EMIT_LOAD_MEMBASE (ins, ldb);
1318                         hppa_extrs (code, ins->dreg, 31, 8, ins->dreg);
1319                         break;
1320                 case OP_LOADU2_MEMBASE:
1321                         EMIT_LOAD_MEMBASE (ins, ldh);
1322                         break;
1323                 case OP_LOADI2_MEMBASE:
1324                         EMIT_LOAD_MEMBASE (ins, ldh);
1325                         hppa_extrs (code, ins->dreg, 31, 16, ins->dreg);
1326                         break;
1327                 case OP_LOAD_MEMBASE:
1328                 case OP_LOADI4_MEMBASE:
1329                 case OP_LOADU4_MEMBASE:
1330                         EMIT_LOAD_MEMBASE (ins, ldw);
1331                         break;
1332                 case CEE_CONV_I1:
1333                         hppa_extrs (code, ins->sreg1, 31, 8, ins->dreg);
1334                         break;
1335                 case CEE_CONV_I2:
1336                         hppa_extrs (code, ins->sreg1, 31, 16, ins->dreg);
1337                         break;
1338                 case CEE_CONV_U1:
1339                         hppa_extru (code, ins->sreg1, 31, 8, ins->dreg);
1340                         break;
1341                 case CEE_CONV_U2:
1342                         hppa_extru (code, ins->sreg1, 31, 16, ins->dreg);
1343                         break;
1344                 case CEE_CONV_U:
1345                 case CEE_CONV_I4:
1346                 case CEE_CONV_U4:
1347                 case OP_MOVE:
1348                         if (ins->sreg1 != ins->dreg)
1349                                 hppa_copy (code, ins->sreg1, ins->dreg);
1350                         break;
1351                 case OP_SETLRET:
1352                         hppa_copy (code, ins->sreg1 + 1, ins->dreg);
1353                         hppa_copy (code, ins->sreg1, ins->dreg + 1);
1354                         break;
1355
1356                 case OP_BREAK:
1357                         /* break 4,8 - this is what gdb normally uses... */
1358                         *code++ = 0x00010004;
1359                         break;
1360                 case OP_ADDCC:
1361                 case CEE_ADD:
1362                         hppa_add (code, ins->sreg1, ins->sreg2, ins->dreg);
1363                         break;
1364                 case OP_ADC:
1365                         hppa_addc (code, ins->sreg1, ins->sreg2, ins->dreg);
1366                         break;
1367                 case OP_ADDCC_IMM:
1368                 case OP_ADD_IMM:
1369                         hppa_addi (code, ins->inst_imm, ins->sreg1, ins->dreg);
1370                         break;
1371                 case OP_ADC_IMM:
1372                         hppa_set (code, ins->inst_imm, hppa_r1);
1373                         hppa_addc (code, ins->sreg1, hppa_r1, ins->dreg);
1374                         break;
1375                 case OP_HPPA_ADD_OVF: {
1376                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));
1377                         hppa_bl (code, 8, hppa_r2);
1378                         hppa_depi (code, 0, 31, 2, hppa_r2);
1379                         hppa_ldo (code, 12, hppa_r2, hppa_r2);
1380
1381                         if (ins->backend.reg3 == CEE_ADD_OVF)
1382                                 hppa_add_cond (code, HPPA_ADD_COND_NSV, ins->sreg1, ins->sreg2, ins->dreg);
1383                         else                    
1384                                 hppa_add_cond (code, HPPA_ADD_COND_NUV, ins->sreg1, ins->sreg2, ins->dreg);
1385
1386                         ovfj->data.exception = "OverflowException";
1387                         ovfj->ip_offset = (guint8*)code - cfg->native_code;
1388                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj);
1389                         hppa_bl_n (code, 8, hppa_r0);
1390                         break;
1391                 }
1392                 case OP_HPPA_ADDC_OVF: {
1393                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));
1394                         hppa_bl (code, 8, hppa_r2);
1395                         hppa_depi (code, 0, 31, 2, hppa_r2);
1396                         hppa_ldo (code, 12, hppa_r2, hppa_r2);
1397
1398                         if (ins->backend.reg3 == OP_LADD_OVF)
1399                                 hppa_addc_cond (code, HPPA_ADD_COND_NSV, ins->sreg1, ins->sreg2, ins->dreg);
1400                         else                    
1401                                 hppa_addc_cond (code, HPPA_ADD_COND_NUV, ins->sreg1, ins->sreg2, ins->dreg);
1402
1403                         ovfj->data.exception = "OverflowException";
1404                         ovfj->ip_offset = (guint8*)code - cfg->native_code;
1405                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj);
1406                         hppa_bl_n (code, 8, hppa_r0);
1407                         break;
1408                 }
1409                 case OP_SUBCC:
1410                 case CEE_SUB:
1411                         hppa_sub (code, ins->sreg1, ins->sreg2, ins->dreg);
1412                         break;
1413                 case OP_SUBCC_IMM:
1414                 case OP_SUB_IMM:
1415                         hppa_addi (code, -ins->inst_imm, ins->sreg1, ins->dreg);
1416                         break;
1417                 case OP_SBB:
1418                         hppa_subb (code, ins->sreg1, ins->sreg2, ins->dreg);
1419                         break;
1420                 case OP_SBB_IMM:
1421                         hppa_set (code, ins->inst_imm, hppa_r1);
1422                         hppa_subb (code, ins->sreg1, hppa_r1, ins->dreg);
1423                         break;
1424                 case OP_HPPA_SUB_OVF: {
1425                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));
1426                         hppa_bl (code, 8, hppa_r2);
1427                         hppa_depi (code, 0, 31, 2, hppa_r2);
1428                         hppa_ldo (code, 12, hppa_r2, hppa_r2);
1429                         hppa_sub_cond (code, HPPA_SUB_COND_NSV, ins->sreg1, ins->sreg2, ins->dreg);
1430                         ovfj->data.exception = "OverflowException";
1431                         ovfj->ip_offset = (guint8*)code - cfg->native_code;
1432                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj);
1433                         hppa_bl_n (code, 8, hppa_r0);
1434                         break;
1435                 }
1436                 case OP_HPPA_SUBB_OVF: {
1437                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));
1438                         hppa_bl (code, 8, hppa_r2);
1439                         hppa_depi (code, 0, 31, 2, hppa_r2);
1440                         hppa_ldo (code, 12, hppa_r2, hppa_r2);
1441
1442                         hppa_subb_cond (code, HPPA_SUB_COND_NSV, ins->sreg1, ins->sreg2, ins->dreg);
1443                         ovfj->data.exception = "OverflowException";
1444                         ovfj->ip_offset = (guint8*)code - cfg->native_code;
1445                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj);
1446                         hppa_bl_n (code, 8, hppa_r0);
1447                         break;
1448                 }
1449
1450                 case CEE_AND:
1451                         hppa_and (code, ins->sreg1, ins->sreg2, ins->dreg);
1452                         break;
1453                 case OP_AND_IMM:
1454                         hppa_set (code, ins->inst_imm, hppa_r1);
1455                         hppa_and (code, ins->sreg1, hppa_r1, ins->dreg);
1456                         break;
1457
1458                 case CEE_OR:
1459                         hppa_or (code, ins->sreg1, ins->sreg2, ins->dreg);
1460                         break;
1461
1462                 case OP_OR_IMM:
1463                         hppa_set (code, ins->inst_imm, hppa_r1);
1464                         hppa_or (code, ins->sreg1, hppa_r1, ins->dreg);
1465                         break;
1466
1467                 case CEE_XOR:
1468                         hppa_xor (code, ins->sreg1, ins->sreg2, ins->dreg);
1469                         break;
1470                 case OP_XOR_IMM:
1471                         hppa_set (code, ins->inst_imm, hppa_r1);
1472                         hppa_xor (code, ins->sreg1, hppa_r1, ins->dreg);
1473                         break;
1474                 case CEE_SHL:
1475                         if (ins->sreg1 != ins->dreg) {
1476                                 hppa_shl (code, ins->sreg1, ins->sreg2, ins->dreg);
1477                         } 
1478                         else {
1479                                 hppa_copy (code, ins->sreg1, hppa_r1);
1480                                 hppa_shl (code, hppa_r1, ins->sreg2, ins->dreg);
1481                         }
1482                         break;
1483                 case OP_SHL_IMM:
1484                 case OP_ISHL_IMM:
1485                         g_assert (ins->inst_imm < 32);
1486                         if (ins->sreg1 != ins->dreg) {
1487                                 hppa_zdep (code, ins->sreg1, 31-ins->inst_imm, 32-ins->inst_imm, ins->dreg);
1488                         } 
1489                         else {
1490                                 hppa_copy (code, ins->sreg1, hppa_r1);
1491                                 hppa_zdep (code, hppa_r1, 31-ins->inst_imm, 32-ins->inst_imm, ins->dreg);
1492                         }
1493                         break;
1494                 case CEE_SHR:
1495                         if (ins->sreg1 != ins->dreg) {
1496                                 hppa_shr (code, ins->sreg1, ins->sreg2, ins->dreg);
1497                         }
1498                         else {
1499                                 hppa_copy (code, ins->sreg1, hppa_r1);
1500                                 hppa_shr (code, hppa_r1, ins->sreg2, ins->dreg);
1501                         }
1502                         break;
1503                 case OP_SHR_IMM:
1504                         g_assert (ins->inst_imm < 32);
1505                         if (ins->sreg1 != ins->dreg) {
1506                                 hppa_extrs (code, ins->sreg1, 31-ins->inst_imm, 32-ins->inst_imm, ins->dreg);
1507                         } 
1508                         else {
1509                                 hppa_copy (code, ins->sreg1, hppa_r1);
1510                                 hppa_extrs (code, hppa_r1, 31-ins->inst_imm, 32-ins->inst_imm, ins->dreg);
1511                         }
1512                         break;
1513                 case OP_SHR_UN_IMM:
1514                         g_assert (ins->inst_imm < 32);
1515                         if (ins->sreg1 != ins->dreg) {
1516                                 hppa_extru (code, ins->sreg1, 31-ins->inst_imm, 32-ins->inst_imm, ins->dreg);
1517                         } 
1518                         else {
1519                                 hppa_copy (code, ins->sreg1, hppa_r1);
1520                                 hppa_extru (code, hppa_r1, 31-ins->inst_imm, 32-ins->inst_imm, ins->dreg);
1521                         }
1522                         break;
1523                 case CEE_SHR_UN:
1524                         if (ins->sreg1 != ins->dreg) {
1525                                 hppa_lshr (code, ins->sreg1, ins->sreg2, ins->dreg);
1526                         }
1527                         else {
1528                                 hppa_copy (code, ins->sreg1, hppa_r1);
1529                                 hppa_lshr (code, hppa_r1, ins->sreg2, ins->dreg);
1530                         }
1531                         break;
1532                 case CEE_NOT:
1533                         hppa_not (code, ins->sreg1, ins->dreg);
1534                         break;
1535                 case CEE_NEG:
1536                         hppa_subi (code, 0, ins->sreg1, ins->dreg);
1537                         break;
1538
1539                 case CEE_MUL:
1540                 case OP_MUL_IMM:
1541                         /* Should have been rewritten using xmpyu */
1542                         g_assert_not_reached ();
1543
1544                 case OP_ICONST:
1545                         if ((ins->inst_c0 > 0 && ins->inst_c0 >= (1 << 13)) ||
1546                             (ins->inst_c0 < 0 && ins->inst_c0 < -(1 << 13))) {
1547                                 hppa_ldil (code, hppa_lsel (ins->inst_c0), ins->dreg);
1548                                 hppa_ldo (code, hppa_rsel (ins->inst_c0), ins->dreg, ins->dreg);
1549                         } else {
1550                                 hppa_ldo (code, ins->inst_c0, hppa_r0, ins->dreg);
1551                         }
1552                         break;
1553                 case OP_AOTCONST:
1554                         g_assert_not_reached ();
1555                 /*
1556                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
1557                         hppa_set_template (code, ins->dreg);
1558                 */
1559                         g_warning ("unimplemented opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
1560                         NOT_IMPLEMENTED;
1561                         break;
1562                 case OP_FMOVE:
1563                         if (ins->sreg1 != ins->dreg)
1564                                 hppa_fcpy (code, HPPA_FP_FMT_DBL, ins->sreg1, ins->dreg);
1565                         break;
1566
1567                 case OP_HPPA_OUTARG_R4CONST:
1568                         hppa_set (code, (unsigned int)ins->inst_p0, hppa_r1);
1569                         hppa_fldwx (code, hppa_r0, hppa_r1, ins->dreg, 0);
1570                         break;
1571
1572                 case OP_HPPA_OUTARG_REGOFFSET:
1573                         hppa_ldo (code, ins->inst_offset, ins->inst_basereg, ins->dreg);
1574                         break;
1575
1576                 case OP_JMP:
1577                         /*
1578                          * Keep in sync with mono_arch_emit_epilog
1579                          */
1580                         g_assert (!cfg->method->save_lmf);
1581                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
1582                         hppa_bl (code, 8, hppa_r0);
1583                         break;
1584                 case OP_CHECK_THIS:
1585                         /* ensure ins->sreg1 is not NULL */
1586                         hppa_ldw (code, 0, ins->sreg1, hppa_r1);
1587                         break;
1588                 case OP_ARGLIST:
1589                         break;
1590                 case OP_FCALL:
1591                 case OP_LCALL:
1592                 case OP_VCALL:
1593                 case OP_VOIDCALL:
1594                 case OP_CALL:
1595                         call = (MonoCallInst*)ins;
1596                         if (ins->flags & MONO_INST_HAS_METHOD)
1597                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
1598                         else
1599                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
1600                         hppa_ldil (code, 0, hppa_r1); 
1601                         hppa_ldo (code, 0, hppa_r1, hppa_r1); 
1602                         /* 
1603                          * We may have loaded an actual function address, or
1604                          * it might be a plabel. Check to see if the plabel
1605                          * bit is set, and load the actual fptr from it if
1606                          * needed
1607                          */
1608                         hppa_bb_n (code, HPPA_BIT_COND_MSB_CLR, hppa_r1, 30, 2);
1609                         hppa_depi (code, 0, 31, 2, hppa_r1);
1610                         hppa_ldw (code, 4, hppa_r1, hppa_r19);
1611                         hppa_ldw (code, 0, hppa_r1, hppa_r1);
1612                         hppa_ble (code, 0, hppa_r1);
1613                         hppa_copy (code, hppa_r31, hppa_r2);
1614                         if (call->signature->ret->type == MONO_TYPE_R4)
1615                                 hppa_fcnvff (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_DBL, hppa_fr4, hppa_fr4);
1616                         break;
1617                 case OP_FCALL_REG:
1618                 case OP_LCALL_REG:
1619                 case OP_VCALL_REG:
1620                 case OP_VOIDCALL_REG:
1621                 case OP_CALL_REG:
1622                         call = (MonoCallInst*)ins;
1623                         g_assert (!call->virtual);
1624                         hppa_copy (code, ins->sreg1, hppa_r1);
1625                         hppa_bb_n (code, HPPA_BIT_COND_MSB_CLR, hppa_r1, 30, 2);
1626                         hppa_depi (code, 0, 31, 2, hppa_r1);
1627                         hppa_ldw (code, 4, hppa_r1, hppa_r19);
1628                         hppa_ldw (code, 0, hppa_r1, hppa_r1);
1629                         hppa_ble (code, 0, hppa_r1);
1630                         hppa_copy (code, hppa_r31, hppa_r2);
1631                         if (call->signature->ret->type == MONO_TYPE_R4)
1632                                 hppa_fcnvff (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_DBL, hppa_fr4, hppa_fr4);
1633                         break;
1634                 case OP_FCALL_MEMBASE:
1635                 case OP_LCALL_MEMBASE:
1636                 case OP_VCALL_MEMBASE:
1637                 case OP_VOIDCALL_MEMBASE:
1638                 case OP_CALL_MEMBASE:
1639                         call = (MonoCallInst*)ins;
1640                         /* jump to ins->inst_sreg1 + ins->inst_offset */
1641                         hppa_ldw (code, ins->inst_offset, ins->sreg1, hppa_r1);
1642
1643                         /* For virtual calls, emit a special token that can
1644                          * be used by get_vcall_slot_addr
1645                          */
1646                         if (call->virtual)
1647                                 hppa_ldo (code, 0x777, hppa_r0, hppa_r0);
1648                         hppa_ble (code, 0, hppa_r1);
1649                         hppa_copy (code, hppa_r31, hppa_r2);
1650                         break;
1651                 case OP_LOCALLOC: {
1652                         guint32 size_reg;
1653
1654                         /* Keep alignment */
1655                         hppa_ldo (code, MONO_ARCH_LOCALLOC_ALIGNMENT - 1, ins->sreg1, ins->dreg);
1656                         hppa_depi (code, 0, 31, 6, ins->dreg);
1657                         hppa_copy (code, hppa_sp, hppa_r1);
1658                         hppa_addl (code, ins->dreg, hppa_sp, hppa_sp);
1659                         hppa_copy (code, hppa_r1, ins->dreg);
1660
1661                         if (ins->flags & MONO_INST_INIT) {
1662                                 hppa_stw (code, hppa_r0, 0, hppa_r1);
1663                                 hppa_combt (code, hppa_r1, hppa_sp, HPPA_CMP_COND_ULT, -3);
1664                                 hppa_ldo (code, 4, hppa_r1, hppa_r1);
1665                         }
1666                         break;
1667                 }
1668                 
1669                 case OP_THROW:
1670                         hppa_copy (code, ins->sreg1, hppa_r26);
1671                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
1672                                              (gpointer)"mono_arch_throw_exception");
1673                         hppa_ldil (code, 0, hppa_r1); 
1674                         hppa_ldo (code, 0, hppa_r1, hppa_r1);
1675                         hppa_ble (code, 0, hppa_r1);
1676                         hppa_copy (code, hppa_r31, hppa_r2);
1677                         /* should never return */
1678                         *code++ = 0xffeeddcc;
1679                         break;
1680                 case OP_RETHROW:
1681                         hppa_copy (code, ins->sreg1, hppa_r26);
1682                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
1683                                              (gpointer)"mono_arch_rethrow_exception");
1684                         hppa_ldil (code, 0, hppa_r1); 
1685                         hppa_ldo (code, 0, hppa_r1, hppa_r1);
1686                         hppa_ble (code, 0, hppa_r1);
1687                         hppa_copy (code, hppa_r31, hppa_r2);
1688                         /* should never return */
1689                         *code++ = 0xffeeddcc;
1690                         break;
1691                 case OP_START_HANDLER:
1692                         if (hppa_check_bits (ins->inst_left->inst_offset, 14))
1693                                 hppa_stw (code, hppa_r2, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
1694                         else {
1695                                 hppa_set (code, ins->inst_left->inst_offset, hppa_r1);
1696                                 hppa_addl (code, ins->inst_left->inst_basereg, hppa_r1, hppa_r1);
1697                                 hppa_stw (code, hppa_r2, 0, hppa_r1);
1698                         }
1699                         break;
1700                 case OP_ENDFILTER:
1701                         if (ins->sreg1 != hppa_r26)
1702                                 hppa_copy (code, ins->sreg1, hppa_r26);
1703                         if (hppa_check_bits (ins->inst_left->inst_offset, 14))
1704                                 hppa_ldw (code, ins->inst_left->inst_offset, ins->inst_left->inst_basereg, hppa_r2);
1705                         else {
1706                                 hppa_set (code, ins->inst_left->inst_offset, hppa_r1);
1707                                 hppa_ldwx (code, hppa_r1, ins->inst_left->inst_basereg, hppa_r2);
1708                         }
1709                         hppa_bv (code, hppa_r0, hppa_r2);
1710                         hppa_nop (code);
1711                         break;
1712                 case OP_ENDFINALLY:
1713                         if (hppa_check_bits (ins->inst_left->inst_offset, 14))
1714                                 hppa_ldw (code, ins->inst_left->inst_offset, ins->inst_left->inst_basereg, hppa_r1);
1715                         else {
1716                                 hppa_set (code, ins->inst_left->inst_offset, hppa_r1);
1717                                 hppa_ldwx (code, hppa_r1, ins->inst_left->inst_basereg, hppa_r1);
1718                         }
1719                         hppa_bv (code, hppa_r0, hppa_r1);
1720                         hppa_nop (code);
1721                         break;
1722                 case OP_CALL_HANDLER: 
1723                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
1724                         hppa_bl (code, 0, hppa_r2);
1725                         hppa_nop (code);
1726                         break;
1727                 case OP_LABEL:
1728                         ins->inst_c0 = (guint8*)code - cfg->native_code;
1729                         break;
1730                 case OP_BR: {
1731                         guint32 target;
1732                         DEBUG (printf ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins));
1733                         if (ins->flags & MONO_INST_BRLABEL) {
1734                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
1735                         } else {
1736                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
1737                         }
1738                         hppa_bl (code, 8, hppa_r0); 
1739                         /* TODO: if the branch is too long, we may need to
1740                          * use a long-branch sequence:
1741                          *      hppa_ldil (code, 0, hppa_r1); 
1742                          *      hppa_ldo (code, 0, hppa_r1, hppa_r1); 
1743                          *      hppa_bv (code, hppa_r0, hppa_r1);
1744                          */
1745                         hppa_nop (code);
1746                         break;
1747                 }
1748                 case OP_BR_REG:
1749                         hppa_bv (code, hppa_r0, ins->sreg1);
1750                         hppa_nop(code);
1751                         break;
1752
1753                 case OP_SWITCH: {
1754                         int i;
1755
1756                         max_len += 8 * GPOINTER_TO_INT (ins->klass);
1757                         if (offset > (cfg->code_size - max_len - 16)) {
1758                                 cfg->code_size += max_len;
1759                                 cfg->code_size *= 2;
1760                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1761                                 code = cfg->native_code + offset;
1762                                 code_start = (guint8*)code;
1763                         }
1764                         hppa_blr (code, ins->sreg1, hppa_r0);
1765                         hppa_nop (code);
1766                         for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i) {
1767                                 *code++ = 0xdeadbeef;
1768                                 *code++ = 0xdeadbeef;
1769                         }
1770                         break;
1771                 }
1772
1773                 /* comclr is cool :-) */
1774                 case OP_HPPA_CEQ:
1775                         hppa_comclr_cond (code, HPPA_SUB_COND_NE, ins->sreg1, ins->sreg2, ins->dreg);
1776                         hppa_ldo (code, 1, hppa_r0, ins->dreg);
1777                         break;
1778
1779                 case OP_HPPA_CLT:
1780                         hppa_comclr_cond (code, HPPA_SUB_COND_SGE, ins->sreg1, ins->sreg2, ins->dreg);
1781                         hppa_ldo (code, 1, hppa_r0, ins->dreg);
1782                         break;
1783
1784                 case OP_HPPA_CLT_UN:
1785                         hppa_comclr_cond (code, HPPA_SUB_COND_UGE, ins->sreg1, ins->sreg2, ins->dreg);
1786                         hppa_ldo (code, 1, hppa_r0, ins->dreg);
1787                         break;
1788
1789                 case OP_HPPA_CGT:
1790                         hppa_comclr_cond (code, HPPA_SUB_COND_SLE, ins->sreg1, ins->sreg2, ins->dreg);
1791                         hppa_ldo (code, 1, hppa_r0, ins->dreg);
1792                         break;
1793
1794                 case OP_HPPA_CGT_UN:
1795                         hppa_comclr_cond (code, HPPA_SUB_COND_ULE, ins->sreg1, ins->sreg2, ins->dreg);
1796                         hppa_ldo (code, 1, hppa_r0, ins->dreg);
1797                         break;
1798
1799                 case OP_CEQ:
1800                 case OP_CLT:
1801                 case OP_CLT_UN:
1802                 case OP_CGT:
1803                 case OP_CGT_UN:
1804                 case OP_COND_EXC_EQ:
1805                 case OP_COND_EXC_NE_UN:
1806                 case OP_COND_EXC_LT:
1807                 case OP_COND_EXC_LT_UN:
1808                 case OP_COND_EXC_GT:
1809                 case OP_COND_EXC_GT_UN:
1810                 case OP_COND_EXC_GE:
1811                 case OP_COND_EXC_GE_UN:
1812                 case OP_COND_EXC_LE:
1813                 case OP_COND_EXC_LE_UN:
1814                 case OP_COND_EXC_OV:
1815                 case OP_COND_EXC_NO:
1816                 case OP_COND_EXC_C:
1817                 case OP_COND_EXC_NC:
1818                 case OP_COND_EXC_IOV:
1819                 case OP_COND_EXC_IC:
1820                 case CEE_BEQ:
1821                 case CEE_BNE_UN:
1822                 case CEE_BLT:
1823                 case CEE_BLT_UN:
1824                 case CEE_BGT:
1825                 case CEE_BGT_UN:
1826                 case CEE_BGE:
1827                 case CEE_BGE_UN:
1828                 case CEE_BLE:
1829                 case CEE_BLE_UN:
1830                 case OP_COMPARE:
1831                 case OP_LCOMPARE:
1832                 case OP_ICOMPARE:
1833                 case OP_COMPARE_IMM:
1834                 case OP_ICOMPARE_IMM:
1835                         g_warning ("got opcode %s in %s(), should be reduced\n", mono_inst_name (ins->opcode), __FUNCTION__);
1836                         g_assert_not_reached ();
1837                         break;
1838
1839                 case OP_HPPA_BEQ:
1840                 case OP_HPPA_BNE:
1841                 case OP_HPPA_BLT:
1842                 case OP_HPPA_BLT_UN:
1843                 case OP_HPPA_BGT:
1844                 case OP_HPPA_BGT_UN:
1845                 case OP_HPPA_BGE:
1846                 case OP_HPPA_BGE_UN:
1847                 case OP_HPPA_BLE:
1848                 case OP_HPPA_BLE_UN:
1849                         EMIT_COND_BRANCH (ins, ins->sreg1, ins->sreg2, ins->opcode - OP_HPPA_BEQ);
1850                         break;
1851
1852                 case OP_HPPA_COND_EXC_EQ:
1853                 case OP_HPPA_COND_EXC_GE:
1854                 case OP_HPPA_COND_EXC_GT:
1855                 case OP_HPPA_COND_EXC_LE:
1856                 case OP_HPPA_COND_EXC_LT:
1857                 case OP_HPPA_COND_EXC_NE_UN:
1858                 case OP_HPPA_COND_EXC_GE_UN:
1859                 case OP_HPPA_COND_EXC_GT_UN:
1860                 case OP_HPPA_COND_EXC_LE_UN:
1861                 case OP_HPPA_COND_EXC_LT_UN: 
1862                         EMIT_COND_SYSTEM_EXCEPTION (ins->sreg1, ins->sreg2, ins->opcode - OP_HPPA_COND_EXC_EQ, ins->inst_p1);
1863                         break;
1864
1865                 case OP_HPPA_COND_EXC_OV:
1866                 case OP_HPPA_COND_EXC_NO:
1867                 case OP_HPPA_COND_EXC_C:
1868                 case OP_HPPA_COND_EXC_NC: 
1869                         NOT_IMPLEMENTED;
1870
1871                 /* floating point opcodes */
1872                 case OP_R8CONST:
1873                         hppa_set (code, (unsigned int)ins->inst_p0, hppa_r1);
1874                         hppa_flddx (code, hppa_r0, hppa_r1, ins->dreg);
1875                         break;
1876                 case OP_R4CONST:
1877                         hppa_set (code, (unsigned int)ins->inst_p0, hppa_r1);
1878                         hppa_fldwx (code, hppa_r0, hppa_r1, hppa_fr31, 0);
1879                         hppa_fcnvff (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_DBL, hppa_fr31, ins->dreg);
1880                         break;
1881                 case OP_STORER8_MEMBASE_REG:
1882                         hppa_set (code, ins->inst_offset, hppa_r1);
1883                         hppa_fstdx (code, ins->sreg1, hppa_r1, ins->inst_destbasereg);
1884                         break;
1885                 case OP_LOADR8_MEMBASE:
1886                         hppa_set (code, ins->inst_offset, hppa_r1);
1887                         hppa_flddx (code, hppa_r1, ins->inst_basereg, ins->dreg);
1888                         break;
1889                 case OP_STORER4_MEMBASE_REG:
1890                         hppa_fcnvff (code, HPPA_FP_FMT_DBL, HPPA_FP_FMT_SGL, ins->sreg1, hppa_fr31);
1891                         if (hppa_check_bits (ins->inst_offset, 5)) {
1892                                 hppa_fstws (code, hppa_fr31, 0, ins->inst_offset, ins->inst_destbasereg);
1893                         } else {
1894                                 hppa_set (code, ins->inst_offset, hppa_r1);
1895                                 hppa_fstwx (code, hppa_fr31, 0, hppa_r1, ins->inst_destbasereg);
1896                         }
1897                         break;
1898                 case OP_HPPA_STORER4_LEFT:
1899                 case OP_HPPA_STORER4_RIGHT:
1900                         if (hppa_check_bits (ins->inst_offset, 5)) {
1901                                 hppa_fstws (code, ins->sreg1, (ins->opcode == OP_HPPA_STORER4_RIGHT), ins->inst_offset, ins->inst_destbasereg);
1902                         } else {
1903                                 hppa_set (code, ins->inst_offset, hppa_r1);
1904                                 hppa_fstwx (code, ins->sreg1, (ins->opcode == OP_HPPA_STORER4_RIGHT), hppa_r1, ins->inst_destbasereg);
1905                         }
1906                         break;
1907                 case OP_LOADR4_MEMBASE:
1908                         if (hppa_check_bits (ins->inst_offset, 5)) {
1909                                 hppa_fldws (code, ins->inst_offset, ins->inst_basereg, hppa_fr31, 0);
1910                         } else {
1911                                 hppa_set (code, ins->inst_offset, hppa_r1);
1912                                 hppa_fldwx (code, hppa_r1, ins->inst_basereg, hppa_fr31, 0);
1913                         }
1914                         hppa_fcnvff (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_DBL, hppa_fr31, ins->dreg);
1915                         break;
1916                 case OP_HPPA_LOADR4_LEFT:
1917                 case OP_HPPA_LOADR4_RIGHT:
1918                         if (hppa_check_bits (ins->inst_offset, 5)) {
1919                                 hppa_fldws (code, ins->inst_offset, ins->inst_basereg, ins->dreg, (ins->opcode == OP_HPPA_LOADR4_RIGHT));
1920                         } else {
1921                                 hppa_set (code, ins->inst_offset, hppa_r1);
1922                                 hppa_fldwx (code, hppa_r1, ins->inst_basereg, ins->dreg, (ins->opcode == OP_HPPA_LOADR4_RIGHT));
1923                         }
1924                         break;
1925                 
1926                 case CEE_CONV_R4:
1927                         hppa_stw (code, ins->sreg1, -16, hppa_sp);
1928                         hppa_fldws (code, -16, hppa_sp, hppa_fr31, 0);
1929                         hppa_fcnvxf (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_SGL, hppa_fr31, ins->dreg);
1930                         hppa_fcnvff (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_DBL, ins->dreg, ins->dreg);
1931                         break;
1932
1933                 case OP_FCONV_TO_R4:
1934                         /* reduce precision */
1935                         hppa_fcnvff (code, HPPA_FP_FMT_DBL, HPPA_FP_FMT_SGL, ins->sreg1, ins->dreg);
1936                         hppa_fcnvff (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_DBL, ins->dreg, ins->dreg);
1937                         break;
1938
1939                 case OP_HPPA_SETF4REG:
1940                         hppa_fcnvff (code, HPPA_FP_FMT_DBL, HPPA_FP_FMT_SGL, ins->sreg1, ins->dreg);
1941                         break;
1942                 case CEE_CONV_R8: 
1943                         hppa_stw (code, ins->sreg1, -16, hppa_sp);
1944                         hppa_fldws (code, -16, hppa_sp, hppa_fr31, 0);
1945                         hppa_fcnvxf (code, HPPA_FP_FMT_SGL, HPPA_FP_FMT_DBL, hppa_fr31, ins->dreg);
1946                         break;
1947
1948                 case OP_FCONV_TO_I1:
1949                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
1950                         break;
1951                 case OP_FCONV_TO_U1:
1952                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
1953                         break;
1954                 case OP_FCONV_TO_I2:
1955                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
1956                         break;
1957                 case OP_FCONV_TO_U2:
1958                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
1959                         break;
1960                 case OP_FCONV_TO_I4:
1961                 case OP_FCONV_TO_I:
1962                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
1963                         break;
1964                 case OP_FCONV_TO_U4:
1965                 case OP_FCONV_TO_U:
1966                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
1967                         break;
1968
1969                 case OP_FCONV_TO_I8:
1970                 case OP_FCONV_TO_U8:
1971                         g_assert_not_reached ();
1972                         /* Implemented as helper calls */
1973                         break;
1974                 case OP_LCONV_TO_R_UN:
1975                         g_assert_not_reached ();
1976                         /* Implemented as helper calls */
1977                         break;
1978
1979                 case OP_LCONV_TO_OVF_I: 
1980                         NOT_IMPLEMENTED;
1981                         break;
1982
1983                 case OP_FADD:
1984                         hppa_fadd (code, HPPA_FP_FMT_DBL, ins->sreg1, ins->sreg2, ins->dreg);
1985                         break;
1986                 case OP_FSUB:
1987                         hppa_fsub (code, HPPA_FP_FMT_DBL, ins->sreg1, ins->sreg2, ins->dreg);
1988                         break;          
1989                 case OP_FMUL:
1990                         hppa_fmul (code, HPPA_FP_FMT_DBL, ins->sreg1, ins->sreg2, ins->dreg);
1991                         break;
1992                 case OP_FDIV:
1993                         hppa_fdiv (code, HPPA_FP_FMT_DBL, ins->sreg1, ins->sreg2, ins->dreg);
1994                         break;
1995                 case OP_FREM:
1996                         NOT_IMPLEMENTED;
1997                         break;          
1998
1999                 case OP_FCOMPARE:
2000                         g_assert_not_reached();
2001                         break;
2002
2003                 case OP_FCEQ:
2004                 case OP_FCLT:
2005                 case OP_FCLT_UN:
2006                 case OP_FCGT:
2007                 case OP_FCGT_UN:
2008                         hppa_fcmp (code, HPPA_FP_FMT_DBL, float_ceq_table [ins->opcode - OP_FCEQ], ins->sreg1, ins->sreg2);
2009                         hppa_ftest (code, 0);
2010                         hppa_bl (code, 12, hppa_r0);
2011                         hppa_ldo (code, 1, hppa_r0, ins->dreg);
2012                         hppa_ldo (code, 0, hppa_r0, ins->dreg);
2013                         break;
2014
2015                 case OP_FBEQ:
2016                 case OP_FBLT:
2017                 case OP_FBGT:
2018                 case OP_FBGE:
2019                 case OP_FBLE:
2020                 case OP_FBNE_UN:
2021                 case OP_FBLT_UN:
2022                 case OP_FBGT_UN:
2023                 case OP_FBGE_UN:
2024                 case OP_FBLE_UN:
2025                         EMIT_FLOAT_COND_BRANCH (ins, ins->sreg1, ins->sreg2, ins->opcode - OP_FBEQ);
2026                         break;
2027
2028                 case OP_CKFINITE: 
2029                 case OP_MEMORY_BARRIER:
2030                         break;
2031
2032                 case OP_HPPA_XMPYU:
2033                         hppa_xmpyu (code, ins->sreg1, ins->sreg2, ins->dreg);
2034                         break;
2035
2036                 default:
2037                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2038                         g_assert_not_reached ();
2039                 }
2040
2041                 if ((((guint8*)code) - code_start) > max_len) {
2042                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2043                                    mono_inst_name (ins->opcode), max_len, ((guint8*)code) - code_start);
2044                         g_assert_not_reached ();
2045                 }
2046                
2047                 cpos += max_len;
2048
2049                 last_ins = ins;
2050         }
2051
2052         cfg->code_len = (guint8*)code - cfg->native_code;
2053         DEBUG_FUNC_EXIT();
2054 }
2055
2056 void
2057 mono_arch_register_lowlevel_calls (void)
2058 {
2059 }
2060
2061 void
2062 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
2063 {
2064         MonoJumpInfo *patch_info;
2065
2066         DEBUG_FUNC_ENTER();
2067         /* FIXME: Move part of this to arch independent code */
2068         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
2069                 unsigned char *ip = patch_info->ip.i + code;
2070                 gpointer target;
2071
2072                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
2073                 DEBUG (printf ("patch_info->type = %d, target = %p\n", patch_info->type, target));
2074
2075                 switch (patch_info->type) {
2076                 case MONO_PATCH_INFO_NONE:
2077                 case MONO_PATCH_INFO_BB_OVF:
2078                 case MONO_PATCH_INFO_EXC_OVF:
2079                         continue;
2080
2081                 case MONO_PATCH_INFO_IP:
2082                         hppa_patch ((guint32 *)ip, ip);
2083                         continue;
2084
2085                 case MONO_PATCH_INFO_CLASS_INIT: {
2086                         break;
2087                 }
2088                 case MONO_PATCH_INFO_METHOD_JUMP: {
2089                         break;
2090                 }
2091                 case MONO_PATCH_INFO_SWITCH: {
2092                         int i;
2093                         gpointer *table = (gpointer *)target;
2094                         ip += 8;
2095                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
2096                                 DEBUG (printf ("Patching switch table, table[%d] = %p\n", i, table[i]));
2097                                 hppa_ldil (ip, hppa_lsel (table [i]), hppa_r1);
2098                                 hppa_be_n (ip, hppa_rsel (table [i]), hppa_r1);
2099                         }
2100                         continue;
2101                 }
2102                 default:
2103                         break;
2104                 }
2105                 hppa_patch ((guint32 *)ip, target);
2106         }
2107
2108         DEBUG_FUNC_EXIT();
2109 }
2110
2111 void*
2112 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2113 {
2114         guint32 *code = (guint32*)p;
2115
2116         DEBUG_FUNC_ENTER();
2117
2118         hppa_set (code, cfg->method, hppa_r26);
2119         hppa_copy (code, hppa_r0, hppa_r25); /* NULL sp for now */
2120         hppa_set (code, func, hppa_r1);
2121         hppa_depi (code, 0, 31, 2, hppa_r1);
2122         hppa_ldw (code, 0, hppa_r1, hppa_r1);
2123         hppa_ble (code, 0, hppa_r1);
2124         hppa_copy (code, hppa_r31, hppa_r2);
2125
2126         DEBUG_FUNC_EXIT();
2127         return code;
2128 }
2129
2130 enum {
2131         SAVE_NONE,
2132         SAVE_STRUCT,
2133         SAVE_ONE,
2134         SAVE_TWO,
2135         SAVE_FP
2136 };
2137
2138 void*
2139 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2140 {
2141         guint32 *code = (guint32*)p;
2142         DEBUG_FUNC_ENTER();
2143 #if 0
2144         int save_mode = SAVE_NONE;
2145         MonoMethod *method = cfg->method;
2146
2147         switch (mono_type_get_underlying_type (mono_method_signature (method)->ret)->type) {
2148         case MONO_TYPE_VOID:
2149                 /* special case string .ctor icall */
2150                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
2151                         save_mode = SAVE_ONE;
2152                 else
2153                         save_mode = SAVE_NONE;
2154                 break;
2155         case MONO_TYPE_I8:
2156         case MONO_TYPE_U8:
2157 #ifdef SPARCV9
2158                 save_mode = SAVE_ONE;
2159 #else
2160                 save_mode = SAVE_TWO;
2161 #endif
2162                 break;
2163         case MONO_TYPE_R4:
2164         case MONO_TYPE_R8:
2165                 save_mode = SAVE_FP;
2166                 break;
2167         case MONO_TYPE_VALUETYPE:
2168                 save_mode = SAVE_STRUCT;
2169                 break;
2170         default:
2171                 save_mode = SAVE_ONE;
2172                 break;
2173         }
2174
2175         /* Save the result to the stack and also put it into the output registers */
2176
2177         switch (save_mode) {
2178         case SAVE_TWO:
2179                 /* V8 only */
2180                 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
2181                 sparc_st_imm (code, sparc_i0, sparc_fp, 72);
2182                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
2183                 sparc_mov_reg_reg (code, sparc_i1, sparc_o2);
2184                 break;
2185         case SAVE_ONE:
2186                 sparc_sti_imm (code, sparc_i0, sparc_fp, ARGS_OFFSET);
2187                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
2188                 break;
2189         case SAVE_FP:
2190 #ifdef SPARCV9
2191                 sparc_stdf_imm (code, sparc_f0, sparc_fp, ARGS_OFFSET);
2192 #else
2193                 sparc_stdf_imm (code, sparc_f0, sparc_fp, 72);
2194                 sparc_ld_imm (code, sparc_fp, 72, sparc_o1);
2195                 sparc_ld_imm (code, sparc_fp, 72 + 4, sparc_o2);
2196 #endif
2197                 break;
2198         case SAVE_STRUCT:
2199 #ifdef SPARCV9
2200                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
2201 #else
2202                 sparc_ld_imm (code, sparc_fp, 64, sparc_o1);
2203 #endif
2204                 break;
2205         case SAVE_NONE:
2206         default:
2207                 break;
2208         }
2209
2210         sparc_set (code, cfg->method, sparc_o0);
2211
2212         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_ABS, func);
2213         EMIT_CALL ();
2214
2215         /* Restore result */
2216
2217         switch (save_mode) {
2218         case SAVE_TWO:
2219                 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
2220                 sparc_ld_imm (code, sparc_fp, 72, sparc_i0);
2221                 break;
2222         case SAVE_ONE:
2223                 sparc_ldi_imm (code, sparc_fp, ARGS_OFFSET, sparc_i0);
2224                 break;
2225         case SAVE_FP:
2226                 sparc_lddf_imm (code, sparc_fp, ARGS_OFFSET, sparc_f0);
2227                 break;
2228         case SAVE_NONE:
2229         default:
2230                 break;
2231         }
2232 #endif
2233         DEBUG_FUNC_EXIT();
2234         return code;
2235 }
2236
2237 /* 
2238  * The HPPA stack frame should look like this:
2239  *
2240  * ---------------------
2241  *  incoming params area
2242  * ---------------------
2243  *     linkage area             size = ARGS_OFFSET
2244  * ---------------------        fp = psp
2245  * HPPA_STACK_LMF_OFFSET
2246  * ---------------------
2247  * MonoLMF structure or saved registers
2248  * -------------------
2249  *        locals                size = cfg->stack_offset - cfg->param_area
2250  * ---------------------
2251  *      params area             size = cfg->param_area - ARGS_OFFSET  (aligned)
2252  * ---------------------
2253  *  callee linkage area         size = ARGS_OFFSET
2254  * --------------------- sp
2255  */
2256 guint8 *
2257 mono_arch_emit_prolog (MonoCompile *cfg)
2258 {
2259         MonoMethod *method = cfg->method;
2260         MonoBasicBlock *bb;
2261         MonoMethodSignature *sig;
2262         MonoInst *inst;
2263         int alloc_size, pos, max_offset, i;
2264         guint8 *code;
2265         CallInfo *cinfo;
2266         int tracing = 0;
2267         int lmf_offset = 0;
2268
2269         DEBUG_FUNC_ENTER();
2270         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
2271                 tracing = 1;
2272
2273         sig = mono_method_signature (method);
2274         cfg->code_size = 512 + sig->param_count * 20;
2275         code = cfg->native_code = g_malloc (cfg->code_size);
2276
2277         /* TODO: enable tail call optimization */
2278         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2279                 hppa_stw (code, hppa_r2, -20, hppa_sp);
2280         }
2281
2282         /* locals area */
2283         pos = HPPA_STACK_LMF_OFFSET;
2284
2285         /* figure out how much space we need for spilling */
2286         if (!method->save_lmf) {
2287                 /* spill callee-save registers */
2288                 guint32 mask = cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS;
2289                 for (i = 0; i < 32; i++) {
2290                         if ((1 << i) & mask)
2291                                 pos += sizeof (gulong);
2292                 }
2293         } else {
2294                 lmf_offset = pos;
2295                 pos += sizeof (MonoLMF);
2296         }
2297
2298         alloc_size = ALIGN_TO (pos + cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
2299         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) == 0);
2300
2301         cfg->stack_usage = alloc_size;
2302
2303         if (alloc_size) {
2304                 hppa_copy (code, hppa_r3, hppa_r1);
2305                 hppa_copy (code, hppa_sp, hppa_r3);
2306                 if (hppa_check_bits (alloc_size, 14))
2307                         hppa_stwm (code, hppa_r1, alloc_size, hppa_sp);
2308                 else {
2309                         hppa_stwm (code, hppa_r1, 8100, hppa_sp);
2310                         hppa_addil (code, hppa_lsel (alloc_size - 8100), hppa_sp);
2311                         hppa_ldo (code, hppa_rsel (alloc_size - 8100), hppa_r1, hppa_sp);
2312                 }
2313         }
2314
2315         /* compute max_offset in order to use short forward jumps
2316          * we always do it on hppa because the immediate displacement
2317          * for jumps is small 
2318          */
2319         max_offset = 0;
2320         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
2321                 MonoInst *ins = bb->code;
2322                 bb->max_offset = max_offset;
2323
2324                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
2325                         max_offset += 6; 
2326
2327                 MONO_BB_FOR_EACH_INS (bb, ins)
2328                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2329         }
2330
2331         DEBUG (printf ("Incoming arguments: \n"));
2332         cinfo = get_call_info (sig, sig->pinvoke);
2333
2334         /* We do this first so that we don't have to worry about the LMF-
2335          * saving code clobbering r28
2336          */
2337         if (cinfo->struct_return)
2338                 hppa_stw (code, hppa_r28, cfg->ret->inst_offset, hppa_sp);
2339
2340         /* Save the LMF or the spilled registers */
2341         pos = HPPA_STACK_LMF_OFFSET;
2342         if (!method->save_lmf) {
2343                 /* spill callee-save registers */
2344                 guint32 mask = cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS;
2345                 for (i = 0; i < 32; i++) {
2346                         if ((1 << i) & mask) {
2347                                 if (i == hppa_r3) {
2348                                         hppa_ldw (code, 0, hppa_r3, hppa_r1);
2349                                         hppa_stw (code, hppa_r1, pos, hppa_r3);
2350                                 } else
2351                                         hppa_stw (code, i, pos, hppa_r3);
2352                                 pos += sizeof (gulong);
2353                         }
2354                 }
2355         } else {
2356                 int ofs = lmf_offset + G_STRUCT_OFFSET (MonoLMF, regs);
2357                 int reg;
2358
2359                 hppa_ldw (code, 0, hppa_r3, hppa_r1);
2360                 hppa_stw (code, hppa_r1, ofs, hppa_r3);
2361                 ofs += sizeof (gulong);
2362                 for (reg = 4; reg < 32; reg++) {
2363                         if (HPPA_IS_SAVED_GREG (reg)) {
2364                                 hppa_stw (code, reg, ofs, hppa_r3);
2365                                 ofs += sizeof (gulong);
2366                         }
2367                 }
2368                 /* We shouldn't need to save the FP regs.... */
2369                 ofs = ALIGN_TO (ofs, sizeof(double));
2370                 hppa_set (code, ofs, hppa_r1);
2371                 for (reg = 0; reg < 32; reg++) {
2372                         if (HPPA_IS_SAVED_FREG (reg)) {
2373                                 hppa_fstdx (code, reg, hppa_r1, hppa_r3);
2374                                 hppa_ldo (code, sizeof(double), hppa_r1, hppa_r1);
2375                         }
2376                 }
2377
2378                 /* We also spill the arguments onto the stack, because
2379                  * the call to hppa_get_lmf_addr below can clobber them
2380                  *
2381                  * This goes in the param area that is always allocated
2382                  */
2383                 ofs = -36;
2384                 for (reg = hppa_r26; reg >= hppa_r23; reg--) {
2385                         hppa_stw (code, reg, ofs, hppa_sp);
2386                         ofs -= 4;
2387                 }
2388         }
2389
2390         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
2391                 hppa_copy (code, hppa_r30, hppa_r4);
2392
2393         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
2394                 hppa_set (code, cfg->domain, hppa_r26);
2395                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
2396                 hppa_ldil (code, 0, hppa_r1);
2397                 hppa_ldo (code, 0, hppa_r1, hppa_r1);
2398                 hppa_depi (code, 0, 31, 2, hppa_r1);
2399                 hppa_ldw (code, 0, hppa_r1, hppa_r1);
2400                 hppa_ble (code, 0, hppa_r1);
2401                 hppa_copy (code, hppa_r31, hppa_r2);
2402         }
2403
2404         if (method->save_lmf) {
2405                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2406                                      (gpointer)"mono_get_lmf_addr");
2407                 hppa_ldil (code, 0, hppa_r1);
2408                 hppa_ldo (code, 0, hppa_r1, hppa_r1);
2409                 hppa_depi (code, 0, 31, 2, hppa_r1);
2410                 hppa_ldw (code, 0, hppa_r1, hppa_r1);
2411                 hppa_ble (code, 0, hppa_r1);
2412                 hppa_copy (code, hppa_r31, hppa_r2);
2413
2414                 /* lmf_offset is the offset from the previous stack pointer,
2415                  * The pointer to the struct is put in hppa_r22 (new_lmf).
2416                  * The callee-saved registers are already in the MonoLMF 
2417                  * structure
2418                  */
2419
2420                 /* hppa_r22 = new_lmf (on the stack) */
2421                 hppa_ldo (code, lmf_offset, hppa_r3, hppa_r22);
2422                 /* lmf_offset is the offset from the previous stack pointer,
2423                  */
2424                 hppa_stw (code, hppa_r28, G_STRUCT_OFFSET(MonoLMF, lmf_addr), hppa_r22);
2425                 /* new_lmf->previous_lmf = *lmf_addr */
2426                 hppa_ldw (code, 0, hppa_r28, hppa_r1);
2427                 hppa_stw (code, hppa_r1, G_STRUCT_OFFSET(MonoLMF, previous_lmf), hppa_r22);
2428                 /* *(lmf_addr) = r22 */
2429                 hppa_stw (code, hppa_r22, 0, hppa_r28);
2430                 hppa_set (code, method, hppa_r1);
2431                 hppa_stw (code, hppa_r1, G_STRUCT_OFFSET(MonoLMF, method), hppa_r22);
2432                 hppa_stw (code, hppa_sp, G_STRUCT_OFFSET(MonoLMF, ebp), hppa_r22);
2433                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
2434                 hppa_ldil (code, 0, hppa_r1);
2435                 hppa_ldo (code, 0, hppa_r1, hppa_r1);
2436                 hppa_stw (code, hppa_r1, G_STRUCT_OFFSET(MonoLMF, eip), hppa_r22);
2437
2438                 /* Now reload the arguments from the stack */
2439                 hppa_ldw (code, -36, hppa_sp, hppa_r26);
2440                 hppa_ldw (code, -40, hppa_sp, hppa_r25);
2441                 hppa_ldw (code, -44, hppa_sp, hppa_r24);
2442                 hppa_ldw (code, -48, hppa_sp, hppa_r23);
2443         }
2444
2445         /* load arguments allocated to register from the stack */
2446         pos = 0;
2447
2448         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2449                 ArgInfo *ainfo = cinfo->args + i;
2450                 inst = cfg->args [pos];
2451
2452                 if (inst->opcode == OP_REGVAR) {
2453                         /* Want the argument in a register */
2454                         switch (ainfo->storage) {
2455                         case ArgInIReg:
2456                                 if (ainfo->reg != inst->dreg)
2457                                         hppa_copy (code, ainfo->reg, inst->dreg);
2458                                 DEBUG (printf ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg)));
2459                                 break;
2460
2461                         case ArgInIRegPair:
2462                                 if (ainfo->reg != inst->dreg) {
2463                                         hppa_copy (code, ainfo->reg, inst->dreg);
2464                                         hppa_copy (code, ainfo->reg + 1, inst->dreg + 1);
2465                                 }
2466                                 DEBUG (printf ("Argument %d assigned to register %s, %s\n", pos, mono_arch_regname (inst->dreg), mono_arch_regname (inst->dreg + 1)));
2467                                 break;
2468
2469                         case ArgInFReg:
2470                                 if (ainfo->reg != inst->dreg)
2471                                         hppa_fcpy (code, HPPA_FP_FMT_SGL, ainfo->reg, inst->dreg);
2472                                 DEBUG (printf ("Argument %d assigned to single register %s\n", pos, mono_arch_fregname (inst->dreg)));
2473                                 break;
2474
2475                         case ArgInDReg:
2476                                 if (ainfo->reg != inst->dreg)
2477                                         hppa_fcpy (code, HPPA_FP_FMT_DBL, ainfo->reg, inst->dreg);
2478                                 DEBUG (printf ("Argument %d assigned to double register %s\n", pos, mono_arch_fregname (inst->dreg)));
2479                                 break;
2480
2481                         case ArgOnStack:
2482                                 switch (ainfo->size) {
2483                                 case 1:
2484                                         hppa_ldb (code, ainfo->offset, hppa_r3, inst->dreg);
2485                                         break;
2486                                 case 2:
2487                                         hppa_ldh (code, ainfo->offset, hppa_r3, inst->dreg);
2488                                         break;
2489                                 case 4:
2490                                         hppa_ldw (code, ainfo->offset, hppa_r3, inst->dreg);
2491                                         break;
2492                                 default:
2493                                         g_assert_not_reached ();
2494                                 }
2495
2496                                 
2497                                 DEBUG (printf ("Argument %d loaded from the stack [%s - %d]\n", pos, mono_arch_regname (hppa_r3), -ainfo->offset));
2498                                 break;
2499
2500                         default:
2501                                 g_assert_not_reached ();
2502                         }
2503                 } 
2504                 else {
2505                         /* Want the argument on the stack */
2506                         switch (ainfo->storage)
2507                         {
2508                         case ArgInIReg: {
2509                                 int off, reg;
2510                                 DEBUG (printf ("Argument %d stored from register %s to stack [%s + %d]\n", pos, mono_arch_regname (ainfo->reg), mono_arch_regname (inst->inst_basereg), inst->inst_offset));
2511                                 if (hppa_check_bits (inst->inst_offset, 14)) {
2512                                         off = inst->inst_offset;
2513                                         reg = inst->inst_basereg;
2514                                 }
2515                                 else {
2516                                         hppa_set (code, inst->inst_offset, hppa_r1);
2517                                         hppa_add (code, hppa_r1, inst->inst_basereg, hppa_r1);
2518                                         off = 0;
2519                                         reg = hppa_r1;
2520                                 }
2521                                 switch (ainfo->size)
2522                                 {
2523                                 case 1:
2524                                         hppa_stb (code, ainfo->reg, off, reg);
2525                                         break;
2526                                 case 2:
2527                                         hppa_sth (code, ainfo->reg, off, reg);
2528                                         break;
2529                                 case 4:
2530                                         hppa_stw (code, ainfo->reg, off, reg);
2531                                         break;
2532                                 default:
2533                                         g_assert_not_reached ();
2534                                 }
2535                                 break;
2536                         }
2537                         case ArgInIRegPair:
2538                                 DEBUG (printf ("Argument %d stored from register (%s,%s) to stack [%s + %d]\n", pos, mono_arch_regname (ainfo->reg), mono_arch_regname (ainfo->reg+1), mono_arch_regname (inst->inst_basereg), inst->inst_offset));
2539                                 if (hppa_check_bits (inst->inst_offset + 4, 14)) {
2540                                         hppa_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2541                                         hppa_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
2542                                 }
2543                                 else {
2544                                         hppa_ldo (code, inst->inst_offset, inst->inst_basereg, hppa_r1);
2545                                         hppa_stw (code, ainfo->reg, 0, hppa_r1);
2546                                         hppa_stw (code, ainfo->reg + 1, 4, hppa_r1);
2547                                 }
2548                                 break;
2549
2550                         case ArgInFReg:
2551                                 DEBUG (printf ("Argument %d (float) stored from register %s to stack [%s + %d]\n", pos, mono_arch_fregname (ainfo->reg), mono_arch_regname (inst->inst_basereg), inst->inst_offset));
2552                                 hppa_ldo (code, inst->inst_offset, inst->inst_basereg, hppa_r1);
2553                                 hppa_fstwx (code, ainfo->reg, 0, hppa_r0, hppa_r1);
2554                                 break;
2555
2556                         case ArgInDReg:
2557                                 DEBUG (printf ("Argument %d (double) stored from register %s to stack [%s + %d]\n", pos, mono_arch_fregname (ainfo->reg), mono_arch_regname (inst->inst_basereg), inst->inst_offset));
2558                                 hppa_ldo (code, inst->inst_offset, inst->inst_basereg, hppa_r1);
2559                                 hppa_fstdx (code, ainfo->reg, hppa_r0, hppa_r1);
2560                                 break;
2561
2562                         case ArgOnStack:
2563                                 DEBUG (printf ("Argument %d copied from [%s - %d] to [%s + %d] (size=%d)\n", pos, mono_arch_regname (hppa_r3), -ainfo->offset, mono_arch_regname (inst->inst_basereg), inst->inst_offset, ainfo->size));
2564                                 if (inst->inst_offset != ainfo->offset ||
2565                                     inst->inst_basereg != hppa_r3)
2566                                         code = emit_memcpy (code, inst->inst_offset, inst->inst_basereg, ainfo->offset, hppa_r3, ainfo->size);
2567                                 break;
2568
2569                         default:
2570                                 g_assert_not_reached ();
2571                         }
2572                 }
2573
2574                 pos++;
2575         }
2576
2577
2578         if (tracing)
2579                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
2580
2581         if (getenv("HPPA_BREAK")) {
2582                 *(guint32*)code = 0x00010004;
2583                 code += 4;
2584         }
2585
2586         cfg->code_len = code - cfg->native_code;
2587         g_assert (cfg->code_len < cfg->code_size);
2588         g_free (cinfo);
2589
2590         DEBUG_FUNC_EXIT();
2591         return code;
2592 }
2593
2594
2595 void
2596 mono_arch_emit_epilog (MonoCompile *cfg)
2597 {
2598         MonoMethod *method = cfg->method;
2599         MonoMethodSignature *sig;
2600         guint32 *code;
2601         int max_epilog_size = 16 + 20 * 4;
2602         int pos;
2603         
2604         DEBUG_FUNC_ENTER();
2605         sig = mono_method_signature (cfg->method);
2606         if (cfg->method->save_lmf)
2607                 max_epilog_size += 128;
2608         
2609         if (mono_jit_trace_calls != NULL)
2610                 max_epilog_size += 50;
2611
2612         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2613                 max_epilog_size += 50;
2614
2615         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
2616                 cfg->code_size *= 2;
2617                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2618                 mono_jit_stats.code_reallocs++;
2619         }
2620
2621         code = (guint32*)(cfg->native_code + cfg->code_len);
2622
2623         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
2624                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
2625
2626         pos = HPPA_STACK_LMF_OFFSET;
2627         if (cfg->method->save_lmf) {
2628                 int reg;
2629                 hppa_ldo (code, pos, hppa_r3, hppa_r22);
2630                 hppa_ldw (code, G_STRUCT_OFFSET(MonoLMF, previous_lmf), hppa_r22, hppa_r21);
2631                 hppa_ldw (code, G_STRUCT_OFFSET(MonoLMF, lmf_addr), hppa_r22, hppa_r20);
2632                 hppa_stw (code, hppa_r21, G_STRUCT_OFFSET(MonoLMF, previous_lmf), hppa_r20);
2633
2634                 pos += G_STRUCT_OFFSET(MonoLMF, regs) + sizeof (gulong);
2635                 /* We skip the restore of r3 here, it is restored from the
2636                  * stack anyway. This makes the code a bit easier.
2637                  */
2638                 for (reg = 4; reg < 31; reg++) {
2639                         if (HPPA_IS_SAVED_GREG (reg)) {
2640                                 hppa_ldw (code, pos, hppa_r3, reg);
2641                                 pos += sizeof(gulong);
2642                         }
2643                 }
2644                 
2645                 pos = ALIGN_TO (pos, sizeof (double));
2646                 hppa_set (code, pos, hppa_r1);
2647                 for (reg = 0; reg < 31; reg++) {
2648                         if (HPPA_IS_SAVED_FREG (reg)) {
2649                                 hppa_flddx (code, hppa_r1, hppa_r3, reg);
2650                                 hppa_ldo (code, sizeof (double), hppa_r1, hppa_r1);
2651                                 pos += sizeof (double);
2652                         }
2653                 }
2654         } else {
2655                 guint32 mask = cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS;
2656                 int i;
2657                 for (i = 0; i < 32; i++) {
2658                         if (i == hppa_r3)
2659                                 continue;
2660                         if ((1 << i) & mask) {
2661                                 hppa_ldw (code, pos, hppa_r3, i);
2662                                 pos += sizeof (gulong);
2663                         }
2664                 }
2665         }
2666
2667         if (sig->ret->type != MONO_TYPE_VOID && 
2668             mono_type_to_stind (sig->ret) == CEE_STOBJ) {
2669                 CallInfo *cinfo = get_call_info (sig, sig->pinvoke);
2670
2671                 switch (cinfo->ret.storage) {
2672                 case ArgInIReg:
2673                         hppa_ldw (code, cfg->ret->inst_offset, hppa_sp, hppa_r28);
2674                         hppa_ldw (code, 0, hppa_r28, hppa_r28);
2675                         break;
2676                 case ArgInIRegPair:
2677                         hppa_ldw (code, cfg->ret->inst_offset, hppa_sp, hppa_r28);
2678                         hppa_ldw (code, 4, hppa_r28, hppa_r29);
2679                         hppa_ldw (code, 0, hppa_r28, hppa_r28);
2680                         break;
2681                 case ArgOnStack:
2682                         /* Nothing to do */
2683                         break;
2684                 default:
2685                         g_assert_not_reached ();
2686                 }
2687                 g_free (cinfo);
2688         }
2689
2690         if (1 || cfg->flags & MONO_CFG_HAS_CALLS)
2691                 hppa_ldw (code, -20, hppa_r3, hppa_r2);
2692         hppa_ldo (code, 64, hppa_r3, hppa_sp);
2693         hppa_bv (code, hppa_r0, hppa_r2);
2694         hppa_ldwm (code, -64, hppa_sp, hppa_r3);
2695
2696         cfg->code_len = (guint8*)code - cfg->native_code;
2697
2698         g_assert (cfg->code_len < cfg->code_size);
2699         DEBUG_FUNC_EXIT();
2700 }
2701
2702 /* remove once throw_exception_by_name is eliminated */
2703 static int
2704 exception_id_by_name (const char *name)
2705 {
2706         if (strcmp (name, "IndexOutOfRangeException") == 0)
2707                 return MONO_EXC_INDEX_OUT_OF_RANGE;
2708         if (strcmp (name, "OverflowException") == 0)
2709                 return MONO_EXC_OVERFLOW;
2710         if (strcmp (name, "ArithmeticException") == 0)
2711                 return MONO_EXC_ARITHMETIC;
2712         if (strcmp (name, "DivideByZeroException") == 0)
2713                 return MONO_EXC_DIVIDE_BY_ZERO;
2714         if (strcmp (name, "InvalidCastException") == 0)
2715                 return MONO_EXC_INVALID_CAST;
2716         if (strcmp (name, "NullReferenceException") == 0)
2717                 return MONO_EXC_NULL_REF;
2718         if (strcmp (name, "ArrayTypeMismatchException") == 0)
2719                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
2720         g_error ("Unknown intrinsic exception %s\n", name);
2721         return 0;
2722 }
2723
2724 void
2725 mono_arch_emit_exceptions (MonoCompile *cfg)
2726 {
2727         MonoJumpInfo *patch_info;
2728         int i;
2729         guint8 *code;
2730         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
2731         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
2732         int max_epilog_size = 50;
2733
2734         DEBUG_FUNC_ENTER();
2735
2736         /* count the number of exception infos */
2737      
2738         /* 
2739          * make sure we have enough space for exceptions
2740          */
2741         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2742                 switch (patch_info->type) {
2743                 case MONO_PATCH_INFO_BB_OVF:
2744                         g_assert_not_reached ();
2745                         break;
2746
2747                 case MONO_PATCH_INFO_EXC_OVF: {
2748                         const MonoOvfJump *ovfj = patch_info->data.target;
2749                         max_epilog_size += 8;
2750                         i = exception_id_by_name (ovfj->data.exception);
2751                         if (!exc_throw_found [i]) {
2752                                 max_epilog_size += 24;
2753                                 exc_throw_found [i] = TRUE;
2754                         }
2755                         break;
2756                 }
2757
2758                 case MONO_PATCH_INFO_EXC:
2759                         i = exception_id_by_name (patch_info->data.target);
2760                         if (!exc_throw_found [i]) {
2761                                 max_epilog_size += 24;
2762                                 exc_throw_found [i] = TRUE;
2763                         }
2764                         break;
2765
2766                 default:
2767                         break;
2768                 }
2769         }
2770
2771         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
2772                 cfg->code_size *= 2;
2773                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2774                 mono_jit_stats.code_reallocs++;
2775         }
2776
2777         code = cfg->native_code + cfg->code_len;
2778
2779         /* add code to raise exceptions */
2780         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2781                 switch (patch_info->type) {
2782                 case MONO_PATCH_INFO_BB_OVF: {
2783                         /* TODO */
2784                         break;
2785                 }
2786                 case MONO_PATCH_INFO_EXC_OVF: {
2787                         const MonoOvfJump *ovfj = patch_info->data.target;
2788                         MonoJumpInfo *newji;
2789                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
2790                         unsigned char *stub = code;
2791
2792                         /* Patch original call, point it at the stub */
2793                         hppa_patch ((guint32 *)ip, code);
2794
2795                         /* Write the stub */
2796                         /* SUBTLE: this has to be PIC, because the code block
2797                          * can be relocated
2798                          */
2799                         hppa_bl_n (code, 8, hppa_r0);
2800                         hppa_nop (code);
2801
2802                         /* Add a patch info to patch the stub to point to the exception code */
2803                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2804                         newji->type = MONO_PATCH_INFO_EXC;
2805                         newji->ip.i = stub - cfg->native_code;
2806                         newji->data.target = ovfj->data.exception;
2807                         newji->next = patch_info->next;
2808                         patch_info->next = newji;
2809                         break;
2810                 }
2811                 case MONO_PATCH_INFO_EXC: {
2812                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
2813                         i = exception_id_by_name (patch_info->data.target);
2814                         if (exc_throw_pos [i]) {
2815                                 hppa_patch ((guint32 *)ip, exc_throw_pos [i]);
2816                                 patch_info->type = MONO_PATCH_INFO_NONE;
2817                                 break;
2818                         } else {
2819                                 exc_throw_pos [i] = code;
2820                         }
2821                         hppa_patch ((guint32 *)ip, code);
2822                         hppa_set (code, patch_info->data.target, hppa_r26);
2823                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
2824                         patch_info->data.name = "mono_arch_throw_exception_by_name";
2825                         patch_info->ip.i = code - cfg->native_code;
2826                         
2827                         /* Assume the caller has set r2, we can't set it 
2828                          * here based on ip, because the caller may 
2829                          * be relocated (also the "ip" may be from an overflow
2830                          * stub)
2831                          */
2832                         hppa_ldil (code, 0, hppa_r1);
2833                         hppa_ldo (code, 0, hppa_r1, hppa_r1);
2834                         hppa_bv (code, hppa_r0, hppa_r1);
2835                         hppa_nop (code);
2836                         break;
2837                 }
2838                 default:
2839                         /* do nothing */
2840                         break;
2841                 }
2842         }
2843
2844         cfg->code_len = code - cfg->native_code;
2845
2846         g_assert (cfg->code_len < cfg->code_size);
2847         DEBUG_FUNC_EXIT();
2848 }
2849
2850 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2851
2852 #error "--with-sigaltstack=yes not supported on hppa"
2853
2854 #endif
2855
2856 void
2857 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
2858 {
2859 }
2860
2861 void
2862 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
2863 {
2864 }
2865
2866 void
2867 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
2868 {
2869         /* add the this argument */
2870         if (this_reg != -1) {
2871                 MonoInst *this;
2872                 MONO_INST_NEW (cfg, this, OP_MOVE);
2873                 this->type = this_type;
2874                 this->sreg1 = this_reg;
2875                 this->dreg = mono_regstate_next_int (cfg->rs);
2876                 mono_bblock_add_inst (cfg->cbb, this);
2877                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, hppa_r26, FALSE);
2878         }
2879
2880         if (vt_reg != -1) {
2881                 MonoInst *vtarg;
2882                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
2883                 vtarg->type = STACK_MP;
2884                 vtarg->sreg1 = vt_reg;
2885                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
2886                 mono_bblock_add_inst (cfg->cbb, vtarg);
2887                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, hppa_r28, FALSE);
2888         }
2889 }
2890
2891
2892 MonoInst*
2893 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
2894 {
2895         MonoInst *ins = NULL;
2896         DEBUG_FUNC_ENTER();
2897         DEBUG_FUNC_EXIT();
2898
2899         return ins;
2900 }
2901
2902 /*
2903  * mono_arch_get_argument_info:
2904  * @csig:  a method signature
2905  * @param_count: the number of parameters to consider
2906  * @arg_info: an array to store the result infos
2907  *
2908  * Gathers information on parameters such as size, alignment and
2909  * padding. arg_info should be large enought to hold param_count + 1 entries. 
2910  *
2911  * Returns the size of the activation frame.
2912  */
2913 int
2914 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
2915 {
2916         int k, align;
2917         CallInfo *cinfo;
2918         ArgInfo *ainfo;
2919
2920         DEBUG_FUNC_ENTER();
2921         cinfo = get_call_info (csig, FALSE);
2922
2923         if (csig->hasthis) {
2924                 ainfo = &cinfo->args [0];
2925                 arg_info [0].offset = ainfo->offset;
2926         }
2927
2928         for (k = 0; k < param_count; k++) {
2929                 ainfo = &cinfo->args [k + csig->hasthis];
2930
2931                 arg_info [k + 1].offset = ainfo->offset;
2932                 arg_info [k + 1].size = mono_type_size (csig->params [k], &align);
2933         }
2934
2935         g_free (cinfo);
2936         DEBUG_FUNC_EXIT();
2937 }
2938
2939 gboolean
2940 mono_arch_print_tree (MonoInst *tree, int arity)
2941 {
2942         return 0;
2943 }
2944
2945 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
2946 {
2947         return NULL;
2948 }
2949
2950 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
2951 {
2952         return NULL;
2953 }
2954
2955 gpointer
2956 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
2957 {
2958         /* FIXME: implement */
2959         g_assert_not_reached ();
2960 }