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