In mono/metadata:
[mono.git] / mono / mini / mini-alpha.c
blob2c372c44cb6e6190a817150dfeabbe88cfe4f6f6
1 /*------------------------------------------------------------------*/
2 /* */
3 /* Name - mini-alpha.c */
4 /* */
5 /* Function - Alpha backend for the Mono code generator. */
6 /* */
7 /* Name - Sergey Tikhonov (tsv@solvo.ru) */
8 /* */
9 /* Date - January, 2006 */
10 /* */
11 /* Derivation - From mini-am64 & mini-ia64 & mini-s390 by - */
12 /* Paolo Molaro (lupus@ximian.com) */
13 /* Dietmar Maurer (dietmar@ximian.com) */
14 /* Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
15 /* */
16 /*------------------------------------------------------------------*/
18 /*------------------------------------------------------------------*/
19 /* D e f i n e s */
20 /*------------------------------------------------------------------*/
21 #define ALPHA_DEBUG(x) \
22 if (mini_alpha_verbose_level) \
23 g_debug ("ALPHA_DEBUG: %s is called.", x);
25 #define ALPHA_PRINT if (mini_alpha_verbose_level)
27 #define NEW_INS(cfg,dest,op) do { \
28 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
29 (dest)->opcode = (op); \
30 insert_after_ins (bb, last_ins, (dest)); \
31 } while (0)
33 #undef DEBUG
34 #define DEBUG(a) if (cfg->verbose_level > 1) a
36 #define CFG_DEBUG(LVL) if (cfg->verbose_level > LVL)
38 //#define ALPHA_IS_CALLEE_SAVED_REG(reg) (MONO_ARCH_CALLEE_SAVED_REGS & (1 << (reg)))
39 #define ALPHA_ARGS_REGS ((regmask_t)0x03F0000)
40 #define ARGS_OFFSET 16
42 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
43 #define alpha_is_imm(X) ((X >= 0 && X <= 255))
44 #define ALPHA_LOAD_GP(IP) { AlphaGotData ge_data; add_got_entry(cfg, GT_LD_GTADDR, ge_data, IP, MONO_PATCH_INFO_NONE, 0); }
46 /*========================= End of Defines =========================*/
48 /*------------------------------------------------------------------*/
49 /* I n c l u d e s */
50 /*------------------------------------------------------------------*/
52 #include "mini.h"
53 #include <string.h>
55 #include <mono/metadata/appdomain.h>
56 #include <mono/metadata/debug-helpers.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/utils/mono-math.h>
60 #include "trace.h"
61 #include "mini-alpha.h"
62 #include "cpu-alpha.h"
63 #include "jit-icalls.h"
65 /*========================= End of Includes ========================*/
67 /*------------------------------------------------------------------*/
68 /* G l o b a l V a r i a b l e s */
69 /*------------------------------------------------------------------*/
70 static int indent_level = 0;
72 int mini_alpha_verbose_level = 0;
73 static int bwx_supported = 0;
75 static gboolean tls_offset_inited = FALSE;
77 static int appdomain_tls_offset = -1,
78 lmf_tls_offset = -1,
79 thread_tls_offset = -1;
81 pthread_key_t lmf_addr_key;
83 gboolean lmf_addr_key_inited = FALSE;
85 MonoBreakpointInfo
86 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
88 /*====================== End of Global Variables ===================*/
90 gpointer mono_arch_get_lmf_addr (void);
92 typedef enum {
93 ArgInIReg,
94 ArgInFloatReg,
95 ArgInDoubleReg,
96 ArgOnStack,
97 ArgValuetypeInReg, // ??
98 ArgAggregate,
99 ArgNone
100 } ArgStorage;
103 typedef struct {
104 gint16 offset;
105 gint8 reg;
106 ArgStorage storage;
108 /* Only if storage == ArgAggregate */
109 int nregs, nslots;
110 //AggregateType atype; // So far use only AggregateNormal
111 } ArgInfo;
113 typedef struct {
114 int nargs;
115 guint32 stack_usage;
116 // guint32 struct_ret; /// ???
118 guint32 reg_usage;
119 guint32 freg_usage;
120 gboolean need_stack_align;
122 ArgInfo ret;
123 ArgInfo sig_cookie;
124 ArgInfo args [1];
125 } CallInfo;
127 static CallInfo* get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke);
128 static unsigned int *emit_call(MonoCompile *cfg, unsigned int *code,
129 guint32 patch_type, gconstpointer data);
131 #define PARAM_REGS 6
132 static int param_regs [] =
134 alpha_a0, alpha_a1,
135 alpha_a2, alpha_a3,
136 alpha_a4, alpha_a5
139 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
141 static void inline
142 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
144 ainfo->offset = *stack_size;
146 if (*gr >= PARAM_REGS)
148 ainfo->storage = ArgOnStack;
149 (*stack_size) += sizeof (gpointer);
151 else
153 ainfo->storage = ArgInIReg;
154 ainfo->reg = param_regs [*gr];
155 (*gr) ++;
159 #define FLOAT_PARAM_REGS 6
160 static int fparam_regs [] = { alpha_fa0, alpha_fa1, alpha_fa2, alpha_fa3,
161 alpha_fa4, alpha_fa5 };
163 static void inline
164 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo,
165 gboolean is_double)
167 ainfo->offset = *stack_size;
169 if (*gr >= FLOAT_PARAM_REGS)
171 ainfo->storage = ArgOnStack;
172 (*stack_size) += sizeof (gpointer);
174 else
176 /* A double register */
177 if (is_double)
178 ainfo->storage = ArgInDoubleReg;
179 else
180 ainfo->storage = ArgInFloatReg;
182 ainfo->reg = fparam_regs [*gr];
183 (*gr) += 1;
187 static void
188 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
189 gboolean is_return,
190 guint32 *gr, guint32 *fr, guint32 *stack_size)
192 guint32 size;
193 MonoClass *klass;
194 MonoMarshalType *info;
195 //gboolean is_hfa = TRUE;
196 //guint32 hfa_type = 0;
198 klass = mono_class_from_mono_type (type);
199 if (type->type == MONO_TYPE_TYPEDBYREF)
200 size = 3 * sizeof (gpointer);
201 else if (sig->pinvoke)
202 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
203 else
204 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
206 if (!sig->pinvoke || (size == 0) || is_return) {
207 /* Allways pass in memory */
208 ainfo->offset = *stack_size;
209 *stack_size += ALIGN_TO (size, 8);
210 ainfo->storage = ArgOnStack;
212 return;
215 info = mono_marshal_load_type_info (klass);
216 g_assert (info);
218 ainfo->storage = ArgAggregate;
219 //ainfo->atype = AggregateNormal;
221 #if 0
222 /* This also handles returning of TypedByRef used by some icalls */
223 if (is_return) {
224 if (size <= 32) {
225 ainfo->reg = IA64_R8;
226 ainfo->nregs = (size + 7) / 8;
227 ainfo->nslots = ainfo->nregs;
228 return;
230 NOT_IMPLEMENTED;
232 #endif
234 ainfo->reg = param_regs [*gr];
235 ainfo->offset = *stack_size;
236 ainfo->nslots = (size + 7) / 8;
238 if (((*gr) + ainfo->nslots) <= 6) {
239 /* Fits entirely in registers */
240 ainfo->nregs = ainfo->nslots;
241 (*gr) += ainfo->nregs;
242 return;
245 ainfo->nregs = 6 - (*gr);
246 (*gr) = 6;
247 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
251 // This function is called from mono_arch_call_opcode and
252 // should determine which registers will be used to do the call
253 // For Alpha we could calculate number of parameter used for each
254 // call and allocate space in stack only for whose "a0-a5" registers
255 // that will be used in calls
256 static void
257 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
258 ArgStorage storage, int reg, MonoInst *tree)
260 switch (storage)
262 case ArgInIReg:
263 arg->opcode = OP_OUTARG_REG;
264 arg->inst_left = tree;
265 arg->inst_right = (MonoInst*)call;
266 arg->backend.reg3 = reg;
267 call->used_iregs |= 1 << reg;
268 break;
269 case ArgInFloatReg:
270 arg->opcode = OP_OUTARG_FREG;
271 arg->inst_left = tree;
272 arg->inst_right = (MonoInst*)call;
273 arg->backend.reg3 = reg;
274 call->used_fregs |= 1 << reg;
275 break;
276 case ArgInDoubleReg:
277 arg->opcode = OP_OUTARG_FREG;
278 arg->inst_left = tree;
279 arg->inst_right = (MonoInst*)call;
280 arg->backend.reg3 = reg;
281 call->used_fregs |= 1 << reg;
282 break;
283 default:
284 g_assert_not_reached ();
288 static void
289 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
291 if (ins == NULL)
293 ins = bb->code;
294 bb->code = to_insert;
295 to_insert->next = ins;
297 else
299 to_insert->next = ins->next;
300 ins->next = to_insert;
304 static void add_got_entry(MonoCompile *cfg, AlphaGotType ge_type,
305 AlphaGotData ge_data,
306 int ip, MonoJumpInfoType type, gconstpointer target)
308 AlphaGotEntry *AGE = mono_mempool_alloc (cfg->mempool,
309 sizeof (AlphaGotEntry));
311 AGE->type = ge_type;
313 switch(ge_type)
315 case GT_INT:
316 AGE->value.data.i = ge_data.data.i;
317 break;
318 case GT_LONG:
319 AGE->value.data.l = ge_data.data.l;
320 break;
321 case GT_PTR:
322 AGE->value.data.p = ge_data.data.p;
323 break;
324 case GT_FLOAT:
325 AGE->value.data.f = ge_data.data.f;
326 break;
327 case GT_DOUBLE:
328 AGE->value.data.d = ge_data.data.d;
329 break;
330 case GT_LD_GTADDR:
331 AGE->value.data.l = ip;
332 break;
333 default:
334 AGE->type = GT_NONE;
337 if (type != MONO_PATCH_INFO_NONE)
339 mono_add_patch_info(cfg, ip, type, target);
340 AGE->patch_info = cfg->patch_info;
342 else
343 AGE->patch_info = 0;
345 if (AGE->type != GT_LD_GTADDR)
347 mono_add_patch_info(cfg, ip, MONO_PATCH_INFO_GOT_OFFSET, 0);
348 AGE->got_patch_info = cfg->patch_info;
351 AGE->next = cfg->arch.got_data;
353 cfg->arch.got_data = AGE;
356 /*------------------------------------------------------------------*/
357 /* */
358 /* Name - mono_arch_create_vars */
359 /* */
360 /* Function - */
361 /* */
362 /* Returns -
364 * Params:
365 * cfg - pointer to compile unit
367 * TSV (guess)
368 * This method is called right before starting converting compiled
369 * method to IR. I guess we could find out how many arguments we
370 * should expect, what type and what return value would be.
371 * After that we could correct "cfg" structure, or "arch" part of
372 * that structure.
374 /* */
375 /*------------------------------------------------------------------*/
377 void
378 mono_arch_create_vars (MonoCompile *cfg)
380 MonoMethodSignature *sig;
381 CallInfo *cinfo;
383 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
385 sig = mono_method_signature (cfg->method);
387 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
389 if (cinfo->ret.storage == ArgValuetypeInReg)
390 cfg->ret_var_is_local = TRUE;
392 g_free (cinfo);
396 /*------------------------------------------------------------------*/
397 /* */
398 /* Name - mono_arch_get_lmf_addr */
399 /* */
400 /* Function - */
401 /* */
402 /* Returns - */
403 /* */
404 /*------------------------------------------------------------------*/
406 gpointer
407 mono_arch_get_lmf_addr (void)
409 ALPHA_DEBUG("mono_arch_get_lmf_addr");
411 return pthread_getspecific (lmf_addr_key);
414 /*========================= End of Function ========================*/
416 /*------------------------------------------------------------------*/
417 /* */
418 /* Name - mono_arch_free_jit_tls_data */
419 /* */
420 /* Function - Free tls data. */
421 /* */
422 /*------------------------------------------------------------------*/
424 void
425 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
427 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
430 /*========================= End of Function ========================*/
432 // This peephole function is called before "local_regalloc" method
433 // TSV_TODO - Check what we need to move here
434 void
435 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
437 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_1 pass\n");
440 // This peephole function is called after "local_regalloc" method
441 void
442 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
444 MonoInst *ins, *n, *last_ins = NULL;
445 ins = bb->code;
447 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_2 pass\n");
449 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
450 switch (ins->opcode)
452 case OP_MOVE:
453 case OP_FMOVE:
455 * Removes:
457 * OP_MOVE reg, reg except special case (mov at, at)
459 if (ins->dreg == ins->sreg1 &&
460 ins->dreg != alpha_at)
462 MONO_DELETE_INS (bb, ins);
463 continue;
467 * Removes:
469 * OP_MOVE sreg, dreg
470 * OP_MOVE dreg, sreg
472 if (last_ins && last_ins->opcode == OP_MOVE &&
473 ins->sreg1 == last_ins->dreg &&
474 last_ins->dreg != alpha_at &&
475 ins->dreg == last_ins->sreg1)
477 MONO_DELETE_INS (bb, ins);
478 continue;
481 break;
482 case OP_MUL_IMM:
483 case OP_IMUL_IMM:
484 /* remove unnecessary multiplication with 1 */
485 if (ins->inst_imm == 1)
487 if (ins->dreg != ins->sreg1)
489 ins->opcode = OP_MOVE;
491 else
493 MONO_DELETE_INS (bb, ins);
494 continue;
498 break;
500 case OP_LOADI8_MEMBASE:
501 case OP_LOAD_MEMBASE:
503 * Note: if reg1 = reg2 the load op is removed
505 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
506 * OP_LOADI8_MEMBASE offset(basereg), reg2
507 * -->
508 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
509 * OP_MOVE reg1, reg2
511 if (last_ins &&
512 (last_ins->opcode == OP_STOREI8_MEMBASE_REG ||
513 last_ins->opcode == OP_STORE_MEMBASE_REG) &&
514 ins->inst_basereg == last_ins->inst_destbasereg &&
515 ins->inst_offset == last_ins->inst_offset)
517 if (ins->dreg == last_ins->sreg1)
519 MONO_DELETE_INS (bb, ins);
520 continue;
522 else
524 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
525 ins->opcode = OP_MOVE;
526 ins->sreg1 = last_ins->sreg1;
529 break;
531 #if 0
532 case OP_LOAD_MEMBASE:
533 case OP_LOADI4_MEMBASE:
535 * Note: if reg1 = reg2 the load op is removed
537 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
538 * OP_LOAD_MEMBASE offset(basereg), reg2
539 * -->
540 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
541 * OP_MOVE reg1, reg2
543 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
544 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
545 ins->inst_basereg == last_ins->inst_destbasereg &&
546 ins->inst_offset == last_ins->inst_offset)
548 if (ins->dreg == last_ins->sreg1)
550 MONO_DELETE_INS (bb, ins);
551 continue;
553 else
555 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
556 ins->opcode = OP_MOVE;
557 ins->sreg1 = last_ins->sreg1;
561 * Note: reg1 must be different from the basereg in the second load
562 * Note: if reg1 = reg2 is equal then second load is removed
564 * OP_LOAD_MEMBASE offset(basereg), reg1
565 * OP_LOAD_MEMBASE offset(basereg), reg2
566 * -->
567 * OP_LOAD_MEMBASE offset(basereg), reg1
568 * OP_MOVE reg1, reg2
571 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
572 || last_ins->opcode == OP_LOAD_MEMBASE) &&
573 ins->inst_basereg != last_ins->dreg &&
574 ins->inst_basereg == last_ins->inst_basereg &&
575 ins->inst_offset == last_ins->inst_offset)
577 if (ins->dreg == last_ins->dreg)
579 MONO_DELETE_INS (bb, ins);
580 continue;
582 else
584 ins->opcode = OP_MOVE;
585 ins->sreg1 = last_ins->dreg;
588 //g_assert_not_reached ();
590 break;
591 #endif
594 last_ins = ins;
595 ins = ins->next;
598 bb->last_ins = last_ins;
601 // Convert to opposite branch opcode
602 static guint16 cvt_branch_opcode(guint16 opcode)
604 switch (opcode)
606 case CEE_BEQ:
607 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
608 return CEE_BNE_UN;
611 //case CEE_CGT_UN:
612 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
613 //return OP_IBEQ;
615 //case OP_LCGT_UN:
616 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
617 //return OP_IBEQ;
619 // case OP_CGT_UN:
620 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
621 //return OP_IBEQ;
623 case OP_IBEQ:
624 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
625 return OP_IBNE_UN;
627 case OP_FBEQ:
628 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
629 return OP_FBNE_UN;
631 case OP_FBNE_UN:
632 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
633 return OP_FBEQ;
635 case OP_IBNE_UN:
636 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
637 return OP_IBEQ;
639 case CEE_BNE_UN:
640 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
641 return OP_IBEQ;
643 case OP_IBLE:
644 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
645 return OP_IBNE_UN;
647 case OP_IBLE_UN:
648 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
649 return OP_IBNE_UN;
651 case CEE_BLE:
652 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
653 return OP_IBNE_UN;
655 case CEE_BLE_UN:
656 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
657 return OP_IBNE_UN;
659 case OP_IBLT:
660 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
661 return OP_IBNE_UN;
663 case CEE_BLT:
664 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
665 return OP_IBNE_UN;
667 case CEE_BLT_UN:
668 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
669 return OP_IBNE_UN;
671 case OP_IBLT_UN:
672 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
673 return OP_IBNE_UN;
675 case OP_IBGE:
676 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
677 return OP_IBEQ;
679 case CEE_BGE:
680 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
681 return OP_IBEQ;
683 case CEE_BGT:
684 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
685 return OP_IBEQ;
687 case OP_IBGT:
688 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
689 return OP_IBEQ;
691 case CEE_BGT_UN:
692 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
693 return OP_IBEQ;
695 case OP_IBGT_UN:
696 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
697 return OP_IBEQ;
699 case CEE_BGE_UN:
700 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
701 return OP_IBEQ;
703 case OP_IBGE_UN:
704 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
705 return OP_IBEQ;
707 default:
708 break;
711 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
713 return opcode;
716 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
718 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
720 guint16 ret_opcode;
722 switch (opcode)
724 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
725 case OP_FCOMPARE:
726 break;
728 case OP_COMPARE:
729 case OP_ICOMPARE:
730 case OP_LCOMPARE:
732 switch(cond)
734 case EQ:
735 return OP_ALPHA_CMP_EQ;
736 case ULE:
737 return OP_ALPHA_CMP_ULE;
738 case LE:
739 return OP_ALPHA_CMP_LE;
740 case LT:
741 return OP_ALPHA_CMP_LT;
742 case ULT:
743 return OP_ALPHA_CMP_ULT;
746 break;
748 case OP_ICOMPARE_IMM:
749 case OP_COMPARE_IMM:
751 switch(cond)
753 case EQ:
754 return OP_ALPHA_CMP_IMM_EQ;
755 case ULE:
756 return OP_ALPHA_CMP_IMM_ULE;
757 case LE:
758 return OP_ALPHA_CMP_IMM_LE;
759 case LT:
760 return OP_ALPHA_CMP_IMM_LT;
761 case ULT:
762 return OP_ALPHA_CMP_IMM_ULT;
767 g_assert_not_reached();
769 return ret_opcode;
772 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
774 // Instead of compare+b<cond>,
775 // Alpha has compare<cond>+br<cond>
776 // we need to convert
777 // Handle floating compare here too
779 switch(next->opcode)
781 case CEE_BEQ:
782 case OP_IBEQ:
783 // Convert cmp + beq -> cmpeq + bne
784 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
785 next->opcode = cvt_branch_opcode(next->opcode);
786 break;
788 case OP_IBNE_UN:
789 case CEE_BNE_UN:
790 // cmp + ibne_un -> cmpeq + beq
791 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
792 next->opcode = cvt_branch_opcode(next->opcode);
793 break;
795 case OP_IBLE:
796 case CEE_BLE:
797 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
798 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
799 next->opcode = cvt_branch_opcode(next->opcode);
800 break;
802 case CEE_BLE_UN:
803 case OP_IBLE_UN:
804 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
805 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
806 next->opcode = cvt_branch_opcode(next->opcode);
807 break;
809 case OP_IBLT:
810 case CEE_BLT:
811 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
812 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
813 next->opcode = cvt_branch_opcode(next->opcode);
814 break;
816 case CEE_BLT_UN:
817 case OP_IBLT_UN:
818 // lcmp + blt.un -> cmpult + bne
819 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
820 next->opcode = cvt_branch_opcode(next->opcode);
821 break;
823 case OP_IBGE:
824 case CEE_BGE:
825 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
826 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
827 next->opcode = cvt_branch_opcode(next->opcode);
828 break;
830 case CEE_BGE_UN:
831 case OP_IBGE_UN:
832 //lcmp + bge.un -> cmpult + beq
833 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
834 next->opcode = cvt_branch_opcode(next->opcode);
835 break;
837 case OP_IBGT:
838 case CEE_BGT:
839 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
840 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
841 next->opcode = cvt_branch_opcode(next->opcode);
842 break;
844 case CEE_BGT_UN:
845 case OP_IBGT_UN:
846 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
847 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
848 next->opcode = cvt_branch_opcode(next->opcode);
849 break;
851 // case CEE_CGT_UN:
852 case OP_CGT_UN:
853 case OP_ICGT_UN:
854 // cmp + cgt_un -> cmpule + beq
855 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
856 break;
858 case OP_ICEQ:
859 case OP_CEQ:
860 // cmp + iceq -> cmpeq + bne
861 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
862 break;
864 case OP_ICGT:
865 case OP_CGT:
866 // cmp + int_cgt -> cmple + beq
867 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
868 break;
870 case OP_ICLT:
871 case OP_CLT:
872 // cmp + int_clt -> cmplt + bne
873 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
874 break;
876 case OP_ICLT_UN:
877 case OP_CLT_UN:
878 // cmp + int_clt_un -> cmpult + bne
879 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
880 break;
883 // The conditional exceptions will be handled in
884 // output_basic_blocks. Here we just determine correct
885 // cmp
886 case OP_COND_EXC_GT:
887 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
888 break;
890 case OP_COND_EXC_GT_UN:
891 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
892 break;
894 case OP_COND_EXC_LT:
895 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
896 break;
898 case OP_COND_EXC_LT_UN:
899 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
900 break;
902 case OP_COND_EXC_LE_UN:
903 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
904 break;
906 case OP_COND_EXC_NE_UN:
907 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
908 break;
910 case OP_COND_EXC_EQ:
911 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
912 break;
915 default:
916 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
917 mono_inst_name(next->opcode), next->opcode);
919 // g_assert_not_reached();
921 break;
927 * mono_arch_lowering_pass:
929 * Converts complex opcodes into simpler ones so that each IR instruction
930 * corresponds to one machine instruction.
932 void
933 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
935 MonoInst *ins, *n, *temp, *last_ins = NULL;
936 MonoInst *next;
938 ins = bb->code;
941 * FIXME: Need to add more instructions, but the current machine
942 * description can't model some parts of the composite instructions like
943 * cdq.
946 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
947 switch (ins->opcode)
949 case OP_DIV_IMM:
950 case OP_REM_IMM:
951 case OP_IDIV_IMM:
952 case OP_IREM_IMM:
953 case OP_MUL_IMM:
954 NEW_INS (cfg, temp, OP_I8CONST);
955 temp->inst_c0 = ins->inst_imm;
956 temp->dreg = mono_alloc_ireg (cfg);
958 switch (ins->opcode)
960 case OP_MUL_IMM:
961 ins->opcode = CEE_MUL;
962 break;
963 case OP_DIV_IMM:
964 ins->opcode = OP_LDIV;
965 break;
966 case OP_REM_IMM:
967 ins->opcode = OP_LREM;
968 break;
969 case OP_IDIV_IMM:
970 ins->opcode = OP_IDIV;
971 break;
972 case OP_IREM_IMM:
973 ins->opcode = OP_IREM;
974 break;
977 ins->sreg2 = temp->dreg;
978 break;
980 case OP_COMPARE:
981 case OP_ICOMPARE:
982 case OP_LCOMPARE:
983 case OP_FCOMPARE:
985 // Instead of compare+b<cond>/fcompare+b<cond>,
986 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
987 // we need to convert
988 next = ins->next;
990 cvt_cmp_branch(ins, next);
992 break;
994 case OP_COMPARE_IMM:
995 if (!alpha_is_imm (ins->inst_imm))
997 NEW_INS (cfg, temp, OP_I8CONST);
998 temp->inst_c0 = ins->inst_imm;
999 temp->dreg = mono_alloc_ireg (cfg);
1000 ins->opcode = OP_COMPARE;
1001 ins->sreg2 = temp->dreg;
1003 // We should try to reevaluate new IR opcode
1004 //continue;
1007 next = ins->next;
1009 cvt_cmp_branch(ins, next);
1011 break;
1013 case OP_ICOMPARE_IMM:
1014 if (!alpha_is_imm (ins->inst_imm))
1016 NEW_INS (cfg, temp, OP_ICONST);
1017 temp->inst_c0 = ins->inst_imm;
1018 temp->dreg = mono_alloc_ireg (cfg);
1019 ins->opcode = OP_ICOMPARE;
1020 ins->sreg2 = temp->dreg;
1022 // We should try to reevaluate new IR opcode
1023 //continue;
1026 next = ins->next;
1028 cvt_cmp_branch(ins, next);
1030 break;
1032 case OP_STORE_MEMBASE_IMM:
1033 case OP_STOREI8_MEMBASE_IMM:
1034 if (ins->inst_imm != 0)
1036 NEW_INS (cfg, temp, OP_I8CONST);
1037 temp->inst_c0 = ins->inst_imm;
1038 temp->dreg = mono_alloc_ireg (cfg);
1039 ins->opcode = OP_STOREI8_MEMBASE_REG;
1040 ins->sreg1 = temp->dreg;
1042 break;
1044 case OP_STOREI4_MEMBASE_IMM:
1045 if (ins->inst_imm != 0)
1047 MonoInst *temp;
1048 NEW_INS (cfg, temp, OP_ICONST);
1049 temp->inst_c0 = ins->inst_imm;
1050 temp->dreg = mono_alloc_ireg (cfg);
1051 ins->opcode = OP_STOREI4_MEMBASE_REG;
1052 ins->sreg1 = temp->dreg;
1054 break;
1056 case OP_STOREI1_MEMBASE_IMM:
1057 if (ins->inst_imm != 0 || !bwx_supported)
1059 MonoInst *temp;
1060 NEW_INS (cfg, temp, OP_ICONST);
1061 temp->inst_c0 = ins->inst_imm;
1062 temp->dreg = mono_alloc_ireg (cfg);
1063 ins->opcode = OP_STOREI1_MEMBASE_REG;
1064 ins->sreg1 = temp->dreg;
1066 break;
1068 case OP_STOREI2_MEMBASE_IMM:
1069 if (ins->inst_imm != 0 || !bwx_supported)
1071 MonoInst *temp;
1072 NEW_INS (cfg, temp, OP_ICONST);
1073 temp->inst_c0 = ins->inst_imm;
1074 temp->dreg = mono_alloc_ireg (cfg);
1075 ins->opcode = OP_STOREI2_MEMBASE_REG;
1076 ins->sreg1 = temp->dreg;
1078 break;
1080 case OP_IADD_IMM:
1081 case OP_ISUB_IMM:
1082 case OP_IAND_IMM:
1083 case OP_IOR_IMM:
1084 case OP_IXOR_IMM:
1085 case OP_ISHL_IMM:
1086 case OP_ISHR_IMM:
1087 case OP_ISHR_UN_IMM:
1088 if (!alpha_is_imm(ins->inst_imm))
1090 MonoInst *temp;
1091 NEW_INS (cfg, temp, OP_ICONST);
1092 temp->inst_c0 = ins->inst_imm;
1093 temp->dreg = mono_alloc_ireg (cfg);
1095 switch(ins->opcode)
1097 case OP_IADD_IMM:
1098 ins->opcode = OP_IADD;
1099 break;
1100 case OP_ISUB_IMM:
1101 ins->opcode = OP_ISUB;
1102 break;
1103 case OP_IAND_IMM:
1104 ins->opcode = OP_IAND;
1105 break;
1106 case OP_IOR_IMM:
1107 ins->opcode = OP_IOR;
1108 break;
1109 case OP_IXOR_IMM:
1110 ins->opcode = OP_IXOR;
1111 break;
1112 case OP_ISHL_IMM:
1113 ins->opcode = OP_ISHL;
1114 break;
1115 case OP_ISHR_IMM:
1116 ins->opcode = OP_ISHR;
1117 break;
1118 case OP_ISHR_UN_IMM:
1119 ins->opcode = OP_ISHR_UN;
1121 default:
1122 break;
1125 ins->sreg2 = temp->dreg;
1127 break;
1128 case OP_ADD_IMM:
1129 case OP_AND_IMM:
1130 case OP_SHL_IMM:
1131 if (!alpha_is_imm(ins->inst_imm))
1133 MonoInst *temp;
1134 NEW_INS (cfg, temp, OP_ICONST);
1135 temp->inst_c0 = ins->inst_imm;
1136 temp->dreg = mono_alloc_ireg (cfg);
1138 switch(ins->opcode)
1140 case OP_ADD_IMM:
1141 ins->opcode = CEE_ADD;
1142 break;
1143 case OP_ISUB_IMM:
1144 ins->opcode = CEE_SUB;
1145 break;
1146 case OP_AND_IMM:
1147 ins->opcode = CEE_AND;
1148 break;
1149 case OP_SHL_IMM:
1150 ins->opcode = CEE_SHL;
1151 break;
1152 default:
1153 break;
1156 ins->sreg2 = temp->dreg;
1158 break;
1159 case OP_LSHR_IMM:
1160 if (!alpha_is_imm(ins->inst_imm))
1162 MonoInst *temp;
1163 NEW_INS(cfg, temp, OP_ICONST);
1164 temp->inst_c0 = ins->inst_imm;
1165 temp->dreg = mono_alloc_ireg (cfg);
1166 ins->sreg2 = temp->dreg;
1167 ins->opcode = OP_LSHR;
1169 break;
1170 case OP_LSHL_IMM:
1171 if (!alpha_is_imm(ins->inst_imm))
1173 MonoInst *temp;
1174 NEW_INS(cfg, temp, OP_ICONST);
1175 temp->inst_c0 = ins->inst_imm;
1176 temp->dreg = mono_alloc_ireg (cfg);
1177 ins->sreg2 = temp->dreg;
1178 ins->opcode = OP_LSHL;
1180 break;
1182 default:
1183 break;
1186 last_ins = ins;
1187 ins = ins->next;
1190 bb->last_ins = last_ins;
1192 bb->max_vreg = cfg->next_vreg;
1195 /*========================= End of Function ========================*/
1197 #define AXP_GENERAL_REGS 6
1198 #define AXP_MIN_STACK_SIZE 24
1200 /* A typical Alpha stack frame looks like this */
1202 fun: // called from outside the module.
1203 ldgp gp,0(pv) // load the global pointer
1204 fun..ng: // called from inside the module.
1205 lda sp, -SIZE( sp ) // grow the stack downwards.
1207 stq ra, 0(sp) // save the return address.
1209 stq s0, 8(sp) // callee-saved registers.
1210 stq s1, 16(sp) // ...
1212 // Move the arguments to the argument registers...
1214 mov addr, pv // Load the callee address
1215 jsr ra, (pv) // call the method.
1216 ldgp gp, 0(ra) // restore gp
1218 // return value is in v0
1220 ldq ra, 0(sp) // free stack frame
1221 ldq s0, 8(sp) // restore callee-saved registers.
1222 ldq s1, 16(sp)
1223 ldq sp, 32(sp) // restore stack pointer
1225 ret zero, (ra), 1 // return.
1227 // min SIZE = 48
1228 // our call must look like this.
1230 call_func:
1231 ldgp gp, 0(pv)
1232 call_func..ng:
1233 .prologue
1234 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1235 stq ra, SIZE-48(sp) // store ra
1236 stq fp, SIZE-40(sp) // store fp (frame pointer)
1237 stq a0, SIZE-32(sp) // store args. a0 = func
1238 stq a1, SIZE-24(sp) // a1 = retval
1239 stq a2, SIZE-16(sp) // a2 = this
1240 stq a3, SIZE-8(sp) // a3 = args
1241 mov sp, fp // set frame pointer
1242 mov pv, a0 // func
1244 .calling_arg_this
1245 mov a1, a2
1247 .calling_arg_6plus
1248 ldq t0, POS(a3)
1249 stq t0, 0(sp)
1250 ldq t1, POS(a3)
1251 stq t1, 8(sp)
1252 ... SIZE-56 ...
1254 mov zero,a1
1255 mov zero,a2
1256 mov zero,a3
1257 mov zero,a4
1258 mov zero,a5
1260 .do_call
1261 jsr ra, (pv) // call func
1262 ldgp gp, 0(ra) // restore gp.
1263 mov v0, t1 // move return value into t1
1265 .do_store_retval
1266 ldq t0, SIZE-24(fp) // load retval into t2
1267 stl t1, 0(t0) // store value.
1269 .finished
1270 mov fp,sp
1271 ldq ra,SIZE-48(sp)
1272 ldq fp,SIZE-40(sp)
1273 lda sp,SIZE(sp)
1274 ret zero,(ra),1
1278 * emit_load_volatile_arguments:
1280 * Load volatile arguments from the stack to the original input registers.
1281 * Required before a tail call.
1283 static unsigned int*
1284 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1286 MonoMethod *method = cfg->method;
1287 MonoMethodSignature *sig;
1288 MonoInst *inst;
1289 CallInfo *cinfo;
1290 guint32 i;
1292 /* FIXME: Generate intermediate code instead */
1294 sig = mono_method_signature (method);
1296 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1298 if (sig->ret->type != MONO_TYPE_VOID) {
1299 if ((cinfo->ret.storage == ArgInIReg) &&
1300 (cfg->ret->opcode != OP_REGVAR))
1302 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1303 cfg->ret->inst_offset);
1307 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1309 ArgInfo *ainfo = &cinfo->args [i];
1310 MonoInst *inst = cfg->args [i];
1312 switch(ainfo->storage)
1314 case ArgInIReg:
1315 // We need to save all used a0-a5 params
1316 //for (i=0; i<PARAM_REGS; i++)
1317 // {
1318 // if (i < cinfo->reg_usage)
1320 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1321 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1323 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1324 ainfo->reg, inst->inst_offset/*offset*/);
1327 break;
1328 case ArgInDoubleReg:
1329 case ArgInFloatReg:
1330 // We need to save all used af0-af5 params
1331 //for (i=0; i<PARAM_REGS; i++)
1332 // {
1333 // if (i < cinfo->freg_usage)
1335 switch(cinfo->args[i].storage)
1337 case ArgInFloatReg:
1338 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1339 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1340 break;
1341 case ArgInDoubleReg:
1342 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1343 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1344 break;
1345 default:
1349 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1350 ainfo->reg, /*offset*/inst->inst_offset);
1354 g_free (cinfo);
1356 return code;
1359 /*------------------------------------------------------------------*/
1360 /* */
1361 /* Name - mono_arch_emit_prolog */
1362 /* */
1363 /* Function - Create the instruction sequence for a function */
1364 /* prolog. */
1366 * How to handle consts and method addreses:
1367 * For method we will allocate array of qword after method epiloge.
1368 * These qword will hold readonly info to method to properly to run.
1369 * For example: qword constants, method addreses
1370 * GP will point to start of data. Offsets to the data will be equal
1371 * to "address" of data - start of GP. (GP = 0 during method jiting).
1372 * GP is easily calculated from passed PV (method start address).
1373 * The patch will update GP loadings.
1374 * The GOT section should be more than 32Kb.
1375 * The patch code should put proper offset since the real position of
1376 * qword array will be known after the function epiloge.
1378 /*------------------------------------------------------------------*/
1380 guint8 *
1381 mono_arch_emit_prolog (MonoCompile *cfg)
1383 MonoMethod *method = cfg->method;
1384 MonoMethodSignature *sig = mono_method_signature (method);
1385 //int alloc_size, code_size, max_offset, quad;
1386 unsigned int *code;
1387 CallInfo *cinfo;
1388 int i, stack_size, offset;
1389 gint32 lmf_offset = cfg->arch.lmf_offset;
1391 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1393 // FIXME: Use just one field to hold calculated stack size
1394 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1395 cfg->arch.got_data = 0;
1397 cfg->code_size = 512;
1399 code = (unsigned int *)g_malloc(cfg->code_size);
1400 cfg->native_code = (void *)code;
1402 // Emit method prolog
1403 // Calculate GP from passed PV, allocate stack
1404 ALPHA_LOAD_GP(0)
1405 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1406 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1407 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1409 offset = cfg->arch.params_stack_size;
1411 /* store call convention parameters on stack */
1412 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1413 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1415 /* set the frame pointer */
1416 alpha_mov1( code, alpha_sp, alpha_fp );
1418 /* Save LMF */
1419 if (method->save_lmf)
1421 // Save IP
1422 alpha_stq(code, alpha_pv, alpha_fp,
1423 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1424 // Save SP
1425 alpha_stq(code, alpha_sp, alpha_fp,
1426 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1427 // Save FP
1428 alpha_stq(code, alpha_fp, alpha_fp,
1429 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1430 // Save GP
1431 alpha_stq(code, alpha_gp, alpha_fp,
1432 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1434 // Save method
1435 alpha_stq(code, alpha_pv, alpha_fp,
1436 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1439 /* Save (global) regs */
1440 offset = cfg->arch.reg_save_area_offset;
1442 for (i = 0; i < MONO_MAX_IREGS; ++i)
1443 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1444 (cfg->used_int_regs & (1 << i)) &&
1445 !( ALPHA_ARGS_REGS & (1 << i)) )
1447 alpha_stq(code, i, alpha_fp, offset);
1448 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1449 i, offset);
1450 offset += 8;
1453 offset = cfg->arch.args_save_area_offset;
1455 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1457 if (sig->ret->type != MONO_TYPE_VOID)
1459 if ((cinfo->ret.storage == ArgInIReg) &&
1460 (cfg->ret->opcode != OP_REGVAR))
1462 /* Save volatile arguments to the stack */
1463 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1464 cfg->ret->inst_offset);
1468 /* Keep this in sync with emit_load_volatile_arguments */
1469 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1471 ArgInfo *ainfo = &cinfo->args [i];
1472 MonoInst *inst = cfg->args [i];
1473 int j;
1475 switch(ainfo->storage)
1477 case ArgInIReg:
1478 // We need to save all used a0-a5 params
1480 if (inst->opcode == OP_REGVAR)
1482 alpha_mov1(code, ainfo->reg, inst->dreg);
1483 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1484 ainfo->reg, inst->dreg);
1486 else
1488 alpha_stq(code, ainfo->reg, inst->inst_basereg,
1489 inst->inst_offset);
1491 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1492 ainfo->reg, inst->inst_offset);
1494 offset += 8;
1497 break;
1498 case ArgAggregate:
1500 for(j=0; j<ainfo->nregs; j++)
1502 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1503 ainfo->reg + j, inst->inst_offset + (8*j));
1504 alpha_stq(code, (ainfo->reg+j), inst->inst_basereg,
1505 (inst->inst_offset + (8*j)));
1506 offset += 8;
1509 break;
1510 case ArgInDoubleReg:
1511 case ArgInFloatReg:
1512 // We need to save all used af0-af5 params
1514 switch(cinfo->args[i].storage)
1516 case ArgInFloatReg:
1517 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1518 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1519 break;
1520 case ArgInDoubleReg:
1521 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1522 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1523 break;
1524 default:
1528 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1529 ainfo->reg, /*offset*/inst->inst_offset);
1531 offset += 8;
1536 offset = cfg->arch.reg_save_area_offset;
1539 for (i = 0; i < MONO_MAX_VREGS; ++i)
1540 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1541 (cfg->used_int_regs & (1 << i)) &&
1542 !( ALPHA_ARGS_REGS & (1 << i)) )
1544 alpha_stq(code, i, alpha_fp, offset);
1545 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1546 i, offset);
1547 offset += 8;
1550 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1552 if (method->save_lmf)
1555 * The call might clobber argument registers, but they are already
1556 * saved to the stack/global regs.
1559 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1560 (gpointer)"mono_get_lmf_addr");
1562 // Save lmf_addr
1563 alpha_stq(code, alpha_r0, alpha_fp,
1564 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1565 // Load "previous_lmf" member of MonoLMF struct
1566 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1568 // Save it to MonoLMF struct
1569 alpha_stq(code, alpha_r1, alpha_fp,
1570 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1572 // Set new LMF
1573 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1574 alpha_stq(code, alpha_r1, alpha_r0, 0);
1577 g_free (cinfo);
1579 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1580 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1581 code, TRUE);
1583 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1585 g_assert (cfg->code_len < cfg->code_size);
1587 return (gint8 *)code;
1590 /*========================= End of Function ========================*/
1592 /*------------------------------------------------------------------*/
1593 /* */
1594 /* Name - mono_arch_flush_register_windows */
1595 /* */
1596 /* Function - */
1597 /* */
1598 /* Returns - */
1599 /* */
1600 /*------------------------------------------------------------------*/
1602 void
1603 mono_arch_flush_register_windows (void)
1605 ALPHA_DEBUG("mono_arch_flush_register_windows");
1607 /*========================= End of Function ========================*/
1609 /*------------------------------------------------------------------*/
1610 /* */
1611 /* Name - mono_arch_regalloc_cost */
1612 /* */
1613 /* Function - Determine the cost, in the number of memory */
1614 /* references, of the action of allocating the var- */
1615 /* iable VMV into a register during global register */
1616 /* allocation. */
1617 /* */
1618 /* Returns - Cost */
1619 /* */
1620 /*------------------------------------------------------------------*/
1622 guint32
1623 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1625 MonoInst *ins = cfg->varinfo [vmv->idx];
1627 /* FIXME: */
1628 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1630 if (cfg->method->save_lmf)
1631 /* The register is already saved */
1632 /* substract 1 for the invisible store in the prolog */
1633 return (ins->opcode == OP_ARG) ? 1 : 0;
1634 else
1635 /* push+pop */
1636 return (ins->opcode == OP_ARG) ? 2 : 1;
1639 /*========================= End of Function ========================*/
1643 ** This method emits call sequience
1646 static unsigned int *
1647 emit_call(MonoCompile *cfg, unsigned int *code,
1648 guint32 patch_type, gconstpointer data)
1650 int offset;
1651 AlphaGotData ge_data;
1653 offset = (char *)code - (char *)cfg->native_code;
1655 ge_data.data.p = (void *)data;
1656 add_got_entry(cfg, GT_PTR, ge_data,
1657 offset, patch_type, data);
1659 // Load call address into PV
1660 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1662 // Call method
1663 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1665 offset = (char *)code - (char *)cfg->native_code;
1667 // Restore GP
1668 ALPHA_LOAD_GP(offset)
1669 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1670 alpha_lda(code, alpha_gp, alpha_gp, 0);
1672 return code;
1675 /*------------------------------------------------------------------*/
1676 /* */
1677 /* Name - arch_get_argument_info */
1678 /* */
1679 /* Function - Gathers information on parameters such as size, */
1680 /* alignment, and padding. arg_info should be large */
1681 /* enough to hold param_count + 1 entries. */
1682 /* */
1683 /* Parameters - @csig - Method signature */
1684 /* @param_count - No. of parameters to consider */
1685 /* @arg_info - An array to store the result info */
1686 /* */
1687 /* Returns - Size of the activation frame */
1688 /* */
1689 /*------------------------------------------------------------------*/
1692 mono_arch_get_argument_info (MonoMethodSignature *csig,
1693 int param_count,
1694 MonoJitArgumentInfo *arg_info)
1696 int k;
1697 CallInfo *cinfo = get_call_info (NULL, csig, FALSE);
1698 guint32 args_size = cinfo->stack_usage;
1700 ALPHA_DEBUG("mono_arch_get_argument_info");
1702 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1703 if (csig->hasthis)
1705 arg_info [0].offset = 0;
1708 for (k = 0; k < param_count; k++)
1710 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1712 /* FIXME: */
1713 // Set size to 1
1714 // The size is checked only for valuetype in trace.c
1715 arg_info [k + 1].size = 8;
1718 g_free (cinfo);
1720 return args_size;
1723 /*------------------------------------------------------------------*/
1724 /* */
1725 /* Name - mono_arch_emit_epilog */
1726 /* */
1727 /* Function - Emit the instructions for a function epilog. */
1728 /* */
1729 /*------------------------------------------------------------------*/
1731 void
1732 mono_arch_emit_epilog (MonoCompile *cfg)
1734 MonoMethod *method = cfg->method;
1735 int offset, i;
1736 unsigned int *code;
1737 int max_epilog_size = 128;
1738 int stack_size = cfg->arch.stack_size;
1739 // CallInfo *cinfo;
1740 gint32 lmf_offset = cfg->arch.lmf_offset;
1742 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1744 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1746 cfg->code_size *= 2;
1747 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1748 mono_jit_stats.code_reallocs++;
1751 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1753 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1754 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1755 code, TRUE);
1757 if (method->save_lmf)
1759 /* Restore previous lmf */
1760 alpha_ldq(code, alpha_at, alpha_fp,
1761 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1762 alpha_ldq(code, alpha_ra, alpha_fp,
1763 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1764 alpha_stq(code, alpha_at, alpha_ra, 0);
1767 // 5 instructions.
1768 alpha_mov1( code, alpha_fp, alpha_sp );
1770 // Restore saved regs
1771 offset = cfg->arch.reg_save_area_offset;
1773 for (i = 0; i < MONO_MAX_IREGS; ++i)
1774 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1775 (cfg->used_int_regs & (1 << i)) &&
1776 !( ALPHA_ARGS_REGS & (1 << i)) )
1778 alpha_ldq(code, i, alpha_sp, offset);
1779 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1780 i, offset);
1781 offset += 8;
1784 /* restore fp, ra, sp */
1785 offset = cfg->arch.params_stack_size;
1787 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1788 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1789 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1791 /* return */
1792 alpha_ret( code, alpha_ra, 1 );
1794 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1796 g_assert (cfg->code_len < cfg->code_size);
1799 /*========================= End of Function ========================*/
1801 /*------------------------------------------------------------------*/
1802 /* */
1803 /* Name - mono_arch_emit_exceptions */
1804 /* */
1805 /* Function - Emit the blocks to handle exception conditions. */
1806 /* */
1807 /*------------------------------------------------------------------*/
1809 void
1810 mono_arch_emit_exceptions (MonoCompile *cfg)
1812 MonoJumpInfo *patch_info;
1813 int nthrows, i;
1814 unsigned int *code, *got_start;
1815 unsigned long *corlib_exc_adr;
1816 MonoClass *exc_classes [16];
1817 guint8 *exc_throw_start [16], *exc_throw_end [16];
1818 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1819 AlphaGotEntry *got_data;
1821 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1823 /* Compute needed space */
1824 for (patch_info = cfg->patch_info; patch_info;
1825 patch_info = patch_info->next)
1827 if (patch_info->type == MONO_PATCH_INFO_EXC)
1828 code_size += 40;
1829 if (patch_info->type == MONO_PATCH_INFO_R8)
1830 code_size += 8 + 7; /* sizeof (double) + alignment */
1831 if (patch_info->type == MONO_PATCH_INFO_R4)
1832 code_size += 4 + 7; /* sizeof (float) + alignment */
1835 // Reserve space for GOT entries
1836 for (got_data = cfg->arch.got_data; got_data;
1837 got_data = got_data->next)
1839 // Reserve space for 8 byte const (for now)
1840 if (got_data->type != GT_LD_GTADDR)
1841 code_size += 8;
1844 while (cfg->code_len + code_size > (cfg->code_size - 16))
1846 cfg->code_size *= 2;
1847 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1848 mono_jit_stats.code_reallocs++;
1851 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1853 // Set code alignment
1854 if (((unsigned long)code) % 8)
1855 code++;
1857 got_start = code;
1859 /* Add code to store conts and modify patch into to store offset in got */
1860 for (got_data = cfg->arch.got_data; got_data;
1861 got_data = got_data->next)
1863 unsigned long data = got_data->value.data.l;
1864 MonoJumpInfo *got_ref = got_data->got_patch_info;
1866 // Modify loading of GP
1867 if (got_data->type == GT_LD_GTADDR)
1869 short high_off, low_off;
1870 unsigned int *ldgp_code =
1871 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1872 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1874 high_off = got_off / 0x10000;
1875 low_off = got_off % 0x10000;
1876 if (low_off < 0)
1877 high_off++;
1879 // Set offset from current point to GOT array
1880 // modify the following code sequence
1881 // ldah gp, 0(pv) or ldah gp, 0(ra)
1882 // lda gp, 0(gp)
1883 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1884 ldgp_code++;
1885 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1887 continue;
1890 patch_info = got_data->patch_info;
1892 // Check code alignment
1893 if (((unsigned long)code) % 8)
1894 code++;
1896 got_ref->data.offset = ((char *)code - (char *)got_start);
1898 if (patch_info)
1899 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1901 *code = (unsigned int)(data & 0xFFFFFFFF);
1902 code++;
1903 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1904 code++;
1908 corlib_exc_adr = (unsigned long *)code;
1910 /* add code to raise exceptions */
1911 nthrows = 0;
1912 for (patch_info = cfg->patch_info; patch_info;
1913 patch_info = patch_info->next)
1915 switch (patch_info->type)
1917 case MONO_PATCH_INFO_EXC:
1919 MonoClass *exc_class;
1920 unsigned int *buf, *buf2;
1921 guint32 throw_ip;
1923 if (nthrows == 0)
1925 // Add patch info to call mono_arch_throw_corlib_exception
1926 // method to raise corlib exception
1927 // Will be added at the begining of the patch info list
1928 mono_add_patch_info(cfg,
1929 ((char *)code - (char *)cfg->native_code),
1930 MONO_PATCH_INFO_INTERNAL_METHOD,
1931 "mono_arch_throw_corlib_exception");
1933 // Skip longword before starting the code
1934 *code++ = 0;
1935 *code++ = 0;
1938 exc_class = mono_class_from_name (mono_defaults.corlib,
1939 "System", patch_info->data.name);
1941 g_assert (exc_class);
1942 throw_ip = patch_info->ip.i;
1944 //x86_breakpoint (code);
1945 /* Find a throw sequence for the same exception class */
1946 for (i = 0; i < nthrows; ++i)
1947 if (exc_classes [i] == exc_class)
1948 break;
1950 if (i < nthrows)
1952 int br_offset;
1954 // Patch original branch (patch info) to jump here
1955 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1956 patch_info->data.target =
1957 (char *)code - (char *)cfg->native_code;
1959 alpha_lda(code, alpha_a1, alpha_zero,
1960 -((short)((((char *)exc_throw_end[i] -
1961 (char *)cfg->native_code)) - throw_ip) - 4) );
1963 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
1965 alpha_bsr(code, alpha_zero, br_offset);
1967 else
1969 buf = code;
1971 // Save exception token type as first 32bit word for new
1972 // exception handling jump code
1973 *code = exc_class->type_token;
1974 code++;
1976 // Patch original branch (patch info) to jump here
1977 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1978 patch_info->data.target =
1979 (char *)code - (char *)cfg->native_code;
1981 buf2 = code;
1982 alpha_lda(code, alpha_a1, alpha_zero, 0);
1984 if (nthrows < 16)
1986 exc_classes [nthrows] = exc_class;
1987 exc_throw_start [nthrows] = code;
1990 // Load exception token
1991 alpha_ldl(code, alpha_a0, alpha_gp,
1992 ((char *)buf - (char *)got_start /*cfg->native_code*/));
1993 // Load corlib exception raiser code address
1994 alpha_ldq(code, alpha_pv, alpha_gp,
1995 ((char *)corlib_exc_adr -
1996 (char *)got_start /*cfg->native_code*/));
1998 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
1999 //patch_info->data.name = "mono_arch_throw_corlib_exception";
2000 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
2001 //patch_info->type = MONO_PATCH_INFO_NONE;
2002 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
2004 if (cfg->compile_aot)
2006 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
2007 //amd64_call_reg (code, GP_SCRATCH_REG);
2008 } else {
2009 /* The callee is in memory allocated using
2010 the code manager */
2011 alpha_jsr(code, alpha_ra, alpha_pv, 0);
2014 alpha_lda(buf2, alpha_a1, alpha_zero,
2015 -((short)(((char *)code - (char *)cfg->native_code) -
2016 throw_ip)-4) );
2018 if (nthrows < 16)
2020 exc_throw_end [nthrows] = code;
2021 nthrows ++;
2024 break;
2026 default:
2027 /* do nothing */
2028 break;
2032 /* Handle relocations with RIP relative addressing */
2033 for (patch_info = cfg->patch_info; patch_info;
2034 patch_info = patch_info->next)
2036 gboolean remove = FALSE;
2038 switch (patch_info->type)
2040 case MONO_PATCH_INFO_R8:
2042 guint8 *pos;
2044 code = (guint8*)ALIGN_TO (code, 8);
2046 pos = cfg->native_code + patch_info->ip.i;
2048 *(double*)code = *(double*)patch_info->data.target;
2050 // if (use_sse2)
2051 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2052 //else
2053 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2054 code += 8;
2056 remove = TRUE;
2057 break;
2059 case MONO_PATCH_INFO_R4:
2061 guint8 *pos;
2063 code = (guint8*)ALIGN_TO (code, 8);
2065 pos = cfg->native_code + patch_info->ip.i;
2067 *(float*)code = *(float*)patch_info->data.target;
2069 //if (use_sse2)
2070 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2071 //else
2072 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2073 code += 4;
2075 remove = TRUE;
2076 break;
2078 default:
2079 break;
2082 if (remove)
2084 if (patch_info == cfg->patch_info)
2085 cfg->patch_info = patch_info->next;
2086 else
2088 MonoJumpInfo *tmp;
2090 for (tmp = cfg->patch_info; tmp->next != patch_info;
2091 tmp = tmp->next)
2093 tmp->next = patch_info->next;
2098 cfg->code_len = (char *)code - (char *)cfg->native_code;
2100 g_assert (cfg->code_len < cfg->code_size);
2104 /*========================= End of Function ========================*/
2106 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2107 offset = ((char *)code - \
2108 (char *)cfg->native_code); \
2109 if (Tins->inst_true_bb->native_offset) \
2111 long br_offset = (char *)cfg->native_code + \
2112 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2113 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2114 Tins->inst_target_bb->native_offset, \
2115 cfg->native_code + \
2116 Tins->inst_true_bb->native_offset); \
2117 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2119 else \
2121 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2122 offset, Tins->inst_target_bb); \
2123 mono_add_patch_info (cfg, offset, \
2124 MONO_PATCH_INFO_BB, \
2125 Tins->inst_true_bb); \
2126 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2130 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2131 do \
2133 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2134 bb, \
2135 EXC_NAME); \
2136 if (tins == NULL) \
2138 mono_add_patch_info (cfg, \
2139 ((char *)code - \
2140 (char *)cfg->native_code), \
2141 MONO_PATCH_INFO_EXC, EXC_NAME); \
2142 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2144 else \
2146 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2148 } while(0);
2151 /*------------------------------------------------------------------*/
2152 /* */
2153 /* Name - mono_arch_output_basic_block */
2154 /* */
2155 /* Function - Perform the "real" work of emitting instructions */
2156 /* that will do the work of in the basic block. */
2157 /* */
2158 /*------------------------------------------------------------------*/
2160 void
2161 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2163 MonoInst *ins;
2164 MonoCallInst *call;
2165 guint offset;
2166 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2167 MonoInst *last_ins = NULL;
2168 guint last_offset = 0;
2169 int max_len, cpos;
2171 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2173 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2174 bb->block_num, bb, bb->native_offset);
2176 cpos = bb->max_offset;
2178 offset = ((char *)code) - ((char *)cfg->native_code);
2180 mono_debug_open_block (cfg, bb, offset);
2182 MONO_BB_FOR_EACH_INS (bb, ins) {
2183 offset = ((char *)code) - ((char *)cfg->native_code);
2185 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2187 if (offset > (cfg->code_size - max_len - 16))
2189 cfg->code_size *= 2;
2190 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2191 code = (unsigned int *)(cfg->native_code + offset);
2192 mono_jit_stats.code_reallocs++;
2195 mono_debug_record_line_number (cfg, ins, offset);
2197 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2198 mono_inst_name(ins->opcode));
2200 switch (ins->opcode)
2202 case OP_RELAXED_NOP:
2203 break;
2204 case OP_LSHR:
2205 // Shift 64 bit value right
2206 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2207 ins->dreg, ins->sreg1, ins->sreg2);
2208 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2209 break;
2211 case OP_LSHR_UN:
2212 // Shift 64 bit value right
2213 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2214 ins->dreg, ins->sreg1, ins->sreg2);
2215 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2216 break;
2218 case OP_LSHR_IMM:
2219 // Shift 64 bit value right by constant
2220 g_assert(alpha_is_imm(ins->inst_imm));
2221 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2222 ins->dreg, ins->sreg1, ins->inst_imm);
2223 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2224 break;
2226 case OP_ISHL:
2227 // Shift 32 bit value left
2228 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2229 ins->dreg, ins->sreg1, ins->sreg2);
2230 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2231 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2232 break;
2234 case OP_ISHL_IMM:
2235 // Shift 32 bit value left by constant
2236 g_assert(alpha_is_imm(ins->inst_imm));
2237 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2238 ins->dreg, ins->sreg1, ins->inst_imm);
2239 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2240 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2241 break;
2243 case OP_SHL_IMM:
2244 g_assert(alpha_is_imm(ins->inst_imm));
2245 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2246 ins->dreg, ins->sreg1, ins->inst_imm);
2247 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2248 break;
2250 case OP_LSHL_IMM:
2251 g_assert(alpha_is_imm(ins->inst_imm));
2252 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2253 ins->dreg, ins->sreg1, ins->inst_imm);
2254 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2255 break;
2258 case CEE_SHL:
2259 // Shift 32 bit value left
2260 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2261 ins->dreg, ins->sreg1, ins->sreg2);
2262 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2263 break;
2265 case OP_LSHL:
2266 // Shift 64 bit value left
2267 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2268 ins->dreg, ins->sreg1, ins->sreg2);
2269 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2270 break;
2273 case OP_ISHR:
2274 // Shift 32 bit value right
2275 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2276 ins->dreg, ins->sreg1, ins->sreg2);
2277 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2278 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2279 break;
2281 case OP_ISHR_IMM:
2282 // Shift 32 bit value rigth by constant
2283 g_assert(alpha_is_imm(ins->inst_imm));
2284 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2285 ins->dreg, ins->sreg1, ins->inst_imm);
2286 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2287 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2288 break;
2290 case OP_ISHR_UN:
2291 // Shift 32 bit unsigned value right
2292 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2293 ins->dreg, ins->sreg1, ins->sreg2);
2294 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2295 alpha_srl(code, alpha_at /*ins->dreg*/, ins->sreg2, ins->dreg);
2296 break;
2298 case OP_ISHR_UN_IMM:
2299 // Shift 32 bit unassigned value rigth by constant
2300 g_assert(alpha_is_imm(ins->inst_imm));
2301 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2302 ins->dreg, ins->sreg1, ins->inst_imm);
2303 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2304 alpha_srl_(code, alpha_at /*ins->dreg*/, ins->inst_imm, ins->dreg);
2305 break;
2307 case OP_LSHR_UN_IMM:
2308 // Shift 64 bit unassigned value rigth by constant
2309 g_assert(alpha_is_imm(ins->inst_imm));
2310 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2311 ins->dreg, ins->sreg1, ins->inst_imm);
2312 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2313 break;
2315 case CEE_ADD:
2316 // Sum two 64 bits regs
2317 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2318 ins->dreg, ins->sreg1, ins->sreg2);
2319 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2320 break;
2322 case CEE_SUB:
2323 // Subtract two 64 bit regs
2324 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2325 ins->dreg, ins->sreg1, ins->sreg2);
2326 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2327 break;
2329 case OP_ADD_IMM:
2330 // Add imm value to 64 bits int
2331 g_assert(alpha_is_imm(ins->inst_imm));
2332 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2333 ins->dreg, ins->sreg1, ins->inst_imm);
2334 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2335 break;
2337 case OP_IADD:
2338 // Add two 32 bit ints
2339 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2340 ins->dreg, ins->sreg1, ins->sreg2);
2341 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2342 break;
2344 case OP_IADDCC:
2345 // Add two 32 bit ints with overflow detection
2346 // Use AT to hold flag of signed overflow
2347 // Use t12(PV) to hold unsigned overflow
2348 // Use RA to hold intermediate result
2349 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2350 ins->dreg, ins->sreg1, ins->sreg2);
2351 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2352 alpha_ble(code, ins->sreg2, 2);
2354 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2355 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2356 alpha_br(code, alpha_zero, 1);
2358 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2359 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2361 /* res <u sreg1 => unsigned overflow */
2362 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2364 alpha_mov1(code, alpha_ra, ins->dreg);
2365 break;
2367 case OP_ADDCC:
2368 // Add two 64 bit ints with overflow detection
2369 // Use AT to hold flag of signed overflow
2370 // Use t12(PV) to hold unsigned overflow
2371 // Use RA to hold intermediate result
2372 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2373 ins->dreg, ins->sreg1, ins->sreg2);
2374 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2375 alpha_ble(code, ins->sreg2, 2);
2377 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2378 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2379 alpha_br(code, alpha_zero, 1);
2381 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2382 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2384 /* res <u sreg1 => unsigned overflow */
2385 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2387 alpha_mov1(code, alpha_ra, ins->dreg);
2388 break;
2390 case OP_IADD_IMM:
2391 // Add imm value to 32 bits int
2392 g_assert(alpha_is_imm(ins->inst_imm));
2393 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2394 ins->dreg, ins->sreg1, ins->inst_imm);
2395 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2396 break;
2398 case OP_ISUB:
2399 // Substract to 32 bit ints
2400 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2401 ins->dreg, ins->sreg1, ins->sreg2);
2402 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2403 break;
2405 case OP_ISUB_IMM:
2406 // Sub imm value from 32 bits int
2407 g_assert(alpha_is_imm(ins->inst_imm));
2408 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2409 ins->dreg, ins->sreg1, ins->inst_imm);
2410 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2411 break;
2413 case OP_ISUBCC:
2414 // Sub to 32 bit ints with overflow detection
2415 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2416 ins->dreg, ins->sreg1, ins->sreg2);
2417 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2418 alpha_ble(code, ins->sreg2, 2);
2420 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2421 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2422 alpha_br(code, alpha_zero, 1);
2424 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2425 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2427 /* sreg1 <u sreg2 => unsigned overflow */
2428 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2430 alpha_mov1(code, alpha_ra, ins->dreg);
2431 break;
2433 case OP_SUBCC:
2434 // Sub to 64 bit ints with overflow detection
2435 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2436 ins->dreg, ins->sreg1, ins->sreg2);
2438 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2439 alpha_ble(code, ins->sreg2, 2);
2441 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2442 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2443 alpha_br(code, alpha_zero, 1);
2445 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2446 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2448 /* sreg1 <u sreg2 => unsigned overflow */
2449 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2451 alpha_mov1(code, alpha_ra, ins->dreg);
2452 break;
2454 case OP_IAND:
2455 case CEE_AND:
2456 // AND to 32 bit ints
2457 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2458 ins->dreg, ins->sreg1, ins->sreg2);
2459 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2460 break;
2462 case OP_IAND_IMM:
2463 case OP_AND_IMM:
2464 // AND imm value with 32 bit int
2465 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2466 ins->dreg, ins->sreg1, ins->inst_imm);
2468 g_assert(alpha_is_imm(ins->inst_imm));
2469 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2471 break;
2473 case OP_IOR:
2474 case CEE_OR:
2475 // OR two 32/64 bit ints
2476 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2477 ins->dreg, ins->sreg1, ins->sreg2);
2478 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2479 break;
2481 case OP_IOR_IMM:
2482 // OR imm value with 32 bit int
2483 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2484 ins->dreg, ins->sreg1, ins->inst_imm);
2486 g_assert(alpha_is_imm(ins->inst_imm));
2487 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2489 break;
2491 case OP_IXOR:
2492 case CEE_XOR:
2493 // XOR two 32/64 bit ints
2494 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2495 ins->dreg, ins->sreg1, ins->sreg2);
2496 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2497 break;
2499 case OP_IXOR_IMM:
2500 // XOR imm value with 32 bit int
2501 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2502 ins->dreg, ins->sreg1, ins->inst_imm);
2504 g_assert(alpha_is_imm(ins->inst_imm));
2505 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2507 break;
2509 case OP_INEG:
2510 // NEG 32 bit reg
2511 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2512 ins->dreg, ins->sreg1);
2513 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2514 break;
2516 case CEE_NEG:
2517 // NEG 64 bit reg
2518 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2519 ins->dreg, ins->sreg1);
2520 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2521 break;
2523 case OP_INOT:
2524 case CEE_NOT:
2525 // NOT 32/64 bit reg
2526 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2527 ins->dreg, ins->sreg1);
2528 alpha_not(code, ins->sreg1, ins->dreg);
2529 break;
2532 case OP_IDIV:
2533 case OP_IREM:
2534 case OP_IMUL:
2535 case OP_IMUL_OVF:
2536 case OP_IMUL_OVF_UN:
2537 case OP_IDIV_UN:
2538 case OP_IREM_UN:
2539 CFG_DEBUG(4) g_print("ALPHA_TODO: [idiv/irem/imul/imul_ovf/imul_ovf_un/idiv_un/irem_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2540 ins->dreg, ins->sreg1, ins->sreg2);
2541 break;
2543 case CEE_MUL:
2544 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2545 ins->dreg, ins->sreg1, ins->sreg2);
2546 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2547 break;
2549 case OP_IMUL_IMM:
2550 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2551 ins->dreg, ins->sreg1, ins->inst_imm);
2552 break;
2554 case OP_CHECK_THIS:
2555 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2556 ins->sreg1);
2557 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2558 break;
2560 case OP_SEXT_I1:
2561 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2562 ins->dreg, ins->sreg1);
2563 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2564 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2565 break;
2567 case OP_SEXT_I2:
2568 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2569 ins->dreg, ins->sreg1);
2570 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2571 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2572 break;
2574 case OP_SEXT_I4:
2575 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2576 ins->dreg, ins->sreg1);
2577 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2578 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2579 break;
2581 case OP_ICONST:
2582 // Actually ICONST is 32 bits long
2583 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2584 ins->dreg, ins->inst_c0);
2586 // if const = 0
2587 if (ins->inst_c0 == 0)
2589 alpha_clr(code, ins->dreg);
2590 break;
2593 // if -32768 < const <= 32767
2594 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2596 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2597 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2598 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2600 else
2602 int lo = (char *)code - (char *)cfg->native_code;
2603 AlphaGotData ge_data;
2605 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2606 ge_data.data.l = ins->inst_c0;
2608 add_got_entry(cfg, GT_LONG, ge_data,
2609 lo, MONO_PATCH_INFO_NONE, 0);
2610 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2611 // ins->inst_c0);
2612 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2613 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2616 break;
2617 case OP_I8CONST:
2619 int lo;
2621 // To load 64 bit values we will have to use ldah/lda combination
2622 // and temporary register. As temporary register use r28
2623 // Divide 64 bit value in two parts and load upper 32 bits into
2624 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2625 // dreg from temp reg
2626 // the 32 bit value could be loaded with ldah/lda
2627 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2628 ins->dreg, ins->inst_c0);
2630 // if const = 0
2631 if (ins->inst_c0 == 0)
2633 alpha_clr(code, ins->dreg);
2634 break;
2637 // if -32768 < const <= 32767
2638 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2639 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2640 else
2642 AlphaGotData ge_data;
2644 lo = (char *)code - (char *)cfg->native_code;
2646 ge_data.data.l = ins->inst_c0;
2648 add_got_entry(cfg, GT_LONG, ge_data,
2649 lo, MONO_PATCH_INFO_NONE, 0);
2650 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2652 break;
2655 case OP_R8CONST:
2657 double d = *(double *)ins->inst_p0;
2658 AlphaGotData ge_data;
2660 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2661 ins->dreg, d);
2663 ge_data.data.d = d;
2664 add_got_entry(cfg, GT_DOUBLE, ge_data,
2665 (char *)code - (char *)cfg->native_code,
2666 MONO_PATCH_INFO_NONE, 0);
2667 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2669 break;
2672 case OP_R4CONST:
2674 float d = *(float *)ins->inst_p0;
2675 AlphaGotData ge_data;
2677 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2678 ins->dreg, d);
2680 ge_data.data.f = d;
2681 add_got_entry(cfg, GT_FLOAT, ge_data,
2682 (char *)code - (char *)cfg->native_code,
2683 MONO_PATCH_INFO_NONE, 0);
2684 alpha_lds(code, ins->dreg, alpha_gp, 0);
2686 break;
2689 case OP_LOADU4_MEMBASE:
2690 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2691 ins->dreg, ins->inst_basereg, ins->inst_offset);
2693 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2694 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2695 break;
2697 case OP_LOADU1_MEMBASE:
2698 // Load unassigned byte from REGOFFSET
2699 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2700 ins->dreg, ins->inst_basereg, ins->inst_offset);
2701 if (bwx_supported)
2702 alpha_ldbu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2703 else
2705 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2706 ins->inst_offset);
2707 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2708 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2710 break;
2712 case OP_LOADU2_MEMBASE:
2713 // Load unassigned word from REGOFFSET
2714 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2715 ins->dreg, ins->inst_basereg, ins->inst_offset);
2717 if (bwx_supported)
2718 alpha_ldwu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2719 else
2721 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2722 ins->inst_offset);
2723 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2724 (ins->inst_offset+1));
2725 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2726 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2727 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2728 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2730 break;
2732 case OP_LOAD_MEMBASE:
2733 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2734 ins->dreg, ins->inst_basereg, ins->inst_offset);
2735 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2736 break;
2738 case OP_LOADI8_MEMBASE:
2739 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2740 ins->dreg, ins->inst_basereg, ins->inst_offset);
2741 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2742 break;
2744 case OP_LOADI4_MEMBASE:
2745 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2746 ins->dreg, ins->inst_basereg, ins->inst_offset);
2747 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2748 break;
2750 case OP_LOADI1_MEMBASE:
2751 // Load sign-extended byte from REGOFFSET
2752 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2753 ins->dreg, ins->inst_basereg, ins->inst_offset);
2754 if (bwx_supported)
2756 alpha_ldbu(code, ins->dreg, ins->inst_basereg,
2757 ins->inst_offset);
2758 alpha_sextb(code, ins->dreg, ins->dreg);
2760 else
2762 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2763 ins->inst_offset);
2764 alpha_lda(code, alpha_at, ins->inst_basereg,
2765 (ins->inst_offset+1));
2766 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2767 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2769 break;
2771 case OP_LOADI2_MEMBASE:
2772 // Load sign-extended word from REGOFFSET
2773 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2774 ins->dreg, ins->inst_basereg, ins->inst_offset);
2775 if (bwx_supported)
2777 alpha_ldwu(code, ins->dreg, ins->inst_basereg,
2778 ins->inst_offset);
2779 alpha_sextw(code, ins->dreg, ins->dreg);
2781 else
2783 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2784 ins->inst_offset);
2785 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2786 (ins->inst_offset+1));
2787 alpha_lda(code, alpha_at, ins->inst_basereg,
2788 (ins->inst_offset+2));
2789 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2790 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2791 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2792 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2794 break;
2796 case OP_STOREI1_MEMBASE_IMM:
2797 // Store signed byte at REGOFFSET
2798 // Valid only for storing 0
2799 // storei1_membase_reg will do the rest
2801 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2802 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2803 g_assert(ins->inst_imm == 0);
2805 if (bwx_supported)
2806 alpha_stb(code, alpha_zero, ins->inst_destbasereg,
2807 ins->inst_offset);
2808 else
2809 g_assert_not_reached();
2811 break;
2813 case OP_STOREI1_MEMBASE_REG:
2814 // Store byte at REGOFFSET
2815 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2816 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2817 if (bwx_supported)
2819 alpha_stb(code, ins->sreg1, ins->inst_destbasereg,
2820 ins->inst_offset);
2822 else
2824 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2825 ins->inst_offset);
2826 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2827 ins->inst_offset);
2828 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2829 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2830 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2831 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2832 ins->inst_offset);
2834 break;
2836 case OP_STOREI2_MEMBASE_IMM:
2837 // Store signed word at REGOFFSET
2838 // Now work only for storing 0
2839 // For now storei2_membase_reg will do the work
2841 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2842 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2844 g_assert(ins->inst_imm == 0);
2846 if (bwx_supported)
2847 alpha_stw(code, alpha_zero, ins->inst_destbasereg,
2848 ins->inst_offset);
2849 else
2850 g_assert_not_reached();
2852 break;
2854 case OP_STOREI2_MEMBASE_REG:
2855 // Store signed word from reg to REGOFFSET
2856 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2857 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2859 if (bwx_supported)
2861 alpha_stw(code, ins->sreg1, ins->inst_destbasereg,
2862 ins->inst_offset);
2864 else
2866 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2867 ins->inst_offset);
2868 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2869 (ins->inst_offset+1));
2870 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2871 ins->inst_offset);
2872 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2873 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2874 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2875 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2876 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2877 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2878 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2879 (ins->inst_offset+1));
2880 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2881 ins->inst_offset);
2884 break;
2886 case OP_STOREI4_MEMBASE_IMM:
2887 // We will get here only with ins->inst_imm = 0
2888 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2889 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2891 g_assert(ins->inst_imm == 0);
2893 alpha_stl(code, alpha_zero,
2894 ins->inst_destbasereg, ins->inst_offset);
2895 break;
2897 case OP_STORER4_MEMBASE_REG:
2898 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2899 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2900 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2901 break;
2903 case OP_STORER8_MEMBASE_REG:
2904 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2905 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2906 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2907 ins->inst_offset);
2908 break;
2910 case OP_LOADR4_MEMBASE:
2911 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2912 ins->dreg, ins->inst_basereg, ins->inst_offset);
2913 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2914 break;
2916 case OP_LOADR8_MEMBASE:
2917 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2918 ins->dreg, ins->inst_basereg, ins->inst_offset);
2919 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2920 break;
2922 case OP_FMOVE:
2923 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2924 ins->sreg1, ins->dreg);
2925 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
2926 break;
2928 case OP_FADD:
2929 // Later check different rounding and exc modes
2930 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2931 ins->sreg1, ins->sreg2, ins->dreg);
2932 alpha_addt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2933 alpha_trapb(code);
2934 break;
2936 case OP_FSUB:
2937 // Later check different rounding and exc modes
2938 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2939 ins->sreg1, ins->sreg2, ins->dreg);
2940 alpha_subt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2941 alpha_trapb(code);
2942 break;
2944 case OP_FMUL:
2945 // Later check different rounding and exc modes
2946 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2947 ins->sreg1, ins->sreg2, ins->dreg);
2948 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
2949 break;
2951 case OP_FNEG:
2952 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2953 ins->sreg1, ins->dreg);
2954 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
2955 break;
2957 case OP_ALPHA_TRAPB:
2958 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2959 alpha_trapb(code);
2960 break;
2962 case OP_ABS:
2963 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2964 ins->sreg1, ins->dreg);
2965 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
2966 break;
2968 case OP_STORE_MEMBASE_IMM:
2969 case OP_STOREI8_MEMBASE_IMM:
2970 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2971 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2972 g_assert(ins->inst_imm == 0);
2974 alpha_stq(code, alpha_zero,
2975 ins->inst_destbasereg, ins->inst_offset);
2977 break;
2978 case OP_STORE_MEMBASE_REG:
2979 case OP_STOREI8_MEMBASE_REG:
2980 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2981 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2982 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2983 break;
2985 case OP_STOREI4_MEMBASE_REG:
2986 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2987 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2988 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2989 break;
2991 case OP_ICOMPARE_IMM:
2992 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2993 ins->sreg1, ins->dreg, ins->inst_imm);
2995 g_assert_not_reached();
2997 break;
2999 case OP_COMPARE_IMM:
3000 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3001 ins->sreg1, ins->dreg, ins->inst_imm);
3003 g_assert_not_reached();
3005 break;
3007 case OP_COMPARE: // compare two 32 bit regs
3008 case OP_LCOMPARE: // compare two 64 bit regs
3009 case OP_FCOMPARE: // compare two floats
3010 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3011 ins->sreg1, ins->sreg2, ins->dreg);
3013 g_assert_not_reached();
3015 break;
3017 case OP_ALPHA_CMPT_UN:
3018 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3019 ins->sreg1, ins->sreg2, ins->dreg);
3020 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3021 break;
3023 case OP_ALPHA_CMPT_UN_SU:
3024 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3025 ins->sreg1, ins->sreg2, ins->dreg);
3026 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3027 break;
3029 case OP_ALPHA_CMPT_EQ:
3030 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3031 ins->sreg1, ins->sreg2, ins->dreg);
3032 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
3033 break;
3035 case OP_ALPHA_CMPT_EQ_SU:
3036 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3037 ins->sreg1, ins->sreg2, ins->dreg);
3038 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
3039 break;
3042 case OP_ALPHA_CMPT_LT:
3043 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3044 ins->sreg1, ins->sreg2, ins->dreg);
3045 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3046 break;
3048 case OP_ALPHA_CMPT_LT_SU:
3049 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3050 ins->sreg1, ins->sreg2, ins->dreg);
3051 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3052 break;
3054 case OP_ALPHA_CMPT_LE:
3055 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3056 ins->sreg1, ins->sreg2, ins->dreg);
3057 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3058 break;
3060 case OP_ALPHA_CMPT_LE_SU:
3061 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3062 ins->sreg1, ins->sreg2, ins->dreg);
3063 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3064 break;
3066 case OP_ALPHA_CMP_EQ:
3067 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3068 ins->sreg1, ins->sreg2, ins->dreg);
3069 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3070 break;
3072 case OP_ALPHA_CMP_IMM_EQ:
3073 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3074 ins->sreg1, ins->inst_imm, ins->dreg);
3075 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3076 break;
3078 case OP_ALPHA_CMP_IMM_ULE:
3079 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%d\n",
3080 ins->sreg1, ins->inst_imm, ins->dreg);
3081 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3082 break;
3084 case OP_ALPHA_CMP_ULT:
3085 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3086 ins->sreg1, ins->sreg2, ins->dreg);
3087 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3088 break;
3090 case OP_ALPHA_CMP_IMM_ULT:
3091 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3092 ins->sreg1, ins->inst_imm, ins->dreg);
3093 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3094 break;
3096 case OP_ALPHA_CMP_LE:
3097 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3098 ins->sreg1, ins->sreg2, ins->dreg);
3099 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3100 break;
3102 case OP_ALPHA_CMP_ULE:
3103 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3104 ins->sreg1, ins->sreg2, ins->dreg);
3105 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3106 break;
3109 case OP_ALPHA_CMP_IMM_LE:
3110 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%d\n",
3111 ins->sreg1, ins->inst_imm, ins->dreg);
3112 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3113 break;
3115 case OP_ALPHA_CMP_LT:
3116 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3117 ins->sreg1, ins->sreg2, ins->dreg);
3118 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3119 break;
3121 case OP_ALPHA_CMP_IMM_LT:
3122 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3123 ins->sreg1, ins->inst_imm, ins->dreg);
3124 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3125 break;
3127 case OP_COND_EXC_GT:
3128 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3129 (char *)ins->inst_p1);
3131 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3132 break;
3134 case OP_COND_EXC_GT_UN:
3135 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3136 (char *)ins->inst_p1);
3138 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3139 break;
3141 case OP_COND_EXC_LT:
3142 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3143 (char *)ins->inst_p1);
3145 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3146 break;
3148 case OP_COND_EXC_LT_UN:
3149 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3150 (char *)ins->inst_p1);
3152 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3153 break;
3156 case OP_COND_EXC_LE_UN:
3157 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3158 (char *)ins->inst_p1);
3159 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3160 break;
3162 case OP_COND_EXC_NE_UN:
3163 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3164 (char *)ins->inst_p1);
3165 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3166 break;
3168 case OP_COND_EXC_EQ:
3169 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3170 (char *)ins->inst_p1);
3171 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3172 break;
3174 case OP_COND_EXC_IOV:
3175 case OP_COND_EXC_OV:
3176 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3177 break;
3179 case OP_COND_EXC_IC:
3180 case OP_COND_EXC_C:
3181 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3182 break;
3184 case CEE_CONV_OVF_U4:
3185 // Convert unsigned 32 bit value to 64 bit reg
3186 // Check overflow
3187 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3188 ins->sreg1, ins->dreg);
3189 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3190 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3191 alpha_mov1(code, ins->sreg1, ins->dreg);
3192 break;
3194 case CEE_CONV_OVF_I4_UN:
3195 // Convert unsigned 32 bit value to 64 bit reg
3196 // Check overflow
3197 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3198 ins->sreg1, ins->dreg);
3199 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3201 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3202 alpha_mov1(code, ins->sreg1, ins->dreg);
3203 break;
3205 case CEE_CONV_I1:
3206 // Move I1 (byte) to dreg(64 bits) and sign extend it
3207 // Read about sextb
3208 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3209 ins->sreg1, ins->dreg);
3210 if (bwx_supported)
3211 alpha_sextb(code, ins->sreg1, ins->dreg);
3212 else
3214 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3215 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3216 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3218 break;
3220 case CEE_CONV_I2:
3221 // Move I2 (word) to dreg(64 bits) and sign extend it
3222 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3223 ins->sreg1, ins->dreg);
3224 if (bwx_supported)
3225 alpha_sextw(code, ins->sreg1, ins->dreg);
3226 else
3228 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3229 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3230 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3232 break;
3234 case CEE_CONV_I4:
3235 // Move I4 (long) to dreg(64 bits) and sign extend it
3236 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3237 ins->sreg1, ins->dreg);
3238 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3239 break;
3241 case CEE_CONV_I8:
3242 case CEE_CONV_I:
3243 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3244 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3245 ins->sreg1, ins->dreg);
3246 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3247 alpha_mov1(code, ins->sreg1, ins->dreg);
3248 break;
3250 case CEE_CONV_U1:
3251 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3252 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3253 ins->sreg1, ins->dreg);
3254 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3255 break;
3257 case CEE_CONV_U2:
3258 // Move U2 (word) to dreg(64 bits) don't sign extend it
3259 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3260 ins->sreg1, ins->dreg);
3261 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3262 break;
3264 case CEE_CONV_U4:
3265 // Move U4 (long) to dreg(64 bits) don't sign extend it
3266 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3267 ins->sreg1, ins->dreg);
3268 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3269 break;
3271 case CEE_CONV_U8:
3272 case CEE_CONV_U:
3273 // Move U4 (long) to dreg(64 bits) don't sign extend it
3274 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3275 ins->sreg1, ins->dreg);
3276 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3277 break;
3279 case OP_FCONV_TO_I4:
3280 case OP_FCONV_TO_I8:
3281 // Move float to 32 bit reg
3282 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3283 ins->sreg1, ins->dreg);
3284 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3285 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3286 alpha_lda(code, alpha_sp, alpha_sp, -8);
3287 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3288 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3289 alpha_lda(code, alpha_sp, alpha_sp, 8);
3290 break;
3292 case OP_FCONV_TO_I2:
3293 // Move float to 16 bit reg
3294 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3295 ins->sreg1, ins->dreg);
3296 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3297 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3298 alpha_lda(code, alpha_sp, alpha_sp, -8);
3299 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3300 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3301 alpha_lda(code, alpha_sp, alpha_sp, 8);
3302 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3303 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3304 break;
3306 case OP_FCONV_TO_U2:
3307 // Move float to 16 bit reg as unsigned
3308 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3309 ins->sreg1, ins->dreg);
3310 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3311 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3312 alpha_lda(code, alpha_sp, alpha_sp, -8);
3313 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3314 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3315 alpha_lda(code, alpha_sp, alpha_sp, 8);
3316 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3317 break;
3319 case OP_FCONV_TO_U1:
3320 // Move float to 8 bit reg as unsigned
3321 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3322 ins->sreg1, ins->dreg);
3323 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3324 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3325 alpha_lda(code, alpha_sp, alpha_sp, -8);
3326 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3327 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3328 alpha_lda(code, alpha_sp, alpha_sp, 8);
3329 alpha_and_(code, ins->dreg, 0xff, ins->dreg);
3330 break;
3332 case OP_FCONV_TO_I1:
3333 // Move float to 8 bit reg
3334 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3335 ins->sreg1, ins->dreg);
3336 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3337 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3338 alpha_lda(code, alpha_sp, alpha_sp, -8);
3339 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3340 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3341 alpha_lda(code, alpha_sp, alpha_sp, 8);
3342 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3343 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3344 break;
3346 case CEE_CONV_R4:
3347 case OP_LCONV_TO_R4:
3348 // Move 32/64 bit int into float
3349 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3350 ins->sreg1, ins->dreg);
3351 alpha_lda(code, alpha_sp, alpha_sp, -8);
3352 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3353 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3354 alpha_lda(code, alpha_sp, alpha_sp, 8);
3355 alpha_cvtqs(code, ins->dreg, ins->dreg);
3356 alpha_trapb(code);
3357 break;
3359 case CEE_CONV_R8:
3360 case OP_LCONV_TO_R8:
3361 // Move 32/64 bit int into double
3362 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3363 ins->sreg1, ins->dreg);
3364 alpha_lda(code, alpha_sp, alpha_sp, -8);
3365 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3366 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3367 alpha_lda(code, alpha_sp, alpha_sp, 8);
3368 alpha_cvtqt(code, ins->dreg, ins->dreg);
3369 alpha_trapb(code);
3370 break;
3372 case OP_FCONV_TO_R4:
3373 // Convert 64 bit float to 32 bit float (T -> S)
3374 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3375 ins->sreg1, ins->dreg);
3376 alpha_cvtts_su(code, ins->sreg1, ins->dreg);
3377 alpha_trapb(code);
3378 break;
3380 case OP_LOCALLOC:
3381 // Allocate sreg1 bytes on stack, round bytes by 8,
3382 // modify SP, set dreg to end of current stack frame
3383 // top of stack is used for call params
3384 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3385 ins->sreg1, ins->dreg);
3387 alpha_addq_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3388 alpha_bic_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3389 if (ins->flags & MONO_INST_INIT)
3390 alpha_mov1(code, ins->sreg1, ins->sreg2);
3392 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3393 if (cfg->arch.params_stack_size > 0)
3395 alpha_lda(code, ins->dreg, alpha_zero,
3396 (cfg->arch.params_stack_size));
3397 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3399 else
3400 alpha_mov1(code, alpha_sp, ins->dreg);
3402 if (ins->flags & MONO_INST_INIT)
3404 // TODO: Optimize it later
3405 alpha_lda(code, ins->sreg2, ins->sreg2,
3406 -(MONO_ARCH_LOCALLOC_ALIGNMENT));
3407 alpha_blt(code, ins->sreg2, 3);
3408 alpha_addq(code, ins->sreg2, ins->dreg, alpha_at);
3409 alpha_stq(code, alpha_zero, alpha_at, 0);
3410 alpha_br(code, alpha_zero, -5);
3413 break;
3415 case OP_MOVE:
3416 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3417 ins->sreg1, ins->dreg);
3418 alpha_mov1(code, ins->sreg1, ins->dreg);
3419 break;
3421 case OP_CGT_UN:
3422 case OP_ICGT_UN:
3423 case OP_ICGT:
3424 case OP_CGT:
3425 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3426 ins->dreg);
3427 alpha_clr(code, ins->dreg);
3428 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3429 break;
3431 case OP_ICLT:
3432 case OP_ICLT_UN:
3433 case OP_CLT:
3434 case OP_CLT_UN:
3435 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3436 ins->dreg);
3437 alpha_clr(code, ins->dreg);
3438 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3439 break;
3441 case OP_ICEQ:
3442 case OP_CEQ:
3443 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3444 ins->dreg);
3445 alpha_clr(code, ins->dreg);
3446 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3447 break;
3449 case OP_FCEQ:
3450 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3451 ins->dreg);
3452 alpha_clr(code, ins->dreg);
3453 alpha_fbeq(code, alpha_at, 1);
3454 alpha_lda(code, ins->dreg, alpha_zero, 1);
3457 alpha_cvttq_c(code, alpha_at, alpha_at);
3458 alpha_lda(code, alpha_sp, alpha_sp, -8);
3459 alpha_stt(code, alpha_at, alpha_sp, 0);
3460 alpha_ldq(code, alpha_at, alpha_sp, 0);
3461 alpha_lda(code, alpha_sp, alpha_sp, 8);
3463 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3465 break;
3467 case OP_FCGT:
3468 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3469 ins->dreg);
3470 alpha_clr(code, ins->dreg);
3471 alpha_fbne(code, alpha_at, 1);
3472 alpha_lda(code, ins->dreg, alpha_zero, 1);
3475 alpha_cvttq_c(code, alpha_at, alpha_at);
3476 alpha_lda(code, alpha_sp, alpha_sp, -8);
3477 alpha_stt(code, alpha_at, alpha_sp, 0);
3478 alpha_ldq(code, alpha_at, alpha_sp, 0);
3479 alpha_lda(code, alpha_sp, alpha_sp, 8);
3481 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3483 break;
3486 case OP_FCLT:
3487 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3488 ins->dreg);
3489 alpha_clr(code, ins->dreg);
3490 alpha_fbeq(code, alpha_at, 1);
3491 alpha_lda(code, ins->dreg, alpha_zero, 1);
3492 break;
3494 case OP_FCLT_UN:
3495 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3496 ins->dreg);
3498 alpha_clr(code, ins->dreg);
3499 alpha_fbne(code, (alpha_at+1), 1);
3500 alpha_fbeq(code, alpha_at, 1);
3501 alpha_lda(code, ins->dreg, alpha_zero, 1);
3502 break;
3505 case OP_IBNE_UN:
3506 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3507 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3508 break;
3510 case OP_FBNE_UN:
3511 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3512 alpha_fbeq(code, (alpha_at+1), 1);
3513 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3514 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3515 break;
3517 case OP_FBGE_UN:
3518 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3519 alpha_fbeq(code, (alpha_at+1), 1);
3520 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3521 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3522 break;
3524 case OP_FBGE:
3525 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge] [");
3526 alpha_fbne(code, (alpha_at+1), 1);
3527 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3528 break;
3530 case OP_FBLE_UN:
3531 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3532 alpha_fbeq(code, (alpha_at+1), 1);
3533 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3534 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3535 break;
3537 case OP_FBLE:
3538 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble] [");
3539 alpha_fbne(code, (alpha_at+1), 1);
3540 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3541 break;
3543 case OP_FBLT_UN:
3544 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3545 alpha_fbeq(code, (alpha_at+1), 1);
3546 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3547 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3548 break;
3550 case OP_FBLT:
3551 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt] [");
3552 alpha_fbne(code, (alpha_at+1), 1);
3553 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3554 break;
3556 case OP_FBGT_UN:
3557 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3558 alpha_fbeq(code, (alpha_at+1), 1);
3559 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3560 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3561 break;
3563 case OP_FBGT:
3564 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt] [");
3565 alpha_fbne(code, (alpha_at+1), 1);
3566 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3567 break;
3569 case OP_IBEQ:
3570 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3571 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3572 break;
3574 case OP_FBEQ:
3575 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3576 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3577 break;
3579 case CEE_BEQ:
3580 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3581 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3582 break;
3584 case CEE_BNE_UN:
3585 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3586 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3587 break;
3589 case OP_LABEL:
3590 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3591 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3592 break;
3594 case OP_BR:
3595 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br] target: %p, next: %p, curr: %p, last: %p [",
3596 ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3598 if (ins->inst_target_bb->native_offset)
3600 // Somehow native offset is offset from
3601 // start of the code. So convert it to
3602 // offset branch
3603 long br_offset = (char *)cfg->native_code +
3604 ins->inst_target_bb->native_offset - 4 - (char *)code;
3606 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3607 ins->inst_target_bb->native_offset,
3608 cfg->native_code +
3609 ins->inst_target_bb->native_offset);
3610 alpha_br(code, alpha_zero, br_offset/4);
3612 else
3614 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3615 offset, ins->inst_target_bb);
3617 mono_add_patch_info (cfg, offset,
3618 MONO_PATCH_INFO_BB,
3619 ins->inst_target_bb);
3620 alpha_br(code, alpha_zero, 0);
3623 break;
3625 case OP_BR_REG:
3626 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3627 ins->sreg1);
3629 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3630 break;
3632 case OP_FCALL:
3633 case OP_LCALL:
3634 case OP_VCALL:
3635 case OP_VOIDCALL:
3636 case OP_CALL:
3637 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3638 call = (MonoCallInst*)ins;
3640 if (ins->flags & MONO_INST_HAS_METHOD)
3642 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3643 code = emit_call (cfg, code,
3644 MONO_PATCH_INFO_METHOD, call->method);
3646 else
3648 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3649 code = emit_call (cfg, code,
3650 MONO_PATCH_INFO_ABS, call->fptr);
3653 //code = emit_move_return_value (cfg, ins, code);
3655 break;
3657 case OP_FCALL_REG:
3658 case OP_LCALL_REG:
3659 case OP_VCALL_REG:
3660 case OP_VOIDCALL_REG:
3661 case OP_CALL_REG:
3663 int offset;
3665 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3666 call = (MonoCallInst*)ins;
3668 alpha_mov1(code, ins->sreg1, alpha_pv);
3670 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3672 offset = (char *)code - (char *)cfg->native_code;
3674 // Restore GP
3675 ALPHA_LOAD_GP(offset)
3676 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3677 alpha_lda(code, alpha_gp, alpha_gp, 0);
3679 break;
3681 case OP_FCALL_MEMBASE:
3682 case OP_CALL_MEMBASE:
3683 case OP_LCALL_MEMBASE:
3684 case OP_VCALL_MEMBASE:
3686 int offset;
3688 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3689 ins->inst_basereg, ins->inst_offset);
3690 call = (MonoCallInst*)ins;
3692 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3693 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3695 offset = (char *)code - (char *)cfg->native_code;
3697 // Restore GP
3698 ALPHA_LOAD_GP(offset)
3699 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3700 alpha_lda(code, alpha_gp, alpha_gp, 0);
3702 break;
3704 case OP_VOIDCALL_MEMBASE:
3706 int offset;
3708 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3709 ins->inst_basereg, ins->inst_offset);
3710 call = (MonoCallInst*)ins;
3712 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3713 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3715 offset = (char *)code - (char *)cfg->native_code;
3717 // Restore GP
3718 ALPHA_LOAD_GP(offset)
3719 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3720 alpha_lda(code, alpha_gp, alpha_gp, 0);
3722 break;
3724 case OP_START_HANDLER:
3726 // TODO - find out when we called by call_handler or resume_context
3727 // of by call_filter. There should be difference. For now just
3728 // handle - call_handler
3730 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3731 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3733 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3734 ins->inst_left->inst_offset);
3736 break;
3738 case OP_ENDFINALLY:
3740 // Keep in sync with start_handler
3741 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3742 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3744 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3745 ins->inst_left->inst_offset);
3747 alpha_ret(code, alpha_ra, 1);
3750 break;
3751 case OP_ENDFILTER:
3753 // Keep in sync with start_handler
3754 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3755 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3757 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3758 ins->inst_left->inst_offset);
3760 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3761 alpha_mov1(code, ins->sreg1, alpha_r0);
3763 alpha_ret(code, alpha_ra, 1);
3765 break;
3767 case OP_CALL_HANDLER:
3769 int offset;
3771 offset = (char *)code - (char *)cfg->native_code;
3773 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3774 offset, ins->inst_target_bb);
3776 mono_add_patch_info (cfg, offset,
3777 MONO_PATCH_INFO_BB,
3778 ins->inst_target_bb);
3779 alpha_bsr(code, alpha_ra, 0);
3781 break;
3783 case OP_THROW:
3784 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3785 ins->sreg1);
3786 alpha_mov1(code, ins->sreg1, alpha_a0);
3787 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3788 (gpointer)"mono_arch_throw_exception");
3789 break;
3791 case OP_RETHROW:
3792 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3793 ins->sreg1);
3794 alpha_mov1(code, ins->sreg1, alpha_a0);
3795 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3796 (gpointer)"mono_arch_rethrow_exception");
3797 break;
3799 case OP_JMP:
3802 * Note: this 'frame destruction' logic is useful for tail calls,
3803 too. Keep in sync with the code in emit_epilog.
3805 int offset;
3806 AlphaGotData ge_data;
3808 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3810 /* FIXME: no tracing support... */
3811 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3812 code = mono_arch_instrument_epilog (cfg,
3813 mono_profiler_method_leave, code, FALSE);
3814 g_assert (!cfg->method->save_lmf);
3816 alpha_mov1( code, alpha_fp, alpha_sp );
3818 code = emit_load_volatile_arguments (cfg, code);
3820 offset = cfg->arch.params_stack_size;
3822 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3823 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3824 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3826 ge_data.data.p = ins->inst_p0;
3827 add_got_entry(cfg, GT_PTR, ge_data,
3828 (char *)code - (char *)cfg->native_code,
3829 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3830 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3832 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3834 break;
3836 case OP_AOTCONST:
3837 mono_add_patch_info (cfg, offset,
3838 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3839 break;
3841 case OP_MEMORY_BARRIER:
3842 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3843 alpha_mb(code);
3844 break;
3846 case OP_CKFINITE:
3847 // Float register contains a value which we need to check
3849 double ni = -1.0 / 0.0;
3850 double pi = 1.0 / 0.0;
3851 AlphaGotData ge_data;
3853 CFG_DEBUG(4) g_print("ALPHA_TODO: [chfinite] sreg1=%d\n", ins->sreg1);
3854 alpha_cmptun_su(code, ins->sreg1, ins->sreg1, alpha_at);
3855 alpha_trapb(code);
3856 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3858 // Negative infinity
3859 ge_data.data.d = ni;
3860 add_got_entry(cfg, GT_DOUBLE, ge_data,
3861 (char *)code - (char *)cfg->native_code,
3862 MONO_PATCH_INFO_NONE, 0);
3863 alpha_ldt(code, alpha_at, alpha_gp, 0);
3865 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3866 alpha_trapb(code);
3868 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3870 // Positive infinity
3871 ge_data.data.d = pi;
3872 add_got_entry(cfg, GT_DOUBLE, ge_data,
3873 (char *)code - (char *)cfg->native_code,
3874 MONO_PATCH_INFO_NONE, 0);
3875 alpha_ldt(code, alpha_at, alpha_gp, 0);
3877 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3878 alpha_trapb(code);
3880 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3882 break;
3883 case OP_FDIV:
3884 CFG_DEBUG(4) g_print("ALPHA_TODO: [fdiv] dest=%d, sreg1=%d, sreg2=%d\n",
3885 ins->dreg, ins->sreg1, ins->sreg2);
3886 alpha_divt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
3887 alpha_trapb(code);
3889 break;
3890 default:
3891 g_warning ("unknown opcode %s in %s()\n",
3892 mono_inst_name (ins->opcode), __FUNCTION__);
3893 alpha_nop(code);
3894 // g_assert_not_reached ();
3898 if ( (((char *)code) -
3899 ((char *)cfg->native_code) -
3900 offset) > max_len)
3902 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3903 mono_inst_name (ins->opcode), max_len,
3904 ((char *)code) - ((char *)cfg->native_code) - offset );
3905 //g_assert_not_reached ();
3908 cpos += max_len;
3910 last_ins = ins;
3911 last_offset = offset;
3914 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3917 /*========================= End of Function ========================*/
3922 /*------------------------------------------------------------------*/
3923 /* */
3924 /* Name - mono_arch_cpu_optimizazions */
3925 /* */
3926 /* Function - Returns the optimizations supported on this CPU */
3927 /* */
3928 /*------------------------------------------------------------------*/
3930 guint32
3931 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3933 guint32 opts = 0;
3935 if (getenv("MONO_ALPHA_DEBUG"))
3936 mini_alpha_verbose_level = 1;
3938 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3940 /*----------------------------------------------------------*/
3941 /* no alpha-specific optimizations yet */
3942 /*----------------------------------------------------------*/
3943 *exclude_mask = MONO_OPT_LINEARS;
3944 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3946 return opts;
3948 /*========================= End of Function ========================*/
3950 /*------------------------------------------------------------------*/
3951 /* */
3952 /* Name - mono_arch_flush_icache */
3953 /* */
3954 /* Function - Flush the CPU icache. */
3955 /* */
3956 /*------------------------------------------------------------------*/
3958 void
3959 mono_arch_flush_icache (guint8 *code, gint size)
3961 //ALPHA_DEBUG("mono_arch_flush_icache");
3963 /* flush instruction cache to see trampoline code */
3964 asm volatile("imb":::"memory");
3967 /*========================= End of Function ========================*/
3969 /*------------------------------------------------------------------*/
3970 /* */
3971 /* Name - mono_arch_regname */
3972 /* */
3973 /* Function - Returns the name of the register specified by */
3974 /* the input parameter. */
3975 /* */
3976 /*------------------------------------------------------------------*/
3978 const char*
3979 mono_arch_regname (int reg) {
3980 static const char * rnames[] = {
3981 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
3982 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
3983 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
3984 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
3985 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
3986 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
3987 "alpha_r30", "alpha_r31"
3990 if (reg >= 0 && reg < 32)
3991 return rnames [reg];
3992 else
3993 return "unknown";
3995 /*========================= End of Function ========================*/
3997 /*------------------------------------------------------------------*/
3998 /* */
3999 /* Name - mono_arch_fregname */
4000 /* */
4001 /* Function - Returns the name of the register specified by */
4002 /* the input parameter. */
4003 /* */
4004 /*------------------------------------------------------------------*/
4006 const char*
4007 mono_arch_fregname (int reg) {
4008 static const char * rnames[] = {
4009 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4010 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4011 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4012 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4013 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4014 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4015 "alpha_f30", "alpha_f31"
4018 if (reg >= 0 && reg < 32)
4019 return rnames [reg];
4020 else
4021 return "unknown";
4024 /*========================= End of Function ========================*/
4026 /*------------------------------------------------------------------*/
4027 /* */
4028 /* Name - mono_arch_patch_code */
4029 /* */
4030 /* Function - Process the patch data created during the */
4031 /* instruction build process. This resolves jumps, */
4032 /* calls, variables etc. */
4033 /* */
4034 /*------------------------------------------------------------------*/
4036 void
4037 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
4038 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4040 MonoJumpInfo *patch_info;
4041 gboolean compile_aot = !run_cctors;
4043 ALPHA_DEBUG("mono_arch_patch_code");
4045 for (patch_info = ji; patch_info; patch_info = patch_info->next)
4047 unsigned char *ip = patch_info->ip.i + code;
4048 const unsigned char *target;
4050 target = mono_resolve_patch_target (method, domain,
4051 code, patch_info, run_cctors);
4053 if (compile_aot)
4055 switch (patch_info->type)
4058 case MONO_PATCH_INFO_BB:
4059 case MONO_PATCH_INFO_LABEL:
4060 break;
4061 default:
4062 /* No need to patch these */
4063 continue;
4067 switch (patch_info->type)
4069 case MONO_PATCH_INFO_NONE:
4070 continue;
4072 case MONO_PATCH_INFO_GOT_OFFSET:
4074 unsigned int *ip2 = (unsigned int *)ip;
4075 unsigned int inst = *ip2;
4076 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
4078 g_assert(!(off & 0xFFFF8000));
4080 inst |= off;
4082 *ip2 = inst;
4084 continue;
4086 case MONO_PATCH_INFO_CLASS_INIT:
4088 /* Might already been changed to a nop */
4089 unsigned int* ip2 = (unsigned int *)ip;
4090 unsigned long t_addr = (unsigned long)target;
4092 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
4093 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
4094 NOT_IMPLEMENTED;
4095 // amd64_call_code (ip2, 0);
4096 break;
4099 // case MONO_PATCH_INFO_METHOD_REL:
4100 case MONO_PATCH_INFO_R8:
4101 case MONO_PATCH_INFO_R4:
4102 g_assert_not_reached ();
4103 continue;
4104 case MONO_PATCH_INFO_BB:
4105 break;
4107 case MONO_PATCH_INFO_METHOD:
4108 case MONO_PATCH_INFO_METHODCONST:
4109 case MONO_PATCH_INFO_INTERNAL_METHOD:
4110 case MONO_PATCH_INFO_METHOD_JUMP:
4112 volatile unsigned int *p = (unsigned int *)ip;
4113 unsigned long t_addr;
4115 t_addr = *(p+1);
4116 t_addr <<= 32;
4117 t_addr |= *(p);
4119 ALPHA_PRINT
4120 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4121 target, t_addr);
4122 if (target != ((void *)t_addr))
4124 t_addr = (unsigned long)target;
4125 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4126 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4129 continue;
4131 case MONO_PATCH_INFO_ABS:
4133 volatile unsigned int *p = (unsigned int *)ip;
4134 unsigned long t_addr;
4136 t_addr = *(p+1);
4137 t_addr <<= 32;
4138 t_addr += *(p);
4140 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4141 target, t_addr);
4144 continue;
4145 case MONO_PATCH_INFO_SWITCH:
4147 unsigned int *pcode = (unsigned int *)ip;
4148 unsigned long t_addr;
4150 t_addr = (unsigned long)target;
4152 if (((unsigned long)ip) % 8)
4154 alpha_nop(pcode);
4155 ip += 4;
4158 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4159 alpha_nop(pcode); // TODO optimize later
4160 alpha_bsr(pcode, alpha_at, 2);
4162 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4163 pcode++;
4164 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4165 pcode++;
4167 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4170 continue;
4172 default:
4173 break;
4177 volatile unsigned int *p = (unsigned int *)ip;
4178 unsigned int alpha_ins = *p;
4179 unsigned int opcode;
4180 long br_offset;
4182 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4184 if (opcode >= 0x30 && opcode <= 0x3f)
4186 // This is branch with offset instruction
4187 br_offset = (target - ip - 4);
4189 g_assert(!(br_offset & 3));
4191 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4193 *p = alpha_ins;
4199 /*========================= End of Function ========================*/
4200 /*------------------------------------------------------------------*/
4201 /* */
4202 /* Name - mono_arch_emit_this_vret_args */
4203 /* */
4204 /* Function - */
4205 /* */
4206 /*------------------------------------------------------------------*/
4208 void
4209 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4210 int this_reg, int this_type, int vt_reg)
4212 MonoCallInst *call = (MonoCallInst*)inst;
4213 CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, inst->signature, FALSE);
4215 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4217 if (vt_reg != -1)
4219 MonoInst *vtarg;
4221 if (cinfo->ret.storage == ArgValuetypeInReg)
4224 * The valuetype is in RAX:RDX after the call, need to be copied to
4225 * the stack. Push the address here, so the call instruction can
4226 * access it.
4228 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4229 //vtarg->sreg1 = vt_reg;
4230 //mono_bblock_add_inst (cfg->cbb, vtarg);
4232 /* Align stack */
4233 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4234 // SP, 8);
4236 else
4238 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4239 vtarg->sreg1 = vt_reg;
4240 vtarg->dreg = mono_alloc_ireg (cfg);
4241 mono_bblock_add_inst (cfg->cbb, vtarg);
4243 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4244 cinfo->ret.reg, FALSE);
4248 /* add the this argument */
4249 if (this_reg != -1)
4251 MonoInst *this;
4252 MONO_INST_NEW (cfg, this, OP_MOVE);
4253 this->type = this_type;
4254 this->sreg1 = this_reg;
4255 this->dreg = mono_alloc_ireg (cfg);
4256 mono_bblock_add_inst (cfg->cbb, this);
4258 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4259 cinfo->args [0].reg, FALSE);
4262 g_free (cinfo);
4265 /*========================= End of Function ========================*/
4267 /*------------------------------------------------------------------*/
4268 /* */
4269 /* Name - mono_arch_is_inst_imm */
4270 /* */
4271 /* Function - Determine if operand qualifies as an immediate */
4272 /* value. For Alpha this is a value 0 - 255 */
4273 /* */
4274 /* Returns - True|False - is [not] immediate value. */
4275 /* */
4276 /*------------------------------------------------------------------*/
4278 gboolean
4279 mono_arch_is_inst_imm (gint64 imm)
4281 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4283 return (imm & ~(0x0FFL)) ? 0 : 1;
4286 /*------------------------------------------------------------------*/
4287 /* */
4288 /* Name - mono_arch_setup_jit_tls_data */
4289 /* */
4290 /* Function - Setup the JIT's Thread Level Specific Data. */
4291 /* */
4292 /*------------------------------------------------------------------*/
4294 void
4295 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4297 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4299 if (!tls_offset_inited) {
4300 tls_offset_inited = TRUE;
4303 if (!lmf_addr_key_inited) {
4304 lmf_addr_key_inited = TRUE;
4305 pthread_key_create (&lmf_addr_key, NULL);
4308 pthread_setspecific (lmf_addr_key, &tls->lmf);
4311 /*------------------------------------------------------------------*/
4312 /* */
4313 /* Name - mono_arch_cpu_init */
4314 /* */
4315 /* Function - Perform CPU specific initialization to execute */
4316 /* managed code. */
4317 /* */
4318 /*------------------------------------------------------------------*/
4320 void
4321 mono_arch_cpu_init (void)
4323 unsigned long amask, implver;
4324 register long v0 __asm__("$0") = -1;
4326 ALPHA_DEBUG("mono_arch_cpu_init");
4328 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
4329 amask = ~v0;
4330 __asm__ (".long 0x47e03d80" : "=r"(v0));
4331 implver = v0;
4333 if (amask & 1)
4334 bwx_supported = 1;
4336 //printf("amask: %x, implver: %x", amask, implver);
4340 * Initialize architecture specific code.
4342 void
4343 mono_arch_init (void)
4348 * Cleanup architecture specific code.
4350 void
4351 mono_arch_cleanup (void)
4356 * get_call_info:
4358 * Obtain information about a call according to the calling convention.
4360 * For x86 ELF, see the "System V Application Binary Interface Intel386
4361 * Architecture Processor Supplment, Fourth Edition" document for more
4362 * information.
4363 * For x86 win32, see ???.
4365 static CallInfo*
4366 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
4368 guint32 i, gr, fr, *pgr, *pfr;
4369 MonoType *ret_type;
4370 int n = sig->hasthis + sig->param_count;
4371 guint32 stack_size = 0;
4372 CallInfo *cinfo;
4374 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4376 gr = 0;
4377 fr = 0;
4379 if (is_pinvoke)
4380 pgr = pfr = &gr;
4381 else
4383 pgr = &gr;
4384 pfr = &fr;
4387 /* return value */
4389 ret_type = mono_type_get_underlying_type (sig->ret);
4390 switch (ret_type->type) {
4391 case MONO_TYPE_BOOLEAN:
4392 case MONO_TYPE_I1:
4393 case MONO_TYPE_U1:
4394 case MONO_TYPE_I2:
4395 case MONO_TYPE_U2:
4396 case MONO_TYPE_CHAR:
4397 case MONO_TYPE_I4:
4398 case MONO_TYPE_U4:
4399 case MONO_TYPE_I:
4400 case MONO_TYPE_U:
4401 case MONO_TYPE_PTR:
4402 case MONO_TYPE_FNPTR:
4403 case MONO_TYPE_CLASS:
4404 case MONO_TYPE_OBJECT:
4405 case MONO_TYPE_SZARRAY:
4406 case MONO_TYPE_ARRAY:
4407 case MONO_TYPE_STRING:
4408 cinfo->ret.storage = ArgInIReg;
4409 cinfo->ret.reg = alpha_r0;
4410 break;
4411 case MONO_TYPE_U8:
4412 case MONO_TYPE_I8:
4413 cinfo->ret.storage = ArgInIReg;
4414 cinfo->ret.reg = alpha_r0;
4415 break;
4416 case MONO_TYPE_R4:
4417 cinfo->ret.storage = ArgInFloatReg;
4418 cinfo->ret.reg = alpha_f0;
4419 break;
4420 case MONO_TYPE_R8:
4421 cinfo->ret.storage = ArgInDoubleReg;
4422 cinfo->ret.reg = alpha_f0;
4423 break;
4424 case MONO_TYPE_GENERICINST:
4425 if (!mono_type_generic_inst_is_valuetype (sig->ret))
4427 cinfo->ret.storage = ArgInIReg;
4428 cinfo->ret.reg = alpha_r0;
4429 break;
4431 /* Fall through */
4432 case MONO_TYPE_VALUETYPE:
4434 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4436 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE,
4437 &tmp_gr, &tmp_fr, &tmp_stacksize);
4439 if (cinfo->ret.storage == ArgOnStack)
4440 /* The caller passes the address where the value
4441 is stored */
4442 add_general (pgr, &stack_size, &cinfo->ret);
4443 break;
4445 case MONO_TYPE_TYPEDBYREF:
4446 /* Same as a valuetype with size 24 */
4447 add_general (pgr, &stack_size, &cinfo->ret);
4449 break;
4450 case MONO_TYPE_VOID:
4451 break;
4452 default:
4453 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4457 /* this */
4458 if (sig->hasthis)
4459 add_general (pgr, &stack_size, cinfo->args + 0);
4461 if (!sig->pinvoke &&
4462 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4464 gr = PARAM_REGS;
4465 fr = FLOAT_PARAM_REGS;
4467 /* Emit the signature cookie just before the implicit arguments
4469 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4472 for (i = 0; i < sig->param_count; ++i)
4474 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4475 MonoType *ptype;
4477 if (!sig->pinvoke &&
4478 (sig->call_convention == MONO_CALL_VARARG) &&
4479 (i == sig->sentinelpos))
4481 /* We allways pass the sig cookie on the stack for simpl
4482 icity */
4484 * Prevent implicit arguments + the sig cookie from being passed
4485 * in registers.
4487 gr = PARAM_REGS;
4488 fr = FLOAT_PARAM_REGS;
4490 /* Emit the signature cookie just before the implicit arguments */
4491 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4494 if (sig->params [i]->byref) {
4495 add_general (pgr, &stack_size, ainfo);
4496 continue;
4499 ptype = mono_type_get_underlying_type (sig->params [i]);
4501 switch (ptype->type) {
4502 case MONO_TYPE_BOOLEAN:
4503 case MONO_TYPE_I1:
4504 case MONO_TYPE_U1:
4505 add_general (pgr, &stack_size, ainfo);
4506 break;
4507 case MONO_TYPE_I2:
4508 case MONO_TYPE_U2:
4509 case MONO_TYPE_CHAR:
4510 add_general (pgr, &stack_size, ainfo);
4511 break;
4512 case MONO_TYPE_I4:
4513 case MONO_TYPE_U4:
4514 add_general (pgr, &stack_size, ainfo);
4515 break;
4516 case MONO_TYPE_I:
4517 case MONO_TYPE_U:
4518 case MONO_TYPE_PTR:
4519 case MONO_TYPE_FNPTR:
4520 case MONO_TYPE_CLASS:
4521 case MONO_TYPE_OBJECT:
4522 case MONO_TYPE_STRING:
4523 case MONO_TYPE_SZARRAY:
4524 case MONO_TYPE_ARRAY:
4525 add_general (pgr, &stack_size, ainfo);
4526 break;
4527 case MONO_TYPE_GENERICINST:
4528 if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
4530 add_general (pgr, &stack_size, ainfo);
4531 break;
4533 /* Fall through */
4534 case MONO_TYPE_VALUETYPE:
4535 /* FIXME: */
4536 /* We allways pass valuetypes on the stack */
4537 add_valuetype (gsctx, sig, ainfo, sig->params [i],
4538 FALSE, pgr, pfr, &stack_size);
4539 break;
4540 case MONO_TYPE_TYPEDBYREF:
4541 stack_size += sizeof (MonoTypedRef);
4542 ainfo->storage = ArgOnStack;
4543 break;
4544 case MONO_TYPE_U8:
4545 case MONO_TYPE_I8:
4546 add_general (pgr, &stack_size, ainfo);
4547 break;
4548 case MONO_TYPE_R4:
4549 add_float (pfr, &stack_size, ainfo, FALSE);
4550 break;
4551 case MONO_TYPE_R8:
4552 add_float (pfr, &stack_size, ainfo, TRUE);
4553 break;
4554 default:
4555 g_assert_not_reached ();
4559 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4560 (n > 0) && (sig->sentinelpos == sig->param_count))
4562 gr = PARAM_REGS;
4563 fr = FLOAT_PARAM_REGS;
4565 /* Emit the signature cookie just before the implicit arguments
4567 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4570 cinfo->stack_usage = stack_size;
4571 cinfo->reg_usage = gr;
4572 cinfo->freg_usage = fr;
4574 return cinfo;
4577 static const char *CvtMonoType(MonoTypeEnum t)
4579 switch(t)
4581 case MONO_TYPE_END:
4582 return "MONO_TYPE_END";
4583 case MONO_TYPE_VOID:
4584 return "MONO_TYPE_VOID";
4585 case MONO_TYPE_BOOLEAN:
4586 return "MONO_TYPE_BOOLEAN";
4587 case MONO_TYPE_CHAR:
4588 return "MONO_TYPE_CHAR";
4589 case MONO_TYPE_I1:
4590 return "MONO_TYPE_I1";
4591 case MONO_TYPE_U1:
4592 return "MONO_TYPE_U1";
4593 case MONO_TYPE_I2:
4594 return "MONO_TYPE_I2";
4595 case MONO_TYPE_U2:
4596 return "MONO_TYPE_U2";
4597 case MONO_TYPE_I4:
4598 return "MONO_TYPE_I4";
4599 case MONO_TYPE_U4:
4600 return "MONO_TYPE_U4";
4601 case MONO_TYPE_I8:
4602 return "MONO_TYPE_I8";
4603 case MONO_TYPE_U8:
4604 return "MONO_TYPE_U8";
4605 case MONO_TYPE_R4:
4606 return "MONO_TYPE_R4";
4607 case MONO_TYPE_R8:
4608 return "MONO_TYPE_R8";
4609 case MONO_TYPE_STRING:
4610 return "MONO_TYPE_STRING";
4611 case MONO_TYPE_PTR:
4612 return "MONO_TYPE_PTR";
4613 case MONO_TYPE_BYREF:
4614 return "MONO_TYPE_BYREF";
4615 case MONO_TYPE_VALUETYPE:
4616 return "MONO_TYPE_VALUETYPE";
4617 case MONO_TYPE_CLASS:
4618 return "MONO_TYPE_CLASS";
4619 case MONO_TYPE_VAR:
4620 return "MONO_TYPE_VAR";
4621 case MONO_TYPE_ARRAY:
4622 return "MONO_TYPE_ARRAY";
4623 case MONO_TYPE_GENERICINST:
4624 return "MONO_TYPE_GENERICINST";
4625 case MONO_TYPE_TYPEDBYREF:
4626 return "MONO_TYPE_TYPEDBYREF";
4627 case MONO_TYPE_I:
4628 return "MONO_TYPE_I";
4629 case MONO_TYPE_U:
4630 return "MONO_TYPE_U";
4631 case MONO_TYPE_FNPTR:
4632 return "MONO_TYPE_FNPTR";
4633 case MONO_TYPE_OBJECT:
4634 return "MONO_TYPE_OBJECT";
4635 case MONO_TYPE_SZARRAY:
4636 return "MONO_TYPE_SZARRAY";
4637 case MONO_TYPE_MVAR:
4638 return "MONO_TYPE_MVAR";
4639 case MONO_TYPE_CMOD_REQD:
4640 return "MONO_TYPE_CMOD_REQD";
4641 case MONO_TYPE_CMOD_OPT:
4642 return "MONO_TYPE_CMOD_OPT";
4643 case MONO_TYPE_INTERNAL:
4644 return "MONO_TYPE_INTERNAL";
4645 case MONO_TYPE_MODIFIER:
4646 return "MONO_TYPE_MODIFIER";
4647 case MONO_TYPE_SENTINEL:
4648 return "MONO_TYPE_SENTINEL";
4649 case MONO_TYPE_PINNED:
4650 return "MONO_TYPE_PINNED";
4651 default:
4654 return "unknown";
4658 /*------------------------------------------------------------------*/
4659 /* */
4660 /* Name - mono_arch_call_opcode */
4661 /* */
4662 /* Function - Take the arguments and generate the arch-specific */
4663 /* instructions to properly call the function. This */
4664 /* includes pushing, moving argments to the correct */
4665 /* etc. */
4667 * This method is called during converting method to IR
4668 * We need to generate IR ints to follow calling convention
4669 * cfg - points to currently compiled unit
4670 * bb - ???
4671 * call - points to structure that describes what we are going to
4672 * call (at least number of parameters required for the call)
4675 * On return we need to pass back modified call structure
4677 /*------------------------------------------------------------------*/
4679 MonoCallInst*
4680 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4681 MonoCallInst *call, int is_virtual)
4683 MonoInst *arg, *in;
4684 MonoMethodSignature *sig;
4685 int i, n;
4686 CallInfo *cinfo;
4687 int sentinelpos;
4689 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4691 sig = call->signature;
4692 n = sig->param_count + sig->hasthis;
4694 // Collect info about method we age going to call
4695 cinfo = get_call_info (cfg->generic_sharing_context, sig, sig->pinvoke);
4697 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4698 sig->pinvoke ? "PInvoke" : "Managed",
4699 sig->param_count, sig->hasthis,
4700 CvtMonoType(sig->ret->type), sig->ret->type);
4702 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4703 cfg->arch.params_stack_size = cinfo->stack_usage;
4705 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4706 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4708 for (i = 0; i < n; ++i)
4710 ArgInfo *ainfo = cinfo->args + i;
4712 /* Emit the signature cookie just before the implicit arguments
4714 if (!sig->pinvoke &&
4715 (sig->call_convention == MONO_CALL_VARARG) &&
4716 (i == sentinelpos))
4718 MonoMethodSignature *tmp_sig;
4719 MonoInst *sig_arg;
4721 /* FIXME: Add support for signature tokens to AOT */
4722 cfg->disable_aot = TRUE;
4723 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4726 * mono_ArgIterator_Setup assumes the signature cookie is
4727 * passed first and all the arguments which were before it are
4728 * passed on the stack after the signature. So compensate by
4729 * passing a different signature.
4731 tmp_sig = mono_metadata_signature_dup (call->signature);
4732 tmp_sig->param_count -= call->signature->sentinelpos;
4733 tmp_sig->sentinelpos = 0;
4734 memcpy (tmp_sig->params,
4735 call->signature->params + call->signature->sentinelpos,
4736 tmp_sig->param_count * sizeof (MonoType*));
4738 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4739 sig_arg->inst_p0 = tmp_sig;
4741 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4742 arg->inst_left = sig_arg;
4743 arg->type = STACK_PTR;
4745 /* prepend, so they get reversed */
4746 arg->next = call->out_args;
4747 call->out_args = arg;
4750 if (is_virtual && i == 0) {
4751 /* the argument will be attached to the call instrucion
4753 in = call->args [i];
4754 } else {
4755 MonoType *arg_type;
4757 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4758 in = call->args [i];
4759 arg->cil_code = in->cil_code;
4760 arg->inst_left = in;
4761 arg->type = in->type;
4762 /* prepend, so they get reversed */
4763 arg->next = call->out_args;
4764 call->out_args = arg;
4766 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4768 if (sig->hasthis && (i == 0))
4769 arg_type = &mono_defaults.object_class->byval_arg;
4770 else
4771 arg_type = sig->params [i - sig->hasthis];
4773 if ((i >= sig->hasthis) &&
4774 (MONO_TYPE_ISSTRUCT(arg_type)))
4776 guint align;
4777 guint32 size;
4779 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4780 size = sizeof (MonoTypedRef);
4781 align = sizeof (gpointer);
4783 else
4784 if (sig->pinvoke)
4785 size = mono_type_native_stack_size (&in->klass->byval_arg,
4786 &align);
4787 else
4788 size = mini_type_stack_size (cfg->generic_sharing_context, &in->klass->byval_arg, &align);
4790 if (ainfo->storage == ArgAggregate)
4792 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4793 int slot, j;
4795 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4797 vtaddr = mono_compile_create_var (cfg,
4798 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4801 * Part of the structure is passed in registers.
4803 for (j = 0; j < ainfo->nregs; ++j)
4805 int offset, load_op, dest_reg, arg_storage;
4807 slot = ainfo->reg + j;
4808 load_op = CEE_LDIND_I;
4809 offset = j * 8;
4810 dest_reg = ainfo->reg + j;
4811 arg_storage = ArgInIReg;
4813 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4814 load->ssa_op = MONO_SSA_LOAD;
4815 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4817 NEW_ICONST (cfg, offset_ins, offset);
4818 MONO_INST_NEW (cfg, load2, CEE_ADD);
4819 load2->inst_left = load;
4820 load2->inst_right = offset_ins;
4822 MONO_INST_NEW (cfg, load, load_op);
4823 load->inst_left = load2;
4825 if (j == 0)
4826 set_reg = arg;
4827 else
4828 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4830 add_outarg_reg (cfg, call, set_reg, arg_storage,
4831 dest_reg, load);
4832 if (set_reg != call->out_args)
4834 set_reg->next = call->out_args;
4835 call->out_args = set_reg;
4840 * Part of the structure is passed on the stack.
4842 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4844 MonoInst *outarg;
4846 slot = ainfo->reg + j;
4848 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4849 load->ssa_op = MONO_SSA_LOAD;
4850 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4852 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4853 MONO_INST_NEW (cfg, load2, CEE_ADD);
4854 load2->inst_left = load;
4855 load2->inst_right = offset_ins;
4857 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4858 load->inst_left = load2;
4860 if (j == 0)
4861 outarg = arg;
4862 else
4863 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4865 outarg->inst_left = load;
4866 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4867 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4869 if (outarg != call->out_args)
4871 outarg->next = call->out_args;
4872 call->out_args = outarg;
4876 /* Trees can't be shared so make a copy*/
4877 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4878 arg->cil_code = in->cil_code;
4879 arg->ssa_op = MONO_SSA_STORE;
4880 arg->inst_left = vtaddr;
4881 arg->inst_right = in;
4882 arg->type = in->type;
4884 /* prepend, so they get reversed */
4885 arg->next = call->out_args;
4886 call->out_args = arg;
4888 else
4890 MonoInst *stack_addr;
4892 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4894 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4895 stack_addr->inst_basereg = alpha_sp;
4896 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4897 stack_addr->inst_offset = ainfo->offset;
4898 //stack_addr->inst_offset = 16 + ainfo->offset;
4899 stack_addr->inst_imm = size;
4901 arg->opcode = OP_OUTARG_VT;
4902 arg->inst_right = stack_addr;
4906 arg->opcode = OP_OUTARG_VT;
4907 arg->klass = in->klass;
4908 arg->backend.is_pinvoke = sig->pinvoke;
4909 arg->inst_imm = size; */
4911 else
4913 CFG_DEBUG(3) g_print("simple\n");
4915 switch (ainfo->storage)
4917 case ArgInIReg:
4918 add_outarg_reg (cfg, call, arg, ainfo->storage,
4919 ainfo->reg, in);
4920 break;
4921 case ArgOnStack:
4922 arg->opcode = OP_OUTARG;
4923 //arg->dreg = -((n - i) * 8);
4924 arg->dreg = ainfo->offset;
4925 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4927 if (!sig->params[i-sig->hasthis]->byref) {
4928 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4929 arg->opcode = OP_OUTARG_R4;
4930 else
4931 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4932 arg->opcode = OP_OUTARG_R8;
4934 break;
4935 case ArgInFloatReg:
4936 case ArgInDoubleReg:
4937 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4938 break;
4939 default:
4940 g_assert_not_reached ();
4946 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4948 if (cinfo->ret.storage == ArgValuetypeInReg) {
4949 MonoInst *zero_inst;
4951 * After the call, the struct is in registers, but needs to be saved
4952 to the memory pointed
4953 * to by vt_arg in this_vret_args. This means that vt_ar
4954 g needs to be saved somewhere
4955 * before calling the function. So we add a dummy instru
4956 ction to represent pushing the
4957 * struct return address to the stack. The return addres
4958 s will be saved to this stack slot
4959 * by the code emitted in this_vret_args.
4961 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4962 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
4963 zero_inst->inst_p0 = 0;
4964 arg->inst_left = zero_inst;
4965 arg->type = STACK_PTR;
4966 /* prepend, so they get reversed */
4967 arg->next = call->out_args;
4968 call->out_args = arg;
4970 else
4971 /* if the function returns a struct, the called method a
4972 lready does a ret $0x4 */
4973 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4974 ; //cinfo->stack_usage -= 4;
4977 // stack_usage shows how much stack we would need to do the call
4978 // (for example for params that we pass on stack
4979 call->stack_usage = cinfo->stack_usage;
4981 // Save all used regs to do the call in compile unit structure
4982 cfg->used_int_regs |= call->used_iregs;
4984 g_free (cinfo);
4986 return call;
4989 /*========================= End of Function ========================*/
4991 /*------------------------------------------------------------------*/
4992 /* */
4993 /* Name - mono_arch_register_lowlevel_calls */
4994 /* */
4995 /* Function - Register routines to help with --trace operation. */
4996 /* */
4997 /*------------------------------------------------------------------*/
4999 void
5000 mono_arch_register_lowlevel_calls (void)
5002 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
5004 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
5005 NULL, TRUE);
5008 /*========================= End of Function ========================*/
5010 /*------------------------------------------------------------------*/
5011 /* */
5012 /* Name - mono_arch_global_int_regs */
5013 /* */
5014 /* Function - Return a list of usable integer registers. */
5015 /* */
5016 /*------------------------------------------------------------------*/
5018 GList *
5019 mono_arch_get_global_int_regs (MonoCompile *cfg)
5021 GList *regs = NULL;
5023 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5025 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5026 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5027 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5028 regs = g_list_prepend (regs, (gpointer)alpha_r12);
5029 regs = g_list_prepend (regs, (gpointer)alpha_r13);
5030 regs = g_list_prepend (regs, (gpointer)alpha_r14);
5032 return regs;
5035 /*========================= End of Function ========================*/
5037 /*------------------------------------------------------------------*/
5038 /* */
5039 /* Name - mono_arch_get_allocatable_int_vars */
5040 /* */
5041 /* Function - */
5042 /* */
5043 /*------------------------------------------------------------------*/
5045 GList *
5046 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
5048 GList *vars = NULL;
5049 int i;
5050 MonoMethodSignature *sig;
5051 MonoMethodHeader *header;
5052 CallInfo *cinfo;
5054 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5056 header = mono_method_get_header (cfg->method);
5058 sig = mono_method_signature (cfg->method);
5060 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5062 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5064 MonoInst *ins = cfg->args [i];
5066 ArgInfo *ainfo = &cinfo->args [i];
5068 if (ins->flags &
5069 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5070 continue;
5072 // if (ainfo->storage == ArgInIReg) {
5073 // /* The input registers are non-volatile */
5074 // ins->opcode = OP_REGVAR;
5075 //ins->dreg = 32 + ainfo->reg;
5076 // }
5079 for (i = 0; i < cfg->num_varinfo; i++)
5081 MonoInst *ins = cfg->varinfo [i];
5082 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
5084 /* unused vars */
5085 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
5086 continue;
5088 if ((ins->flags &
5089 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
5090 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
5091 continue;
5093 if (mono_is_regsize_var (ins->inst_vtype))
5095 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
5096 g_assert (i == vmv->idx);
5097 vars = g_list_prepend (vars, vmv);
5101 vars = mono_varlist_sort (cfg, vars, 0);
5103 return vars;
5106 /*========================= End of Function ========================*/
5108 /*------------------------------------------------------------------*/
5109 /* */
5110 /* Name - mono_arch_get_domain_intrinsic */
5111 /* */
5112 /* Function - */
5113 /* */
5114 /* Returns - */
5115 /* */
5116 /*------------------------------------------------------------------*/
5118 MonoInst *
5119 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5121 MonoInst *ins;
5123 if (appdomain_tls_offset == -1)
5124 return NULL;
5126 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5127 ins->inst_offset = appdomain_tls_offset;
5128 return (ins);
5131 /*========================= End of Function ========================*/
5133 /*------------------------------------------------------------------*/
5134 /* */
5135 /* Name - mono_arch_get_inst_for_method */
5136 /* */
5137 /* Function - Check for opcodes we can handle directly in */
5138 /* hardware. */
5139 /* */
5140 /*------------------------------------------------------------------*/
5142 MonoInst*
5143 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5144 MonoMethodSignature *fsig, MonoInst **args)
5146 MonoInst *ins = NULL;
5148 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5150 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5152 return ins;
5155 /*========================= End of Function ========================*/
5157 /*------------------------------------------------------------------*/
5158 /* */
5159 /* Name - mono_arch_create_class_init_trampoline */
5160 /* */
5161 /* Function - Creates a trampoline function to run a type init- */
5162 /* ializer. If the trampoline is called, it calls */
5163 /* mono_runtime_class_init with the given vtable, */
5164 /* then patches the caller code so it does not get */
5165 /* called any more. */
5166 /* */
5167 /* Parameter - vtable - The type to initialize */
5168 /* */
5169 /* Returns - A pointer to the newly created code */
5170 /* */
5171 /*------------------------------------------------------------------*/
5173 gpointer
5174 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5176 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5178 NOT_IMPLEMENTED;
5180 return 0;
5183 /*------------------------------------------------------------------*/
5184 /* */
5185 /* Name - mono_arch_instrument_prolog */
5186 /* */
5187 /* Function - Create an "instrumented" prolog. */
5188 /* */
5189 /*------------------------------------------------------------------*/
5191 void*
5192 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5193 gboolean enable_arguments)
5195 unsigned int *code = p;
5196 int offset;
5198 CallInfo *cinfo = NULL;
5199 MonoMethodSignature *sig;
5200 MonoInst *inst;
5201 int i, n, stack_area = 0;
5202 AlphaGotData ge_data;
5204 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5206 /* Keep this in sync with mono_arch_get_argument_info */
5207 if (enable_arguments)
5209 /* Allocate a new area on the stack and save arguments there */
5210 sig = mono_method_signature (cfg->method);
5212 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5214 n = sig->param_count + sig->hasthis;
5216 stack_area = ALIGN_TO (n * 8, 8);
5218 // Correct stack by calculated value
5219 if (stack_area)
5220 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5222 for (i = 0; i < n; ++i)
5224 inst = cfg->args [i];
5226 if (inst->opcode == OP_REGVAR)
5228 switch(cinfo->args[i].storage)
5230 case ArgInDoubleReg:
5231 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5232 break;
5233 case ArgInFloatReg:
5234 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5235 break;
5236 default:
5237 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5240 else
5242 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5243 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5248 offset = (char *)code - (char *)cfg->native_code;
5250 ge_data.data.p = cfg->method;
5252 add_got_entry(cfg, GT_PTR, ge_data,
5253 (char *)code - (char *)cfg->native_code,
5254 MONO_PATCH_INFO_METHODCONST, cfg->method);
5255 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5257 alpha_mov1(code, alpha_sp, alpha_a1);
5259 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5261 if (enable_arguments)
5263 // Correct stack back by calculated value
5264 if (stack_area)
5265 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5267 g_free(cinfo);
5270 return code;
5273 /*========================= End of Function ========================*/
5275 enum {
5276 SAVE_NONE,
5277 SAVE_STRUCT,
5278 SAVE_R0,
5279 SAVE_EAX_EDX,
5280 SAVE_XMM
5283 /*------------------------------------------------------------------*/
5284 /* */
5285 /* Name - mono_arch_instrument_epilog */
5286 /* */
5287 /* Function - Create an epilog that will handle the returned */
5288 /* values used in instrumentation. */
5289 /* */
5290 /*------------------------------------------------------------------*/
5292 void*
5293 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5295 unsigned int *code = p;
5296 int save_mode = SAVE_NONE;
5297 int offset;
5298 MonoMethod *method = cfg->method;
5299 AlphaGotData ge_data;
5300 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5302 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5304 switch (rtype)
5306 case MONO_TYPE_VOID:
5307 /* special case string .ctor icall */
5308 if (strcmp (".ctor", method->name) &&
5309 method->klass == mono_defaults.string_class)
5310 save_mode = SAVE_R0;
5311 else
5312 save_mode = SAVE_NONE;
5313 break;
5314 case MONO_TYPE_I8:
5315 case MONO_TYPE_U8:
5316 save_mode = SAVE_R0;
5317 break;
5318 case MONO_TYPE_R4:
5319 case MONO_TYPE_R8:
5320 save_mode = SAVE_XMM;
5321 break;
5322 case MONO_TYPE_VALUETYPE:
5323 save_mode = SAVE_STRUCT;
5324 break;
5325 default:
5326 save_mode = SAVE_R0;
5327 break;
5330 /* Save the result and copy it into the proper argument register */
5331 switch (save_mode)
5333 case SAVE_R0:
5334 alpha_lda(code, alpha_sp, alpha_sp, -8);
5335 alpha_stq(code, alpha_r0, alpha_sp, 0);
5337 if (enable_arguments)
5338 alpha_mov1(code, alpha_r0, alpha_a1);
5340 break;
5341 case SAVE_STRUCT:
5342 /* FIXME: */
5343 if (enable_arguments)
5344 alpha_lda(code, alpha_a1, alpha_zero, 0);
5346 break;
5347 case SAVE_XMM:
5348 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5349 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5350 /* Align stack */
5351 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5353 * The result is already in the proper argument register so no copying
5354 * needed.
5356 break;
5357 case SAVE_NONE:
5358 break;
5359 default:
5360 g_assert_not_reached ();
5363 offset = (char *)code - (char *)cfg->native_code;
5365 ge_data.data.p = cfg->method;
5367 add_got_entry(cfg, GT_PTR, ge_data,
5368 (char *)code - (char *)cfg->native_code,
5369 MONO_PATCH_INFO_METHODCONST, cfg->method);
5371 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5373 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5375 /* Restore result */
5376 switch (save_mode)
5378 case SAVE_R0:
5379 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5380 alpha_lda(code, alpha_sp, alpha_sp, 8);
5381 break;
5382 case SAVE_STRUCT:
5383 /* FIXME: */
5384 break;
5385 case SAVE_XMM:
5386 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5387 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5388 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5389 break;
5390 case SAVE_NONE:
5391 break;
5392 default:
5393 g_assert_not_reached ();
5396 return code;
5399 /*========================= End of Function ========================*/
5401 /*------------------------------------------------------------------*/
5402 /* */
5403 /* Name - mono_arch_allocate_vars */
5404 /* */
5405 /* Function - Set var information according to the calling */
5406 /* convention for Alpha. The local var stuff should */
5407 /* most likely be split in another method. */
5408 /* */
5409 /* Parameter - @m - Compile unit. */
5411 * This method is called right before working with BBs. Conversion to
5412 * IR was done and some analises what registers would be used.
5413 * Collect info about registers we used - if we want to use a register
5414 * we need to allocate space for it and save on the stack in method
5415 * prolog.
5417 * Alpha calling convertion:
5418 * FP -> Stack top <- SP
5419 * 0: Stack params to call others
5421 * RA <- arch.params_stack_size
5422 * old FP
5424 * [LMF info] <- arch.lmf_offset
5426 * [possible return values allocated on stack]
5428 * . [locals]
5430 * . caller saved regs <- arch.reg_save_area_offset
5431 * . a0 <- arch.args_save_area_offset
5432 * . a1
5433 * . a2
5434 * . a3
5435 * . a4
5436 * . a5
5437 * ------------------------
5438 * . a6 - passed args on stack
5441 /*------------------------------------------------------------------*/
5443 void
5444 mono_arch_allocate_vars (MonoCompile *cfg)
5446 MonoMethodSignature *sig;
5447 MonoMethodHeader *header;
5448 MonoInst *inst;
5449 int i, offset = 0, a_off = 0;
5450 guint32 locals_stack_size, locals_stack_align = 0;
5451 gint32 *offsets;
5452 CallInfo *cinfo;
5454 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5456 header = mono_method_get_header (cfg->method);
5458 sig = mono_method_signature (cfg->method);
5460 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5462 /* if (cfg->arch.omit_fp) {
5463 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5464 cfg->frame_reg = AMD64_RSP;
5465 offset = 0;
5467 else */
5469 /* Locals are allocated forwards from FP. After
5470 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5471 * (starting from offset 16).
5472 * FIXME: Check there Arg6...Argn are supposed to be
5474 cfg->frame_reg = alpha_fp;
5475 // offset = MONO_ALPHA_VARS_OFFSET;
5478 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5479 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5480 offset += cfg->arch.params_stack_size;
5482 offset += 16; // Size to save RA & FP
5484 if (cfg->method->save_lmf)
5486 /* Reserve stack space for saving LMF + argument regs */
5487 guint32 size = sizeof (MonoLMF);
5489 //if (lmf_tls_offset == -1)
5490 // /* Need to save argument regs too */
5491 // size += (AMD64_NREG * 8) + (8 * 8);
5493 cfg->arch.lmf_offset = offset;
5494 offset += size;
5496 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5497 cfg->method->name, cfg->arch.lmf_offset, size);
5500 if (sig->ret->type != MONO_TYPE_VOID)
5502 switch (cinfo->ret.storage)
5504 case ArgInIReg:
5505 case ArgInFloatReg:
5506 case ArgInDoubleReg:
5507 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5508 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5509 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5511 /* The register is volatile */
5512 cfg->ret->opcode = OP_REGOFFSET;
5513 cfg->ret->inst_basereg = cfg->frame_reg;
5515 /*if (cfg->arch.omit_fp) {
5516 cfg->ret->inst_offset = offset;
5517 offset += 8;
5518 } else */
5520 cfg->ret->inst_offset = offset;
5521 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5522 offset += 8;
5525 else
5527 cfg->ret->opcode = OP_REGVAR;
5528 cfg->ret->inst_c0 = cinfo->ret.reg;
5530 break;
5531 case ArgValuetypeInReg:
5532 /* Allocate a local to hold the result, the epilog will
5533 copy it to the correct place */
5534 // g_assert (!cfg->arch.omit_fp);
5535 offset += 16;
5536 cfg->ret->opcode = OP_REGOFFSET;
5537 cfg->ret->inst_basereg = cfg->frame_reg;
5538 cfg->ret->inst_offset = offset;
5539 break;
5540 default:
5541 g_assert_not_reached ();
5543 cfg->ret->dreg = cfg->ret->inst_c0;
5546 /* Allocate locals */
5547 offsets = mono_allocate_stack_slots_full (cfg,
5548 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5549 &locals_stack_size,
5550 &locals_stack_align);
5552 //g_assert((locals_stack_size % 8) == 0);
5553 if (locals_stack_size % 8)
5555 locals_stack_size += 8 - (locals_stack_size % 8);
5558 /* if (locals_stack_align)
5560 offset += (locals_stack_align - 1);
5561 offset &= ~(locals_stack_align - 1);
5565 cfg->arch.localloc_offset = offset;
5567 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5568 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5569 locals_stack_size, locals_stack_size);
5571 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5573 if (offsets [i] != -1) {
5574 MonoInst *inst = cfg->varinfo [i];
5575 inst->opcode = OP_REGOFFSET;
5576 inst->inst_basereg = cfg->frame_reg;
5577 //if (cfg->arch.omit_fp)
5578 // inst->inst_offset = (offset + offsets [i]);
5579 //else
5580 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5582 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5583 CFG_DEBUG(3) mono_print_tree_nl (inst);
5587 // TODO check how offsets[i] are calculated
5588 // it seems they are points to the end on data. Like 8, but it actually - 0
5590 offset += locals_stack_size; //+8;
5592 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5593 // g_assert (!cfg->arch.omit_fp);
5594 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5595 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5598 // Save offset for caller saved regs
5599 cfg->arch.reg_save_area_offset = offset;
5601 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5603 // Reserve space for caller saved registers
5604 for (i = 0; i < MONO_MAX_IREGS; ++i)
5605 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5606 (cfg->used_int_regs & (1 << i)))
5608 offset += sizeof (gpointer);
5611 // Save offset to args regs
5612 cfg->arch.args_save_area_offset = offset;
5614 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5616 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5618 ArgInfo *ainfo = &cinfo->args [i];
5620 switch(ainfo->storage)
5622 case ArgInIReg:
5623 case ArgInFloatReg:
5624 case ArgInDoubleReg:
5625 offset += sizeof (gpointer);
5626 break;
5627 case ArgAggregate:
5628 offset += ainfo->nregs * sizeof (gpointer);
5629 break;
5630 default:
5635 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5636 offset, offset);
5638 // Reserve space for method params
5639 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5641 inst = cfg->args [i];
5643 if (inst->opcode != OP_REGVAR)
5645 ArgInfo *ainfo = &cinfo->args [i];
5646 gboolean inreg = TRUE;
5647 MonoType *arg_type;
5649 if (sig->hasthis && (i == 0))
5650 arg_type = &mono_defaults.object_class->byval_arg;
5651 else
5652 arg_type = sig->params [i - sig->hasthis];
5654 /* FIXME: Allocate volatile arguments to registers */
5655 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5656 inreg = FALSE;
5659 * Under AMD64, all registers used to pass arguments to functions
5660 * are volatile across calls. For Alpha too.
5661 * FIXME: Optimize this.
5664 // Let's
5665 if (inreg && (ainfo->storage == ArgInIReg)
5666 //&& cfg->used_int_regs & (1 << ainfo->reg)
5668 inreg = FALSE;
5670 if (//(ainfo->storage == ArgInIReg) ||
5671 (ainfo->storage == ArgInFloatReg) ||
5672 (ainfo->storage == ArgInDoubleReg) ||
5673 (ainfo->storage == ArgValuetypeInReg))
5674 inreg = FALSE;
5676 inst->opcode = OP_REGOFFSET;
5678 switch (ainfo->storage)
5680 case ArgInIReg:
5681 case ArgInFloatReg:
5682 case ArgInDoubleReg:
5683 inst->opcode = OP_REGVAR;
5684 inst->dreg = ainfo->reg;
5685 break;
5686 case ArgOnStack:
5687 // g_assert (!cfg->arch.omit_fp);
5688 inst->opcode = OP_REGOFFSET;
5689 inst->inst_basereg = cfg->frame_reg;
5691 // "offset" here will point to the end of
5692 // array of saved ret,locals, args
5693 // Ideally it would point to "a7"
5694 inst->inst_offset = ainfo->offset + offset;
5695 break;
5696 case ArgValuetypeInReg:
5697 break;
5698 case ArgAggregate:
5699 inreg = FALSE;
5700 break;
5702 default:
5703 NOT_IMPLEMENTED;
5706 if (!inreg && (ainfo->storage != ArgOnStack))
5708 inst->opcode = OP_REGOFFSET;
5709 inst->inst_basereg = cfg->frame_reg;
5711 /* These arguments are saved to the stack in the prolog */
5712 /*if (cfg->arch.omit_fp) {
5713 inst->inst_offset = offset;
5714 offset += (ainfo->storage == ArgValuetypeInReg) ?
5715 2 * sizeof (gpointer) : sizeof (gpointer);
5716 } else */
5718 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5719 // 2 * sizeof (gpointer) : sizeof (gpointer);
5721 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5722 switch(ainfo->storage)
5724 case ArgAggregate:
5725 a_off += ainfo->nslots * 8;
5726 break;
5727 default:
5728 a_off += sizeof (gpointer);
5730 // (/*(ainfo->reg - 16)*/ i * 8);
5736 cfg->stack_offset = offset;
5738 g_free (cinfo);
5741 /*========================= End of Function ========================*/
5743 /*------------------------------------------------------------------*/
5744 /* */
5745 /* Name - mono_arch_print_tree */
5746 /* */
5747 /* Function - Print platform-specific opcode details. */
5748 /* */
5749 /* Returns - 1 - opcode details have been printed */
5750 /* 0 - opcode details have not been printed */
5751 /* */
5752 /*------------------------------------------------------------------*/
5754 gboolean
5755 mono_arch_print_tree (MonoInst *tree, int arity)
5757 gboolean done;
5759 ALPHA_DEBUG("mono_arch_print_tree");
5761 switch (tree->opcode) {
5762 default:
5763 done = 0;
5765 return (done);
5768 /*========================= End of Function ========================*/
5772 ** mono_arch_get_vcall_slot_addr
5773 ** is called by mono_magic_trampoline to determine that the JIT compiled
5774 ** method is called via vtable slot. We need to analyze call sequence
5775 ** and determine that. In case it is true - we need to return address
5776 ** of vtable slot.
5778 ** code - points to the next instruction after call
5779 ** reg - points to saved regs before the call (this is done
5780 ** by mono_magic_trampoline function
5783 gpointer*
5784 mono_arch_get_vcall_slot_addr (guint8* code, mgreg_t *regs)
5786 unsigned int *pc = (unsigned int *)code;
5787 guint32 reg, disp;
5788 int start_index = -2;
5790 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5791 pc, regs);
5793 // Check if we have parameters on stack
5794 if ((pc[-2] & 0xFFFF0000) == 0x23DE0000) // lda sp,-n(sp)
5795 start_index = -3;
5797 // Check for (call_membase):
5798 // -4: mov v0,a0 - load this ???
5799 // -3: ldq v0,0(v0) - load vtable
5800 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5801 if ((pc[start_index-1] & 0xFC00FFFF) == 0xA4000000 &&
5802 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5805 disp = pc[start_index] & 0xFFFF;
5806 reg = (pc[start_index-1] >> AXP_REG1_SHIFT) & AXP_REG_MASK;
5807 //reg = 0; // For now
5809 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5811 return (gpointer)(((guint64)(regs [reg])) + disp);
5814 // Check for interface call
5815 // -5: mov v0,a0
5816 // -4: ldq v0,0(v0)
5817 // -3: ldq v0,-n(v0)
5818 // -2: ldq t12,0(v0)
5819 if ((pc[start_index-2] & 0xFC00FFFF) == 0xA4000000 &&
5820 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5821 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5824 disp = pc[start_index] & 0xFFFF;;
5825 reg = 0; // For now
5827 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5829 return (gpointer)(((guint64)(regs [reg])) + disp);
5832 return 0;
5835 gpointer
5836 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
5838 unsigned int *pc = (unsigned int *)code;
5840 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_this_arg_from_call] code: %p regs: %p",
5841 pc, regs);
5843 if (MONO_TYPE_ISSTRUCT (sig->ret))
5844 return (gpointer)regs [alpha_a1];
5845 else
5846 return (gpointer)regs [alpha_a0];
5849 gpointer
5850 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5852 unsigned int *code, *start;
5853 MonoDomain *domain = mono_domain_get ();
5854 int i;
5856 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_delegate_invoke_impl]");
5858 /* FIXME: Support more cases */
5859 if (MONO_TYPE_ISSTRUCT (sig->ret))
5860 return NULL;
5862 return NULL;
5865 guint32
5866 mono_arch_get_patch_offset (guint8 *code)
5868 return 3;
5871 gpointer
5872 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5874 /* FIXME: implement */
5875 g_assert_not_reached ();