1 /*------------------------------------------------------------------*/
3 /* Name - mini-alpha.c */
5 /* Function - Alpha backend for the Mono code generator. */
7 /* Name - Sergey Tikhonov (tsv@solvo.ru) */
9 /* Date - January, 2006 */
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) */
16 /*------------------------------------------------------------------*/
18 /*------------------------------------------------------------------*/
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,ins,dest,op) do { \
28 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
29 (dest)->opcode = (op); \
30 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
33 #define NEW_ICONST(cfg,dest,val) do { \
34 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
35 (dest)->opcode = OP_ICONST; \
36 (dest)->inst_c0 = (val); \
37 (dest)->type = STACK_I4; \
42 #define DEBUG(a) if (cfg->verbose_level > 1) a
44 #define CFG_DEBUG(LVL) if (cfg->verbose_level > LVL)
46 //#define ALPHA_IS_CALLEE_SAVED_REG(reg) (MONO_ARCH_CALLEE_SAVED_REGS & (1 << (reg)))
47 #define ALPHA_ARGS_REGS ((regmask_t)0x03F0000)
48 #define ARGS_OFFSET 16
50 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
51 #define alpha_is_imm(X) ((X >= 0 && X <= 255))
52 #define ALPHA_LOAD_GP(IP) { AlphaGotData ge_data; add_got_entry(cfg, GT_LD_GTADDR, ge_data, IP, MONO_PATCH_INFO_NONE, 0); }
54 /*========================= End of Defines =========================*/
56 /*------------------------------------------------------------------*/
58 /*------------------------------------------------------------------*/
63 #include <mono/metadata/appdomain.h>
64 #include <mono/metadata/debug-helpers.h>
65 #include <mono/metadata/profiler-private.h>
66 #include <mono/utils/mono-math.h>
69 #include "mini-alpha.h"
71 #include "cpu-alpha.h"
72 #include "jit-icalls.h"
74 /*========================= End of Includes ========================*/
76 /*------------------------------------------------------------------*/
77 /* G l o b a l V a r i a b l e s */
78 /*------------------------------------------------------------------*/
79 static int indent_level = 0;
81 int mini_alpha_verbose_level = 0;
82 static int bwx_supported = 0;
84 static gboolean tls_offset_inited = FALSE;
86 static int appdomain_tls_offset = -1,
88 thread_tls_offset = -1;
90 pthread_key_t lmf_addr_key;
92 gboolean lmf_addr_key_inited = FALSE;
95 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
97 /*====================== End of Global Variables ===================*/
99 gpointer mono_arch_get_lmf_addr (void);
106 ArgValuetypeInReg, // ??
117 /* Only if storage == ArgAggregate */
119 //AggregateType atype; // So far use only AggregateNormal
125 // guint32 struct_ret; /// ???
129 gboolean need_stack_align;
136 static CallInfo* get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke);
137 static unsigned int *emit_call(MonoCompile *cfg, unsigned int *code,
138 guint32 patch_type, gconstpointer data);
141 static int param_regs [] =
148 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
151 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
153 ainfo->offset = *stack_size;
155 if (*gr >= PARAM_REGS)
157 ainfo->storage = ArgOnStack;
158 (*stack_size) += sizeof (gpointer);
162 ainfo->storage = ArgInIReg;
163 ainfo->reg = param_regs [*gr];
168 #define FLOAT_PARAM_REGS 6
169 static int fparam_regs [] = { alpha_fa0, alpha_fa1, alpha_fa2, alpha_fa3,
170 alpha_fa4, alpha_fa5 };
173 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo,
176 ainfo->offset = *stack_size;
178 if (*gr >= FLOAT_PARAM_REGS)
180 ainfo->storage = ArgOnStack;
181 (*stack_size) += sizeof (gpointer);
185 /* A double register */
187 ainfo->storage = ArgInDoubleReg;
189 ainfo->storage = ArgInFloatReg;
191 ainfo->reg = fparam_regs [*gr];
197 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
199 guint32 *gr, guint32 *fr, guint32 *stack_size)
203 MonoMarshalType *info;
204 //gboolean is_hfa = TRUE;
205 //guint32 hfa_type = 0;
207 klass = mono_class_from_mono_type (type);
208 if (type->type == MONO_TYPE_TYPEDBYREF)
209 size = 3 * sizeof (gpointer);
210 else if (sig->pinvoke)
211 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
213 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
215 if (!sig->pinvoke || (size == 0) || is_return) {
216 /* Allways pass in memory */
217 ainfo->offset = *stack_size;
218 *stack_size += ALIGN_TO (size, 8);
219 ainfo->storage = ArgOnStack;
224 info = mono_marshal_load_type_info (klass);
227 ainfo->storage = ArgAggregate;
228 //ainfo->atype = AggregateNormal;
231 /* This also handles returning of TypedByRef used by some icalls */
234 ainfo->reg = IA64_R8;
235 ainfo->nregs = (size + 7) / 8;
236 ainfo->nslots = ainfo->nregs;
243 ainfo->reg = param_regs [*gr];
244 ainfo->offset = *stack_size;
245 ainfo->nslots = (size + 7) / 8;
247 if (((*gr) + ainfo->nslots) <= 6) {
248 /* Fits entirely in registers */
249 ainfo->nregs = ainfo->nslots;
250 (*gr) += ainfo->nregs;
254 ainfo->nregs = 6 - (*gr);
256 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
260 // This function is called from mono_arch_call_opcode and
261 // should determine which registers will be used to do the call
262 // For Alpha we could calculate number of parameter used for each
263 // call and allocate space in stack only for whose "a0-a5" registers
264 // that will be used in calls
266 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
267 ArgStorage storage, int reg, MonoInst *tree)
272 arg->opcode = OP_OUTARG_REG;
273 arg->inst_left = tree;
274 arg->inst_right = (MonoInst*)call;
275 arg->backend.reg3 = reg;
276 call->used_iregs |= 1 << reg;
279 arg->opcode = OP_OUTARG_FREG;
280 arg->inst_left = tree;
281 arg->inst_right = (MonoInst*)call;
282 arg->backend.reg3 = reg;
283 call->used_fregs |= 1 << reg;
286 arg->opcode = OP_OUTARG_FREG;
287 arg->inst_left = tree;
288 arg->inst_right = (MonoInst*)call;
289 arg->backend.reg3 = reg;
290 call->used_fregs |= 1 << reg;
293 g_assert_not_reached ();
297 static void add_got_entry(MonoCompile *cfg, AlphaGotType ge_type,
298 AlphaGotData ge_data,
299 int ip, MonoJumpInfoType type, gconstpointer target)
301 AlphaGotEntry *AGE = mono_mempool_alloc (cfg->mempool,
302 sizeof (AlphaGotEntry));
309 AGE->value.data.i = ge_data.data.i;
312 AGE->value.data.l = ge_data.data.l;
315 AGE->value.data.p = ge_data.data.p;
318 AGE->value.data.f = ge_data.data.f;
321 AGE->value.data.d = ge_data.data.d;
324 AGE->value.data.l = ip;
330 if (type != MONO_PATCH_INFO_NONE)
332 mono_add_patch_info(cfg, ip, type, target);
333 AGE->patch_info = cfg->patch_info;
338 if (AGE->type != GT_LD_GTADDR)
340 mono_add_patch_info(cfg, ip, MONO_PATCH_INFO_GOT_OFFSET, 0);
341 AGE->got_patch_info = cfg->patch_info;
344 AGE->next = cfg->arch.got_data;
346 cfg->arch.got_data = AGE;
349 /*------------------------------------------------------------------*/
351 /* Name - mono_arch_create_vars */
358 * cfg - pointer to compile unit
361 * This method is called right before starting converting compiled
362 * method to IR. I guess we could find out how many arguments we
363 * should expect, what type and what return value would be.
364 * After that we could correct "cfg" structure, or "arch" part of
368 /*------------------------------------------------------------------*/
371 mono_arch_create_vars (MonoCompile *cfg)
373 MonoMethodSignature *sig;
376 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
378 sig = mono_method_signature (cfg->method);
380 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
382 if (cinfo->ret.storage == ArgValuetypeInReg)
383 cfg->ret_var_is_local = TRUE;
389 /*------------------------------------------------------------------*/
391 /* Name - mono_arch_get_lmf_addr */
397 /*------------------------------------------------------------------*/
400 mono_arch_get_lmf_addr (void)
402 ALPHA_DEBUG("mono_arch_get_lmf_addr");
404 return pthread_getspecific (lmf_addr_key);
407 /*========================= End of Function ========================*/
409 /*------------------------------------------------------------------*/
411 /* Name - mono_arch_free_jit_tls_data */
413 /* Function - Free tls data. */
415 /*------------------------------------------------------------------*/
418 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
420 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
423 /*========================= End of Function ========================*/
425 // This peephole function is called before "local_regalloc" method
426 // TSV_TODO - Check what we need to move here
428 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
430 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_1 pass\n");
433 // This peephole function is called after "local_regalloc" method
435 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
439 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_2 pass\n");
441 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
442 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
450 * OP_MOVE reg, reg except special case (mov at, at)
452 if (ins->dreg == ins->sreg1 &&
453 ins->dreg != alpha_at)
455 MONO_DELETE_INS (bb, ins);
465 if (last_ins && last_ins->opcode == OP_MOVE &&
466 ins->sreg1 == last_ins->dreg &&
467 last_ins->dreg != alpha_at &&
468 ins->dreg == last_ins->sreg1)
470 MONO_DELETE_INS (bb, ins);
477 /* remove unnecessary multiplication with 1 */
478 if (ins->inst_imm == 1)
480 if (ins->dreg != ins->sreg1)
482 ins->opcode = OP_MOVE;
486 MONO_DELETE_INS (bb, ins);
493 case OP_LOADI8_MEMBASE:
494 case OP_LOAD_MEMBASE:
496 * Note: if reg1 = reg2 the load op is removed
498 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
499 * OP_LOADI8_MEMBASE offset(basereg), reg2
501 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
505 (last_ins->opcode == OP_STOREI8_MEMBASE_REG ||
506 last_ins->opcode == OP_STORE_MEMBASE_REG) &&
507 ins->inst_basereg == last_ins->inst_destbasereg &&
508 ins->inst_offset == last_ins->inst_offset)
510 if (ins->dreg == last_ins->sreg1)
512 MONO_DELETE_INS (bb, ins);
517 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
518 ins->opcode = OP_MOVE;
519 ins->sreg1 = last_ins->sreg1;
525 case OP_LOAD_MEMBASE:
526 case OP_LOADI4_MEMBASE:
528 * Note: if reg1 = reg2 the load op is removed
530 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
531 * OP_LOAD_MEMBASE offset(basereg), reg2
533 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
536 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
537 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
538 ins->inst_basereg == last_ins->inst_destbasereg &&
539 ins->inst_offset == last_ins->inst_offset)
541 if (ins->dreg == last_ins->sreg1)
543 MONO_DELETE_INS (bb, ins);
548 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
549 ins->opcode = OP_MOVE;
550 ins->sreg1 = last_ins->sreg1;
554 * Note: reg1 must be different from the basereg in the second load
555 * Note: if reg1 = reg2 is equal then second load is removed
557 * OP_LOAD_MEMBASE offset(basereg), reg1
558 * OP_LOAD_MEMBASE offset(basereg), reg2
560 * OP_LOAD_MEMBASE offset(basereg), reg1
564 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
565 || last_ins->opcode == OP_LOAD_MEMBASE) &&
566 ins->inst_basereg != last_ins->dreg &&
567 ins->inst_basereg == last_ins->inst_basereg &&
568 ins->inst_offset == last_ins->inst_offset)
570 if (ins->dreg == last_ins->dreg)
572 MONO_DELETE_INS (bb, ins);
577 ins->opcode = OP_MOVE;
578 ins->sreg1 = last_ins->dreg;
581 //g_assert_not_reached ();
589 // Convert to opposite branch opcode
590 static guint16 cvt_branch_opcode(guint16 opcode)
595 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
600 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
604 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
608 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
612 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
616 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
620 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
624 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
628 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
632 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
636 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
640 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
644 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
648 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
652 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
656 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
660 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
664 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
668 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
672 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
676 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
680 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
684 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
688 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
692 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
699 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
704 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
706 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
712 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
723 return OP_ALPHA_CMP_EQ;
725 return OP_ALPHA_CMP_ULE;
727 return OP_ALPHA_CMP_LE;
729 return OP_ALPHA_CMP_LT;
731 return OP_ALPHA_CMP_ULT;
736 case OP_ICOMPARE_IMM:
742 return OP_ALPHA_CMP_IMM_EQ;
744 return OP_ALPHA_CMP_IMM_ULE;
746 return OP_ALPHA_CMP_IMM_LE;
748 return OP_ALPHA_CMP_IMM_LT;
750 return OP_ALPHA_CMP_IMM_ULT;
755 g_assert_not_reached();
760 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
762 // Instead of compare+b<cond>,
763 // Alpha has compare<cond>+br<cond>
764 // we need to convert
765 // Handle floating compare here too
771 // Convert cmp + beq -> cmpeq + bne
772 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
773 next->opcode = cvt_branch_opcode(next->opcode);
778 // cmp + ibne_un -> cmpeq + beq
779 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
780 next->opcode = cvt_branch_opcode(next->opcode);
785 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
786 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
787 next->opcode = cvt_branch_opcode(next->opcode);
792 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
793 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
794 next->opcode = cvt_branch_opcode(next->opcode);
799 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
800 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
801 next->opcode = cvt_branch_opcode(next->opcode);
806 // lcmp + blt.un -> cmpult + bne
807 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
808 next->opcode = cvt_branch_opcode(next->opcode);
813 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
814 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
815 next->opcode = cvt_branch_opcode(next->opcode);
820 //lcmp + bge.un -> cmpult + beq
821 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
822 next->opcode = cvt_branch_opcode(next->opcode);
827 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
828 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
829 next->opcode = cvt_branch_opcode(next->opcode);
834 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
835 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
836 next->opcode = cvt_branch_opcode(next->opcode);
842 // cmp + cgt_un -> cmpule + beq
843 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
848 // cmp + iceq -> cmpeq + bne
849 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
854 // cmp + int_cgt -> cmple + beq
855 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
860 // cmp + int_clt -> cmplt + bne
861 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
866 // cmp + int_clt_un -> cmpult + bne
867 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
871 // The conditional exceptions will be handled in
872 // output_basic_blocks. Here we just determine correct
875 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
878 case OP_COND_EXC_GT_UN:
879 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
883 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
886 case OP_COND_EXC_LT_UN:
887 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
890 case OP_COND_EXC_LE_UN:
891 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
894 case OP_COND_EXC_NE_UN:
895 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
899 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
904 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
905 mono_inst_name(next->opcode), next->opcode);
907 // g_assert_not_reached();
915 * mono_arch_lowering_pass:
917 * Converts complex opcodes into simpler ones so that each IR instruction
918 * corresponds to one machine instruction.
921 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
923 MonoInst *ins, *n, *next, *temp;
925 if (bb->max_vreg > cfg->rs->next_vreg)
926 cfg->rs->next_vreg = bb->max_vreg;
929 * FIXME: Need to add more instructions, but the current machine
930 * description can't model some parts of the composite instructions like
934 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
942 NEW_INS (cfg, ins, temp, OP_I8CONST);
943 temp->inst_c0 = ins->inst_imm;
944 temp->dreg = mono_regstate_next_int (cfg->rs);
949 ins->opcode = CEE_MUL;
952 ins->opcode = OP_LDIV;
955 ins->opcode = OP_LREM;
958 ins->opcode = OP_IDIV;
961 ins->opcode = OP_IREM;
965 ins->sreg2 = temp->dreg;
973 // Instead of compare+b<cond>/fcompare+b<cond>,
974 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
975 // we need to convert
976 next = mono_inst_list_next (&ins->node, &bb->ins_list);
979 cvt_cmp_branch(ins, next);
984 if (!alpha_is_imm (ins->inst_imm))
986 NEW_INS (cfg, ins, temp, OP_I8CONST);
987 temp->inst_c0 = ins->inst_imm;
988 temp->dreg = mono_regstate_next_int (cfg->rs);
989 ins->opcode = OP_COMPARE;
990 ins->sreg2 = temp->dreg;
992 // We should try to reevaluate new IR opcode
996 next = mono_inst_list_next (&ins->node, &bb->ins_list);
999 cvt_cmp_branch(ins, next);
1003 case OP_ICOMPARE_IMM:
1004 if (!alpha_is_imm (ins->inst_imm))
1006 NEW_INS (cfg, ins, temp, OP_ICONST);
1007 temp->inst_c0 = ins->inst_imm;
1008 temp->dreg = mono_regstate_next_int (cfg->rs);
1009 ins->opcode = OP_ICOMPARE;
1010 ins->sreg2 = temp->dreg;
1012 // We should try to reevaluate new IR opcode
1016 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1019 cvt_cmp_branch(ins, next);
1023 case OP_STORE_MEMBASE_IMM:
1024 case OP_STOREI8_MEMBASE_IMM:
1025 if (ins->inst_imm != 0)
1027 NEW_INS (cfg, ins, temp, OP_I8CONST);
1028 temp->inst_c0 = ins->inst_imm;
1029 temp->dreg = mono_regstate_next_int (cfg->rs);
1030 ins->opcode = OP_STOREI8_MEMBASE_REG;
1031 ins->sreg1 = temp->dreg;
1035 case OP_STOREI4_MEMBASE_IMM:
1036 if (ins->inst_imm != 0)
1039 NEW_INS (cfg, ins, temp, OP_ICONST);
1040 temp->inst_c0 = ins->inst_imm;
1041 temp->dreg = mono_regstate_next_int (cfg->rs);
1042 ins->opcode = OP_STOREI4_MEMBASE_REG;
1043 ins->sreg1 = temp->dreg;
1047 case OP_STOREI1_MEMBASE_IMM:
1048 if (ins->inst_imm != 0 || !bwx_supported)
1051 NEW_INS (cfg, ins, temp, OP_ICONST);
1052 temp->inst_c0 = ins->inst_imm;
1053 temp->dreg = mono_regstate_next_int (cfg->rs);
1054 ins->opcode = OP_STOREI1_MEMBASE_REG;
1055 ins->sreg1 = temp->dreg;
1059 case OP_STOREI2_MEMBASE_IMM:
1060 if (ins->inst_imm != 0 || !bwx_supported)
1063 NEW_INS (cfg, ins, temp, OP_ICONST);
1064 temp->inst_c0 = ins->inst_imm;
1065 temp->dreg = mono_regstate_next_int (cfg->rs);
1066 ins->opcode = OP_STOREI2_MEMBASE_REG;
1067 ins->sreg1 = temp->dreg;
1078 case OP_ISHR_UN_IMM:
1079 if (!alpha_is_imm(ins->inst_imm))
1082 NEW_INS (cfg, ins, temp, OP_ICONST);
1083 temp->inst_c0 = ins->inst_imm;
1084 temp->dreg = mono_regstate_next_int (cfg->rs);
1089 ins->opcode = OP_IADD;
1092 ins->opcode = OP_ISUB;
1095 ins->opcode = OP_IAND;
1098 ins->opcode = OP_IOR;
1101 ins->opcode = OP_IXOR;
1104 ins->opcode = OP_ISHL;
1107 ins->opcode = OP_ISHR;
1109 case OP_ISHR_UN_IMM:
1110 ins->opcode = OP_ISHR_UN;
1116 ins->sreg2 = temp->dreg;
1122 if (!alpha_is_imm(ins->inst_imm))
1125 NEW_INS (cfg, ins, temp, OP_ICONST);
1126 temp->inst_c0 = ins->inst_imm;
1127 temp->dreg = mono_regstate_next_int (cfg->rs);
1132 ins->opcode = CEE_ADD;
1135 ins->opcode = CEE_SUB;
1138 ins->opcode = CEE_AND;
1141 ins->opcode = CEE_SHL;
1147 ins->sreg2 = temp->dreg;
1151 if (!alpha_is_imm(ins->inst_imm))
1154 NEW_INS(cfg, ins, temp, OP_ICONST);
1155 temp->inst_c0 = ins->inst_imm;
1156 temp->dreg = mono_regstate_next_int(cfg->rs);
1157 ins->sreg2 = temp->dreg;
1158 ins->opcode = OP_LSHR;
1162 if (!alpha_is_imm(ins->inst_imm))
1165 NEW_INS(cfg, ins, temp, OP_ICONST);
1166 temp->inst_c0 = ins->inst_imm;
1167 temp->dreg = mono_regstate_next_int(cfg->rs);
1168 ins->sreg2 = temp->dreg;
1169 ins->opcode = OP_LSHL;
1178 bb->max_vreg = cfg->rs->next_vreg;
1181 /*========================= End of Function ========================*/
1183 #define AXP_GENERAL_REGS 6
1184 #define AXP_MIN_STACK_SIZE 24
1186 /* A typical Alpha stack frame looks like this */
1188 fun: // called from outside the module.
1189 ldgp gp,0(pv) // load the global pointer
1190 fun..ng: // called from inside the module.
1191 lda sp, -SIZE( sp ) // grow the stack downwards.
1193 stq ra, 0(sp) // save the return address.
1195 stq s0, 8(sp) // callee-saved registers.
1196 stq s1, 16(sp) // ...
1198 // Move the arguments to the argument registers...
1200 mov addr, pv // Load the callee address
1201 jsr ra, (pv) // call the method.
1202 ldgp gp, 0(ra) // restore gp
1204 // return value is in v0
1206 ldq ra, 0(sp) // free stack frame
1207 ldq s0, 8(sp) // restore callee-saved registers.
1209 ldq sp, 32(sp) // restore stack pointer
1211 ret zero, (ra), 1 // return.
1214 // our call must look like this.
1220 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1221 stq ra, SIZE-48(sp) // store ra
1222 stq fp, SIZE-40(sp) // store fp (frame pointer)
1223 stq a0, SIZE-32(sp) // store args. a0 = func
1224 stq a1, SIZE-24(sp) // a1 = retval
1225 stq a2, SIZE-16(sp) // a2 = this
1226 stq a3, SIZE-8(sp) // a3 = args
1227 mov sp, fp // set frame pointer
1247 jsr ra, (pv) // call func
1248 ldgp gp, 0(ra) // restore gp.
1249 mov v0, t1 // move return value into t1
1252 ldq t0, SIZE-24(fp) // load retval into t2
1253 stl t1, 0(t0) // store value.
1264 * emit_load_volatile_arguments:
1266 * Load volatile arguments from the stack to the original input registers.
1267 * Required before a tail call.
1269 static unsigned int*
1270 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1272 MonoMethod *method = cfg->method;
1273 MonoMethodSignature *sig;
1278 /* FIXME: Generate intermediate code instead */
1280 sig = mono_method_signature (method);
1282 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1284 if (sig->ret->type != MONO_TYPE_VOID) {
1285 if ((cinfo->ret.storage == ArgInIReg) &&
1286 (cfg->ret->opcode != OP_REGVAR))
1288 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1289 cfg->ret->inst_offset);
1293 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1295 ArgInfo *ainfo = &cinfo->args [i];
1296 MonoInst *inst = cfg->args [i];
1298 switch(ainfo->storage)
1301 // We need to save all used a0-a5 params
1302 //for (i=0; i<PARAM_REGS; i++)
1304 // if (i < cinfo->reg_usage)
1306 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1307 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1309 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1310 ainfo->reg, inst->inst_offset/*offset*/);
1314 case ArgInDoubleReg:
1316 // We need to save all used af0-af5 params
1317 //for (i=0; i<PARAM_REGS; i++)
1319 // if (i < cinfo->freg_usage)
1321 switch(cinfo->args[i].storage)
1324 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1325 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1327 case ArgInDoubleReg:
1328 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1329 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1335 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1336 ainfo->reg, /*offset*/inst->inst_offset);
1345 /*------------------------------------------------------------------*/
1347 /* Name - mono_arch_emit_prolog */
1349 /* Function - Create the instruction sequence for a function */
1352 * How to handle consts and method addreses:
1353 * For method we will allocate array of qword after method epiloge.
1354 * These qword will hold readonly info to method to properly to run.
1355 * For example: qword constants, method addreses
1356 * GP will point to start of data. Offsets to the data will be equal
1357 * to "address" of data - start of GP. (GP = 0 during method jiting).
1358 * GP is easily calculated from passed PV (method start address).
1359 * The patch will update GP loadings.
1360 * The GOT section should be more than 32Kb.
1361 * The patch code should put proper offset since the real position of
1362 * qword array will be known after the function epiloge.
1364 /*------------------------------------------------------------------*/
1367 mono_arch_emit_prolog (MonoCompile *cfg)
1369 MonoMethod *method = cfg->method;
1370 MonoMethodSignature *sig = mono_method_signature (method);
1371 //int alloc_size, code_size, max_offset, quad;
1374 int i, stack_size, offset;
1375 gint32 lmf_offset = cfg->arch.lmf_offset;
1377 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1379 // FIXME: Use just one field to hold calculated stack size
1380 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1381 cfg->arch.got_data = 0;
1383 cfg->code_size = 512;
1385 code = (unsigned int *)g_malloc(cfg->code_size);
1386 cfg->native_code = (void *)code;
1388 // Emit method prolog
1389 // Calculate GP from passed PV, allocate stack
1391 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1392 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1393 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1395 offset = cfg->arch.params_stack_size;
1397 /* store call convention parameters on stack */
1398 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1399 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1401 /* set the frame pointer */
1402 alpha_mov1( code, alpha_sp, alpha_fp );
1405 if (method->save_lmf)
1408 alpha_stq(code, alpha_pv, alpha_fp,
1409 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1411 alpha_stq(code, alpha_sp, alpha_fp,
1412 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1414 alpha_stq(code, alpha_fp, alpha_fp,
1415 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1417 alpha_stq(code, alpha_gp, alpha_fp,
1418 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1421 alpha_stq(code, alpha_pv, alpha_fp,
1422 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1425 /* Save (global) regs */
1426 offset = cfg->arch.reg_save_area_offset;
1428 for (i = 0; i < MONO_MAX_IREGS; ++i)
1429 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1430 (cfg->used_int_regs & (1 << i)) &&
1431 !( ALPHA_ARGS_REGS & (1 << i)) )
1433 alpha_stq(code, i, alpha_fp, offset);
1434 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1439 offset = cfg->arch.args_save_area_offset;
1441 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1443 if (sig->ret->type != MONO_TYPE_VOID)
1445 if ((cinfo->ret.storage == ArgInIReg) &&
1446 (cfg->ret->opcode != OP_REGVAR))
1448 /* Save volatile arguments to the stack */
1449 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1450 cfg->ret->inst_offset);
1454 /* Keep this in sync with emit_load_volatile_arguments */
1455 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1457 ArgInfo *ainfo = &cinfo->args [i];
1458 MonoInst *inst = cfg->args [i];
1461 switch(ainfo->storage)
1464 // We need to save all used a0-a5 params
1466 if (inst->opcode == OP_REGVAR)
1468 alpha_mov1(code, ainfo->reg, inst->dreg);
1469 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1470 ainfo->reg, inst->dreg);
1474 alpha_stq(code, ainfo->reg, inst->inst_basereg,
1477 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1478 ainfo->reg, inst->inst_offset);
1486 for(j=0; j<ainfo->nregs; j++)
1488 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1489 ainfo->reg + j, inst->inst_offset + (8*j));
1490 alpha_stq(code, (ainfo->reg+j), inst->inst_basereg,
1491 (inst->inst_offset + (8*j)));
1496 case ArgInDoubleReg:
1498 // We need to save all used af0-af5 params
1500 switch(cinfo->args[i].storage)
1503 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1504 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1506 case ArgInDoubleReg:
1507 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1508 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1514 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1515 ainfo->reg, /*offset*/inst->inst_offset);
1522 offset = cfg->arch.reg_save_area_offset;
1525 for (i = 0; i < MONO_MAX_VREGS; ++i)
1526 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1527 (cfg->used_int_regs & (1 << i)) &&
1528 !( ALPHA_ARGS_REGS & (1 << i)) )
1530 alpha_stq(code, i, alpha_fp, offset);
1531 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1536 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1538 if (method->save_lmf)
1541 * The call might clobber argument registers, but they are already
1542 * saved to the stack/global regs.
1545 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1546 (gpointer)"mono_get_lmf_addr");
1549 alpha_stq(code, alpha_r0, alpha_fp,
1550 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1551 // Load "previous_lmf" member of MonoLMF struct
1552 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1554 // Save it to MonoLMF struct
1555 alpha_stq(code, alpha_r1, alpha_fp,
1556 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1559 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1560 alpha_stq(code, alpha_r1, alpha_r0, 0);
1565 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1566 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1569 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1571 g_assert (cfg->code_len < cfg->code_size);
1573 return (gint8 *)code;
1576 /*========================= End of Function ========================*/
1578 /*------------------------------------------------------------------*/
1580 /* Name - mono_arch_flush_register_windows */
1586 /*------------------------------------------------------------------*/
1589 mono_arch_flush_register_windows (void)
1591 ALPHA_DEBUG("mono_arch_flush_register_windows");
1593 /*========================= End of Function ========================*/
1595 /*------------------------------------------------------------------*/
1597 /* Name - mono_arch_regalloc_cost */
1599 /* Function - Determine the cost, in the number of memory */
1600 /* references, of the action of allocating the var- */
1601 /* iable VMV into a register during global register */
1604 /* Returns - Cost */
1606 /*------------------------------------------------------------------*/
1609 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1611 MonoInst *ins = cfg->varinfo [vmv->idx];
1614 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1616 if (cfg->method->save_lmf)
1617 /* The register is already saved */
1618 /* substract 1 for the invisible store in the prolog */
1619 return (ins->opcode == OP_ARG) ? 1 : 0;
1622 return (ins->opcode == OP_ARG) ? 2 : 1;
1625 /*========================= End of Function ========================*/
1629 ** This method emits call sequience
1632 static unsigned int *
1633 emit_call(MonoCompile *cfg, unsigned int *code,
1634 guint32 patch_type, gconstpointer data)
1637 AlphaGotData ge_data;
1639 offset = (char *)code - (char *)cfg->native_code;
1641 ge_data.data.p = (void *)data;
1642 add_got_entry(cfg, GT_PTR, ge_data,
1643 offset, patch_type, data);
1645 // Load call address into PV
1646 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1649 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1651 offset = (char *)code - (char *)cfg->native_code;
1654 ALPHA_LOAD_GP(offset)
1655 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1656 alpha_lda(code, alpha_gp, alpha_gp, 0);
1661 /*------------------------------------------------------------------*/
1663 /* Name - arch_get_argument_info */
1665 /* Function - Gathers information on parameters such as size, */
1666 /* alignment, and padding. arg_info should be large */
1667 /* enough to hold param_count + 1 entries. */
1669 /* Parameters - @csig - Method signature */
1670 /* @param_count - No. of parameters to consider */
1671 /* @arg_info - An array to store the result info */
1673 /* Returns - Size of the activation frame */
1675 /*------------------------------------------------------------------*/
1678 mono_arch_get_argument_info (MonoMethodSignature *csig,
1680 MonoJitArgumentInfo *arg_info)
1683 CallInfo *cinfo = get_call_info (NULL, csig, FALSE);
1684 guint32 args_size = cinfo->stack_usage;
1686 ALPHA_DEBUG("mono_arch_get_argument_info");
1688 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1691 arg_info [0].offset = 0;
1694 for (k = 0; k < param_count; k++)
1696 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1700 // The size is checked only for valuetype in trace.c
1701 arg_info [k + 1].size = 8;
1709 /*------------------------------------------------------------------*/
1711 /* Name - mono_arch_emit_epilog */
1713 /* Function - Emit the instructions for a function epilog. */
1715 /*------------------------------------------------------------------*/
1718 mono_arch_emit_epilog (MonoCompile *cfg)
1720 MonoMethod *method = cfg->method;
1723 int max_epilog_size = 128;
1724 int stack_size = cfg->arch.stack_size;
1726 gint32 lmf_offset = cfg->arch.lmf_offset;
1728 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1730 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1732 cfg->code_size *= 2;
1733 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1734 mono_jit_stats.code_reallocs++;
1737 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1739 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1740 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1743 if (method->save_lmf)
1745 /* Restore previous lmf */
1746 alpha_ldq(code, alpha_at, alpha_fp,
1747 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1748 alpha_ldq(code, alpha_ra, alpha_fp,
1749 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1750 alpha_stq(code, alpha_at, alpha_ra, 0);
1754 alpha_mov1( code, alpha_fp, alpha_sp );
1756 // Restore saved regs
1757 offset = cfg->arch.reg_save_area_offset;
1759 for (i = 0; i < MONO_MAX_IREGS; ++i)
1760 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1761 (cfg->used_int_regs & (1 << i)) &&
1762 !( ALPHA_ARGS_REGS & (1 << i)) )
1764 alpha_ldq(code, i, alpha_sp, offset);
1765 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1770 /* restore fp, ra, sp */
1771 offset = cfg->arch.params_stack_size;
1773 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1774 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1775 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1778 alpha_ret( code, alpha_ra, 1 );
1780 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1782 g_assert (cfg->code_len < cfg->code_size);
1785 /*========================= End of Function ========================*/
1787 /*------------------------------------------------------------------*/
1789 /* Name - mono_arch_emit_exceptions */
1791 /* Function - Emit the blocks to handle exception conditions. */
1793 /*------------------------------------------------------------------*/
1796 mono_arch_emit_exceptions (MonoCompile *cfg)
1798 MonoJumpInfo *patch_info;
1800 unsigned int *code, *got_start;
1801 unsigned long *corlib_exc_adr;
1802 MonoClass *exc_classes [16];
1803 guint8 *exc_throw_start [16], *exc_throw_end [16];
1804 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1805 AlphaGotEntry *got_data;
1807 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1809 /* Compute needed space */
1810 for (patch_info = cfg->patch_info; patch_info;
1811 patch_info = patch_info->next)
1813 if (patch_info->type == MONO_PATCH_INFO_EXC)
1815 if (patch_info->type == MONO_PATCH_INFO_R8)
1816 code_size += 8 + 7; /* sizeof (double) + alignment */
1817 if (patch_info->type == MONO_PATCH_INFO_R4)
1818 code_size += 4 + 7; /* sizeof (float) + alignment */
1821 // Reserve space for GOT entries
1822 for (got_data = cfg->arch.got_data; got_data;
1823 got_data = got_data->next)
1825 // Reserve space for 8 byte const (for now)
1826 if (got_data->type != GT_LD_GTADDR)
1830 while (cfg->code_len + code_size > (cfg->code_size - 16))
1832 cfg->code_size *= 2;
1833 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1834 mono_jit_stats.code_reallocs++;
1837 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1839 // Set code alignment
1840 if (((unsigned long)code) % 8)
1845 /* Add code to store conts and modify patch into to store offset in got */
1846 for (got_data = cfg->arch.got_data; got_data;
1847 got_data = got_data->next)
1849 unsigned long data = got_data->value.data.l;
1850 MonoJumpInfo *got_ref = got_data->got_patch_info;
1852 // Modify loading of GP
1853 if (got_data->type == GT_LD_GTADDR)
1855 short high_off, low_off;
1856 unsigned int *ldgp_code =
1857 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1858 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1860 high_off = got_off / 0x10000;
1861 low_off = got_off % 0x10000;
1865 // Set offset from current point to GOT array
1866 // modify the following code sequence
1867 // ldah gp, 0(pv) or ldah gp, 0(ra)
1869 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1871 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1876 patch_info = got_data->patch_info;
1878 // Check code alignment
1879 if (((unsigned long)code) % 8)
1882 got_ref->data.offset = ((char *)code - (char *)got_start);
1885 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1887 *code = (unsigned int)(data & 0xFFFFFFFF);
1889 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1894 corlib_exc_adr = (unsigned long *)code;
1896 /* add code to raise exceptions */
1898 for (patch_info = cfg->patch_info; patch_info;
1899 patch_info = patch_info->next)
1901 switch (patch_info->type)
1903 case MONO_PATCH_INFO_EXC:
1905 MonoClass *exc_class;
1906 unsigned int *buf, *buf2;
1911 // Add patch info to call mono_arch_throw_corlib_exception
1912 // method to raise corlib exception
1913 // Will be added at the begining of the patch info list
1914 mono_add_patch_info(cfg,
1915 ((char *)code - (char *)cfg->native_code),
1916 MONO_PATCH_INFO_INTERNAL_METHOD,
1917 "mono_arch_throw_corlib_exception");
1919 // Skip longword before starting the code
1924 exc_class = mono_class_from_name (mono_defaults.corlib,
1925 "System", patch_info->data.name);
1927 g_assert (exc_class);
1928 throw_ip = patch_info->ip.i;
1930 //x86_breakpoint (code);
1931 /* Find a throw sequence for the same exception class */
1932 for (i = 0; i < nthrows; ++i)
1933 if (exc_classes [i] == exc_class)
1940 // Patch original branch (patch info) to jump here
1941 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1942 patch_info->data.target =
1943 (char *)code - (char *)cfg->native_code;
1945 alpha_lda(code, alpha_a1, alpha_zero,
1946 -((short)((((char *)exc_throw_end[i] -
1947 (char *)cfg->native_code)) - throw_ip) - 4) );
1949 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
1951 alpha_bsr(code, alpha_zero, br_offset);
1957 // Save exception token type as first 32bit word for new
1958 // exception handling jump code
1959 *code = exc_class->type_token;
1962 // Patch original branch (patch info) to jump here
1963 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1964 patch_info->data.target =
1965 (char *)code - (char *)cfg->native_code;
1968 alpha_lda(code, alpha_a1, alpha_zero, 0);
1972 exc_classes [nthrows] = exc_class;
1973 exc_throw_start [nthrows] = code;
1976 // Load exception token
1977 alpha_ldl(code, alpha_a0, alpha_gp,
1978 ((char *)buf - (char *)got_start /*cfg->native_code*/));
1979 // Load corlib exception raiser code address
1980 alpha_ldq(code, alpha_pv, alpha_gp,
1981 ((char *)corlib_exc_adr -
1982 (char *)got_start /*cfg->native_code*/));
1984 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
1985 //patch_info->data.name = "mono_arch_throw_corlib_exception";
1986 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
1987 //patch_info->type = MONO_PATCH_INFO_NONE;
1988 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
1990 if (cfg->compile_aot)
1992 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
1993 //amd64_call_reg (code, GP_SCRATCH_REG);
1995 /* The callee is in memory allocated using
1997 alpha_jsr(code, alpha_ra, alpha_pv, 0);
2000 alpha_lda(buf2, alpha_a1, alpha_zero,
2001 -((short)(((char *)code - (char *)cfg->native_code) -
2006 exc_throw_end [nthrows] = code;
2018 /* Handle relocations with RIP relative addressing */
2019 for (patch_info = cfg->patch_info; patch_info;
2020 patch_info = patch_info->next)
2022 gboolean remove = FALSE;
2024 switch (patch_info->type)
2026 case MONO_PATCH_INFO_R8:
2030 code = (guint8*)ALIGN_TO (code, 8);
2032 pos = cfg->native_code + patch_info->ip.i;
2034 *(double*)code = *(double*)patch_info->data.target;
2037 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2039 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2045 case MONO_PATCH_INFO_R4:
2049 code = (guint8*)ALIGN_TO (code, 8);
2051 pos = cfg->native_code + patch_info->ip.i;
2053 *(float*)code = *(float*)patch_info->data.target;
2056 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2058 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2070 if (patch_info == cfg->patch_info)
2071 cfg->patch_info = patch_info->next;
2076 for (tmp = cfg->patch_info; tmp->next != patch_info;
2079 tmp->next = patch_info->next;
2084 cfg->code_len = (char *)code - (char *)cfg->native_code;
2086 g_assert (cfg->code_len < cfg->code_size);
2090 /*========================= End of Function ========================*/
2092 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2093 offset = ((char *)code - \
2094 (char *)cfg->native_code); \
2095 if (Tins->flags & MONO_INST_BRLABEL) \
2097 if (Tins->inst_i0->inst_c0) \
2099 CFG_DEBUG(3) g_print("inst_c0: %0lX, data: %p]\n", \
2100 Tins->inst_i0->inst_c0, \
2101 cfg->native_code + Tins->inst_i0->inst_c0); \
2102 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2106 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n", \
2107 offset, Tins->inst_i0); \
2108 mono_add_patch_info (cfg, offset, \
2109 MONO_PATCH_INFO_LABEL, Tins->inst_i0); \
2110 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2115 if (Tins->inst_true_bb->native_offset) \
2117 long br_offset = (char *)cfg->native_code + \
2118 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2119 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2120 Tins->inst_target_bb->native_offset, \
2121 cfg->native_code + \
2122 Tins->inst_true_bb->native_offset); \
2123 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2127 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2128 offset, Tins->inst_target_bb); \
2129 mono_add_patch_info (cfg, offset, \
2130 MONO_PATCH_INFO_BB, \
2131 Tins->inst_true_bb); \
2132 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2137 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2140 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2145 mono_add_patch_info (cfg, \
2147 (char *)cfg->native_code), \
2148 MONO_PATCH_INFO_EXC, EXC_NAME); \
2149 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2153 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2158 /*------------------------------------------------------------------*/
2160 /* Name - mono_arch_output_basic_block */
2162 /* Function - Perform the "real" work of emitting instructions */
2163 /* that will do the work of in the basic block. */
2165 /*------------------------------------------------------------------*/
2168 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2173 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2174 guint last_offset = 0;
2177 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2179 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2180 bb->block_num, bb, bb->native_offset);
2182 cpos = bb->max_offset;
2184 offset = ((char *)code) - ((char *)cfg->native_code);
2186 mono_debug_open_block (cfg, bb, offset);
2188 MONO_BB_FOR_EACH_INS (bb, ins) {
2189 offset = ((char *)code) - ((char *)cfg->native_code);
2191 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2193 if (offset > (cfg->code_size - max_len - 16))
2195 cfg->code_size *= 2;
2196 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2197 code = (unsigned int *)(cfg->native_code + offset);
2198 mono_jit_stats.code_reallocs++;
2201 mono_debug_record_line_number (cfg, ins, offset);
2203 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2204 mono_inst_name(ins->opcode));
2206 switch (ins->opcode)
2209 // Shift 64 bit value right
2210 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2211 ins->dreg, ins->sreg1, ins->sreg2);
2212 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2216 // Shift 64 bit value right
2217 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2218 ins->dreg, ins->sreg1, ins->sreg2);
2219 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2223 // Shift 64 bit value right by constant
2224 g_assert(alpha_is_imm(ins->inst_imm));
2225 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2226 ins->dreg, ins->sreg1, ins->inst_imm);
2227 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2231 // Shift 32 bit value left
2232 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2233 ins->dreg, ins->sreg1, ins->sreg2);
2234 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2235 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2239 // Shift 32 bit value left by constant
2240 g_assert(alpha_is_imm(ins->inst_imm));
2241 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2242 ins->dreg, ins->sreg1, ins->inst_imm);
2243 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2244 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2248 g_assert(alpha_is_imm(ins->inst_imm));
2249 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2250 ins->dreg, ins->sreg1, ins->inst_imm);
2251 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2255 g_assert(alpha_is_imm(ins->inst_imm));
2256 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2257 ins->dreg, ins->sreg1, ins->inst_imm);
2258 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2263 // Shift 32 bit value left
2264 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2265 ins->dreg, ins->sreg1, ins->sreg2);
2266 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2270 // Shift 64 bit value left
2271 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2272 ins->dreg, ins->sreg1, ins->sreg2);
2273 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2278 // Shift 32 bit value right
2279 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2280 ins->dreg, ins->sreg1, ins->sreg2);
2281 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2282 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2286 // Shift 32 bit value rigth by constant
2287 g_assert(alpha_is_imm(ins->inst_imm));
2288 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2289 ins->dreg, ins->sreg1, ins->inst_imm);
2290 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2291 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2295 // Shift 32 bit unsigned value right
2296 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2297 ins->dreg, ins->sreg1, ins->sreg2);
2298 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2299 alpha_srl(code, alpha_at /*ins->dreg*/, ins->sreg2, ins->dreg);
2302 case OP_ISHR_UN_IMM:
2303 // Shift 32 bit unassigned value rigth by constant
2304 g_assert(alpha_is_imm(ins->inst_imm));
2305 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2306 ins->dreg, ins->sreg1, ins->inst_imm);
2307 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2308 alpha_srl_(code, alpha_at /*ins->dreg*/, ins->inst_imm, ins->dreg);
2311 case OP_LSHR_UN_IMM:
2312 // Shift 64 bit unassigned value rigth by constant
2313 g_assert(alpha_is_imm(ins->inst_imm));
2314 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2315 ins->dreg, ins->sreg1, ins->inst_imm);
2316 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2320 // Sum two 64 bits regs
2321 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2322 ins->dreg, ins->sreg1, ins->sreg2);
2323 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2327 // Subtract two 64 bit regs
2328 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2329 ins->dreg, ins->sreg1, ins->sreg2);
2330 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2334 // Add imm value to 64 bits int
2335 g_assert(alpha_is_imm(ins->inst_imm));
2336 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2337 ins->dreg, ins->sreg1, ins->inst_imm);
2338 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2342 // Add two 32 bit ints
2343 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2344 ins->dreg, ins->sreg1, ins->sreg2);
2345 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2349 // Add two 32 bit ints with overflow detection
2350 // Use AT to hold flag of signed overflow
2351 // Use t12(PV) to hold unsigned overflow
2352 // Use RA to hold intermediate result
2353 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2354 ins->dreg, ins->sreg1, ins->sreg2);
2355 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2356 alpha_ble(code, ins->sreg2, 2);
2358 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2359 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2360 alpha_br(code, alpha_zero, 1);
2362 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2363 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2365 /* res <u sreg1 => unsigned overflow */
2366 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2368 alpha_mov1(code, alpha_ra, ins->dreg);
2372 // Add two 64 bit ints with overflow detection
2373 // Use AT to hold flag of signed overflow
2374 // Use t12(PV) to hold unsigned overflow
2375 // Use RA to hold intermediate result
2376 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2377 ins->dreg, ins->sreg1, ins->sreg2);
2378 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2379 alpha_ble(code, ins->sreg2, 2);
2381 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2382 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2383 alpha_br(code, alpha_zero, 1);
2385 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2386 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2388 /* res <u sreg1 => unsigned overflow */
2389 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2391 alpha_mov1(code, alpha_ra, ins->dreg);
2395 // Add imm value to 32 bits int
2396 g_assert(alpha_is_imm(ins->inst_imm));
2397 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2398 ins->dreg, ins->sreg1, ins->inst_imm);
2399 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2403 // Substract to 32 bit ints
2404 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2405 ins->dreg, ins->sreg1, ins->sreg2);
2406 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2410 // Sub imm value from 32 bits int
2411 g_assert(alpha_is_imm(ins->inst_imm));
2412 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2413 ins->dreg, ins->sreg1, ins->inst_imm);
2414 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2418 // Sub to 32 bit ints with overflow detection
2419 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2420 ins->dreg, ins->sreg1, ins->sreg2);
2421 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2422 alpha_ble(code, ins->sreg2, 2);
2424 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2425 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2426 alpha_br(code, alpha_zero, 1);
2428 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2429 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2431 /* sreg1 <u sreg2 => unsigned overflow */
2432 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2434 alpha_mov1(code, alpha_ra, ins->dreg);
2438 // Sub to 64 bit ints with overflow detection
2439 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2440 ins->dreg, ins->sreg1, ins->sreg2);
2442 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2443 alpha_ble(code, ins->sreg2, 2);
2445 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2446 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2447 alpha_br(code, alpha_zero, 1);
2449 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2450 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2452 /* sreg1 <u sreg2 => unsigned overflow */
2453 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2455 alpha_mov1(code, alpha_ra, ins->dreg);
2460 // AND to 32 bit ints
2461 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2462 ins->dreg, ins->sreg1, ins->sreg2);
2463 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2468 // AND imm value with 32 bit int
2469 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2470 ins->dreg, ins->sreg1, ins->inst_imm);
2472 g_assert(alpha_is_imm(ins->inst_imm));
2473 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2479 // OR two 32/64 bit ints
2480 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2481 ins->dreg, ins->sreg1, ins->sreg2);
2482 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2486 // OR imm value with 32 bit int
2487 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2488 ins->dreg, ins->sreg1, ins->inst_imm);
2490 g_assert(alpha_is_imm(ins->inst_imm));
2491 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2497 // XOR two 32/64 bit ints
2498 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2499 ins->dreg, ins->sreg1, ins->sreg2);
2500 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2504 // XOR imm value with 32 bit int
2505 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2506 ins->dreg, ins->sreg1, ins->inst_imm);
2508 g_assert(alpha_is_imm(ins->inst_imm));
2509 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2515 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2516 ins->dreg, ins->sreg1);
2517 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2522 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2523 ins->dreg, ins->sreg1);
2524 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2529 // NOT 32/64 bit reg
2530 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2531 ins->dreg, ins->sreg1);
2532 alpha_not(code, ins->sreg1, ins->dreg);
2540 case OP_IMUL_OVF_UN:
2543 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",
2544 ins->dreg, ins->sreg1, ins->sreg2);
2548 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2549 ins->dreg, ins->sreg1, ins->sreg2);
2550 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2554 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2555 ins->dreg, ins->sreg1, ins->inst_imm);
2559 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2561 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2565 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2566 ins->dreg, ins->sreg1);
2567 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2568 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2572 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2573 ins->dreg, ins->sreg1);
2574 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2575 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2579 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2580 ins->dreg, ins->sreg1);
2581 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2582 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2586 // Actually ICONST is 32 bits long
2587 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2588 ins->dreg, ins->inst_c0);
2591 if (ins->inst_c0 == 0)
2593 alpha_clr(code, ins->dreg);
2597 // if -32768 < const <= 32767
2598 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2600 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2601 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2602 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2606 int lo = (char *)code - (char *)cfg->native_code;
2607 AlphaGotData ge_data;
2609 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2610 ge_data.data.l = ins->inst_c0;
2612 add_got_entry(cfg, GT_LONG, ge_data,
2613 lo, MONO_PATCH_INFO_NONE, 0);
2614 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2616 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2617 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2625 // To load 64 bit values we will have to use ldah/lda combination
2626 // and temporary register. As temporary register use r28
2627 // Divide 64 bit value in two parts and load upper 32 bits into
2628 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2629 // dreg from temp reg
2630 // the 32 bit value could be loaded with ldah/lda
2631 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2632 ins->dreg, ins->inst_c0);
2635 if (ins->inst_c0 == 0)
2637 alpha_clr(code, ins->dreg);
2641 // if -32768 < const <= 32767
2642 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2643 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2646 AlphaGotData ge_data;
2648 lo = (char *)code - (char *)cfg->native_code;
2650 ge_data.data.l = ins->inst_c0;
2652 add_got_entry(cfg, GT_LONG, ge_data,
2653 lo, MONO_PATCH_INFO_NONE, 0);
2654 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2661 double d = *(double *)ins->inst_p0;
2662 AlphaGotData ge_data;
2664 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2668 add_got_entry(cfg, GT_DOUBLE, ge_data,
2669 (char *)code - (char *)cfg->native_code,
2670 MONO_PATCH_INFO_NONE, 0);
2671 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2678 float d = *(float *)ins->inst_p0;
2679 AlphaGotData ge_data;
2681 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2685 add_got_entry(cfg, GT_FLOAT, ge_data,
2686 (char *)code - (char *)cfg->native_code,
2687 MONO_PATCH_INFO_NONE, 0);
2688 alpha_lds(code, ins->dreg, alpha_gp, 0);
2693 case OP_LOADU4_MEMBASE:
2694 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2695 ins->dreg, ins->inst_basereg, ins->inst_offset);
2697 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2698 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2701 case OP_LOADU1_MEMBASE:
2702 // Load unassigned byte from REGOFFSET
2703 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2704 ins->dreg, ins->inst_basereg, ins->inst_offset);
2706 alpha_ldbu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2709 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2711 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2712 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2716 case OP_LOADU2_MEMBASE:
2717 // Load unassigned word from REGOFFSET
2718 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2719 ins->dreg, ins->inst_basereg, ins->inst_offset);
2722 alpha_ldwu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2725 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2727 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2728 (ins->inst_offset+1));
2729 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2730 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2731 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2732 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2736 case OP_LOAD_MEMBASE:
2737 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2738 ins->dreg, ins->inst_basereg, ins->inst_offset);
2739 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2742 case OP_LOADI8_MEMBASE:
2743 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2744 ins->dreg, ins->inst_basereg, ins->inst_offset);
2745 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2748 case OP_LOADI4_MEMBASE:
2749 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2750 ins->dreg, ins->inst_basereg, ins->inst_offset);
2751 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2754 case OP_LOADI1_MEMBASE:
2755 // Load sign-extended byte from REGOFFSET
2756 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2757 ins->dreg, ins->inst_basereg, ins->inst_offset);
2760 alpha_ldbu(code, ins->dreg, ins->inst_basereg,
2762 alpha_sextb(code, ins->dreg, ins->dreg);
2766 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2768 alpha_lda(code, alpha_at, ins->inst_basereg,
2769 (ins->inst_offset+1));
2770 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2771 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2775 case OP_LOADI2_MEMBASE:
2776 // Load sign-extended word from REGOFFSET
2777 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2778 ins->dreg, ins->inst_basereg, ins->inst_offset);
2781 alpha_ldwu(code, ins->dreg, ins->inst_basereg,
2783 alpha_sextw(code, ins->dreg, ins->dreg);
2787 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2789 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2790 (ins->inst_offset+1));
2791 alpha_lda(code, alpha_at, ins->inst_basereg,
2792 (ins->inst_offset+2));
2793 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2794 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2795 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2796 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2800 case OP_STOREI1_MEMBASE_IMM:
2801 // Store signed byte at REGOFFSET
2802 // Valid only for storing 0
2803 // storei1_membase_reg will do the rest
2805 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2806 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2807 g_assert(ins->inst_imm == 0);
2810 alpha_stb(code, alpha_zero, ins->inst_destbasereg,
2813 g_assert_not_reached();
2817 case OP_STOREI1_MEMBASE_REG:
2818 // Store byte at REGOFFSET
2819 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2820 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2823 alpha_stb(code, ins->sreg1, ins->inst_destbasereg,
2828 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2830 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2832 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2833 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2834 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2835 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2840 case OP_STOREI2_MEMBASE_IMM:
2841 // Store signed word at REGOFFSET
2842 // Now work only for storing 0
2843 // For now storei2_membase_reg will do the work
2845 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2846 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2848 g_assert(ins->inst_imm == 0);
2851 alpha_stw(code, alpha_zero, ins->inst_destbasereg,
2854 g_assert_not_reached();
2858 case OP_STOREI2_MEMBASE_REG:
2859 // Store signed word from reg to REGOFFSET
2860 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2861 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2865 alpha_stw(code, ins->sreg1, ins->inst_destbasereg,
2870 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2872 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2873 (ins->inst_offset+1));
2874 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2876 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2877 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2878 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2879 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2880 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2881 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2882 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2883 (ins->inst_offset+1));
2884 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2890 case OP_STOREI4_MEMBASE_IMM:
2891 // We will get here only with ins->inst_imm = 0
2892 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2893 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2895 g_assert(ins->inst_imm == 0);
2897 alpha_stl(code, alpha_zero,
2898 ins->inst_destbasereg, ins->inst_offset);
2901 case OP_STORER4_MEMBASE_REG:
2902 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2903 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2904 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2907 case OP_STORER8_MEMBASE_REG:
2908 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2909 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2910 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2914 case OP_LOADR4_MEMBASE:
2915 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2916 ins->dreg, ins->inst_basereg, ins->inst_offset);
2917 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2920 case OP_LOADR8_MEMBASE:
2921 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2922 ins->dreg, ins->inst_basereg, ins->inst_offset);
2923 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2927 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2928 ins->sreg1, ins->dreg);
2929 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
2933 // Later check different rounding and exc modes
2934 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2935 ins->sreg1, ins->sreg2, ins->dreg);
2936 alpha_addt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2941 // Later check different rounding and exc modes
2942 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2943 ins->sreg1, ins->sreg2, ins->dreg);
2944 alpha_subt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2949 // Later check different rounding and exc modes
2950 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2951 ins->sreg1, ins->sreg2, ins->dreg);
2952 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
2956 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2957 ins->sreg1, ins->dreg);
2958 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
2961 case OP_ALPHA_TRAPB:
2962 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2967 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2968 ins->sreg1, ins->dreg);
2969 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
2972 case OP_STORE_MEMBASE_IMM:
2973 case OP_STOREI8_MEMBASE_IMM:
2974 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2975 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2976 g_assert(ins->inst_imm == 0);
2978 alpha_stq(code, alpha_zero,
2979 ins->inst_destbasereg, ins->inst_offset);
2982 case OP_STORE_MEMBASE_REG:
2983 case OP_STOREI8_MEMBASE_REG:
2984 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2985 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2986 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2989 case OP_STOREI4_MEMBASE_REG:
2990 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2991 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2992 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2995 case OP_ICOMPARE_IMM:
2996 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2997 ins->sreg1, ins->dreg, ins->inst_imm);
2999 g_assert_not_reached();
3003 case OP_COMPARE_IMM:
3004 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3005 ins->sreg1, ins->dreg, ins->inst_imm);
3007 g_assert_not_reached();
3011 case OP_COMPARE: // compare two 32 bit regs
3012 case OP_LCOMPARE: // compare two 64 bit regs
3013 case OP_FCOMPARE: // compare two floats
3014 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3015 ins->sreg1, ins->sreg2, ins->dreg);
3017 g_assert_not_reached();
3021 case OP_ALPHA_CMPT_UN:
3022 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3023 ins->sreg1, ins->sreg2, ins->dreg);
3024 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3027 case OP_ALPHA_CMPT_UN_SU:
3028 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3029 ins->sreg1, ins->sreg2, ins->dreg);
3030 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3033 case OP_ALPHA_CMPT_EQ:
3034 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3035 ins->sreg1, ins->sreg2, ins->dreg);
3036 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
3039 case OP_ALPHA_CMPT_EQ_SU:
3040 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3041 ins->sreg1, ins->sreg2, ins->dreg);
3042 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
3046 case OP_ALPHA_CMPT_LT:
3047 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3048 ins->sreg1, ins->sreg2, ins->dreg);
3049 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3052 case OP_ALPHA_CMPT_LT_SU:
3053 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3054 ins->sreg1, ins->sreg2, ins->dreg);
3055 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3058 case OP_ALPHA_CMPT_LE:
3059 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3060 ins->sreg1, ins->sreg2, ins->dreg);
3061 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3064 case OP_ALPHA_CMPT_LE_SU:
3065 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3066 ins->sreg1, ins->sreg2, ins->dreg);
3067 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3070 case OP_ALPHA_CMP_EQ:
3071 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3072 ins->sreg1, ins->sreg2, ins->dreg);
3073 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3076 case OP_ALPHA_CMP_IMM_EQ:
3077 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3078 ins->sreg1, ins->inst_imm, ins->dreg);
3079 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3082 case OP_ALPHA_CMP_IMM_ULE:
3083 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%d\n",
3084 ins->sreg1, ins->inst_imm, ins->dreg);
3085 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3088 case OP_ALPHA_CMP_ULT:
3089 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3090 ins->sreg1, ins->sreg2, ins->dreg);
3091 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3094 case OP_ALPHA_CMP_IMM_ULT:
3095 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3096 ins->sreg1, ins->inst_imm, ins->dreg);
3097 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3100 case OP_ALPHA_CMP_LE:
3101 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3102 ins->sreg1, ins->sreg2, ins->dreg);
3103 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3106 case OP_ALPHA_CMP_ULE:
3107 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3108 ins->sreg1, ins->sreg2, ins->dreg);
3109 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3113 case OP_ALPHA_CMP_IMM_LE:
3114 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%d\n",
3115 ins->sreg1, ins->inst_imm, ins->dreg);
3116 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3119 case OP_ALPHA_CMP_LT:
3120 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3121 ins->sreg1, ins->sreg2, ins->dreg);
3122 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3125 case OP_ALPHA_CMP_IMM_LT:
3126 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3127 ins->sreg1, ins->inst_imm, ins->dreg);
3128 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3131 case OP_COND_EXC_GT:
3132 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3133 (char *)ins->inst_p1);
3135 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3138 case OP_COND_EXC_GT_UN:
3139 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3140 (char *)ins->inst_p1);
3142 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3145 case OP_COND_EXC_LT:
3146 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3147 (char *)ins->inst_p1);
3149 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3152 case OP_COND_EXC_LT_UN:
3153 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3154 (char *)ins->inst_p1);
3156 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3160 case OP_COND_EXC_LE_UN:
3161 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3162 (char *)ins->inst_p1);
3163 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3166 case OP_COND_EXC_NE_UN:
3167 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3168 (char *)ins->inst_p1);
3169 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3172 case OP_COND_EXC_EQ:
3173 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3174 (char *)ins->inst_p1);
3175 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3178 case OP_COND_EXC_IOV:
3179 case OP_COND_EXC_OV:
3180 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3183 case OP_COND_EXC_IC:
3185 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3188 case CEE_CONV_OVF_U4:
3189 // Convert unsigned 32 bit value to 64 bit reg
3191 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3192 ins->sreg1, ins->dreg);
3193 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3194 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3195 alpha_mov1(code, ins->sreg1, ins->dreg);
3198 case CEE_CONV_OVF_I4_UN:
3199 // Convert unsigned 32 bit value to 64 bit reg
3201 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3202 ins->sreg1, ins->dreg);
3203 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3205 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3206 alpha_mov1(code, ins->sreg1, ins->dreg);
3210 // Move I1 (byte) to dreg(64 bits) and sign extend it
3212 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3213 ins->sreg1, ins->dreg);
3215 alpha_sextb(code, ins->sreg1, ins->dreg);
3218 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3219 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3220 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3225 // Move I2 (word) to dreg(64 bits) and sign extend it
3226 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3227 ins->sreg1, ins->dreg);
3229 alpha_sextw(code, ins->sreg1, ins->dreg);
3232 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3233 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3234 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3239 // Move I4 (long) to dreg(64 bits) and sign extend it
3240 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3241 ins->sreg1, ins->dreg);
3242 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3247 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3248 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3249 ins->sreg1, ins->dreg);
3250 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3251 alpha_mov1(code, ins->sreg1, ins->dreg);
3255 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3256 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3257 ins->sreg1, ins->dreg);
3258 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3262 // Move U2 (word) to dreg(64 bits) don't sign extend it
3263 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3264 ins->sreg1, ins->dreg);
3265 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3269 // Move U4 (long) to dreg(64 bits) don't sign extend it
3270 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3271 ins->sreg1, ins->dreg);
3272 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3277 // Move U4 (long) to dreg(64 bits) don't sign extend it
3278 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3279 ins->sreg1, ins->dreg);
3280 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3283 case OP_FCONV_TO_I4:
3284 case OP_FCONV_TO_I8:
3285 // Move float to 32 bit reg
3286 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3287 ins->sreg1, ins->dreg);
3288 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3289 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3290 alpha_lda(code, alpha_sp, alpha_sp, -8);
3291 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3292 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3293 alpha_lda(code, alpha_sp, alpha_sp, 8);
3296 case OP_FCONV_TO_I2:
3297 // Move float to 16 bit reg
3298 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3299 ins->sreg1, ins->dreg);
3300 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3301 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3302 alpha_lda(code, alpha_sp, alpha_sp, -8);
3303 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3304 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3305 alpha_lda(code, alpha_sp, alpha_sp, 8);
3306 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3307 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3310 case OP_FCONV_TO_U2:
3311 // Move float to 16 bit reg as unsigned
3312 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3313 ins->sreg1, ins->dreg);
3314 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3315 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3316 alpha_lda(code, alpha_sp, alpha_sp, -8);
3317 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3318 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3319 alpha_lda(code, alpha_sp, alpha_sp, 8);
3320 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3323 case OP_FCONV_TO_U1:
3324 // Move float to 8 bit reg as unsigned
3325 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3326 ins->sreg1, ins->dreg);
3327 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3328 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3329 alpha_lda(code, alpha_sp, alpha_sp, -8);
3330 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3331 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3332 alpha_lda(code, alpha_sp, alpha_sp, 8);
3333 alpha_and_(code, ins->dreg, 0xff, ins->dreg);
3336 case OP_FCONV_TO_I1:
3337 // Move float to 8 bit reg
3338 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3339 ins->sreg1, ins->dreg);
3340 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3341 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3342 alpha_lda(code, alpha_sp, alpha_sp, -8);
3343 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3344 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3345 alpha_lda(code, alpha_sp, alpha_sp, 8);
3346 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3347 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3351 case OP_LCONV_TO_R4:
3352 // Move 32/64 bit int into float
3353 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3354 ins->sreg1, ins->dreg);
3355 alpha_lda(code, alpha_sp, alpha_sp, -8);
3356 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3357 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3358 alpha_lda(code, alpha_sp, alpha_sp, 8);
3359 alpha_cvtqs(code, ins->dreg, ins->dreg);
3364 case OP_LCONV_TO_R8:
3365 // Move 32/64 bit int into double
3366 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3367 ins->sreg1, ins->dreg);
3368 alpha_lda(code, alpha_sp, alpha_sp, -8);
3369 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3370 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3371 alpha_lda(code, alpha_sp, alpha_sp, 8);
3372 alpha_cvtqt(code, ins->dreg, ins->dreg);
3376 case OP_FCONV_TO_R4:
3377 // Convert 64 bit float to 32 bit float (T -> S)
3378 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3379 ins->sreg1, ins->dreg);
3380 alpha_cvtts_su(code, ins->sreg1, ins->dreg);
3385 // Allocate sreg1 bytes on stack, round bytes by 8,
3386 // modify SP, set dreg to end of current stack frame
3387 // top of stack is used for call params
3388 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3389 ins->sreg1, ins->dreg);
3391 alpha_addq_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3392 alpha_bic_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3393 if (ins->flags & MONO_INST_INIT)
3394 alpha_mov1(code, ins->sreg1, ins->sreg2);
3396 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3397 if (cfg->arch.params_stack_size > 0)
3399 alpha_lda(code, ins->dreg, alpha_zero,
3400 (cfg->arch.params_stack_size));
3401 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3404 alpha_mov1(code, alpha_sp, ins->dreg);
3406 if (ins->flags & MONO_INST_INIT)
3408 // TODO: Optimize it later
3409 alpha_lda(code, ins->sreg2, ins->sreg2,
3410 -(MONO_ARCH_LOCALLOC_ALIGNMENT));
3411 alpha_blt(code, ins->sreg2, 3);
3412 alpha_addq(code, ins->sreg2, ins->dreg, alpha_at);
3413 alpha_stq(code, alpha_zero, alpha_at, 0);
3414 alpha_br(code, alpha_zero, -5);
3420 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3421 ins->sreg1, ins->dreg);
3422 alpha_mov1(code, ins->sreg1, ins->dreg);
3429 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3431 alpha_clr(code, ins->dreg);
3432 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3439 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3441 alpha_clr(code, ins->dreg);
3442 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3447 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3449 alpha_clr(code, ins->dreg);
3450 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3454 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3456 alpha_clr(code, ins->dreg);
3457 alpha_fbeq(code, alpha_at, 1);
3458 alpha_lda(code, ins->dreg, alpha_zero, 1);
3461 alpha_cvttq_c(code, alpha_at, alpha_at);
3462 alpha_lda(code, alpha_sp, alpha_sp, -8);
3463 alpha_stt(code, alpha_at, alpha_sp, 0);
3464 alpha_ldq(code, alpha_at, alpha_sp, 0);
3465 alpha_lda(code, alpha_sp, alpha_sp, 8);
3467 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3472 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3474 alpha_clr(code, ins->dreg);
3475 alpha_fbne(code, alpha_at, 1);
3476 alpha_lda(code, ins->dreg, alpha_zero, 1);
3479 alpha_cvttq_c(code, alpha_at, alpha_at);
3480 alpha_lda(code, alpha_sp, alpha_sp, -8);
3481 alpha_stt(code, alpha_at, alpha_sp, 0);
3482 alpha_ldq(code, alpha_at, alpha_sp, 0);
3483 alpha_lda(code, alpha_sp, alpha_sp, 8);
3485 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3491 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3493 alpha_clr(code, ins->dreg);
3494 alpha_fbeq(code, alpha_at, 1);
3495 alpha_lda(code, ins->dreg, alpha_zero, 1);
3499 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3502 alpha_clr(code, ins->dreg);
3503 alpha_fbne(code, (alpha_at+1), 1);
3504 alpha_fbeq(code, alpha_at, 1);
3505 alpha_lda(code, ins->dreg, alpha_zero, 1);
3510 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3511 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3515 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3516 alpha_fbeq(code, (alpha_at+1), 1);
3517 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3518 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3522 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3523 alpha_fbeq(code, (alpha_at+1), 1);
3524 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3525 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3529 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge] [");
3530 alpha_fbne(code, (alpha_at+1), 1);
3531 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3535 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3536 alpha_fbeq(code, (alpha_at+1), 1);
3537 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3538 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3542 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble] [");
3543 alpha_fbne(code, (alpha_at+1), 1);
3544 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3548 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3549 alpha_fbeq(code, (alpha_at+1), 1);
3550 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3551 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3555 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt] [");
3556 alpha_fbne(code, (alpha_at+1), 1);
3557 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3561 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3562 alpha_fbeq(code, (alpha_at+1), 1);
3563 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3564 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3568 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt] [");
3569 alpha_fbne(code, (alpha_at+1), 1);
3570 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3574 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3575 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3579 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3580 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3584 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3585 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3589 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3590 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3594 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3595 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3599 if (ins->flags & MONO_INST_BRLABEL)
3601 if (ins->inst_i0->inst_c0)
3603 CFG_DEBUG(4) g_print("inst_c0: %0lX, data: %p]\n",
3604 ins->inst_i0->inst_c0,
3605 cfg->native_code + ins->inst_i0->inst_c0);
3606 alpha_br(code, alpha_zero, 0);
3610 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n",
3611 offset, ins->inst_i0);
3612 mono_add_patch_info (cfg, offset,
3613 MONO_PATCH_INFO_LABEL, ins->inst_i0);
3615 alpha_br(code, alpha_zero, 0);
3620 if (ins->inst_target_bb->native_offset)
3622 // Somehow native offset is offset from
3623 // start of the code. So convert it to
3625 long br_offset = (char *)cfg->native_code +
3626 ins->inst_target_bb->native_offset - 4 - (char *)code;
3628 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3629 ins->inst_target_bb->native_offset,
3631 ins->inst_target_bb->native_offset);
3632 alpha_br(code, alpha_zero, br_offset/4);
3636 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3637 offset, ins->inst_target_bb);
3639 mono_add_patch_info (cfg, offset,
3641 ins->inst_target_bb);
3642 alpha_br(code, alpha_zero, 0);
3649 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3652 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3660 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3661 call = (MonoCallInst*)ins;
3663 if (ins->flags & MONO_INST_HAS_METHOD)
3665 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3666 code = emit_call (cfg, code,
3667 MONO_PATCH_INFO_METHOD, call->method);
3671 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3672 code = emit_call (cfg, code,
3673 MONO_PATCH_INFO_ABS, call->fptr);
3676 //code = emit_move_return_value (cfg, ins, code);
3683 case OP_VOIDCALL_REG:
3688 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3689 call = (MonoCallInst*)ins;
3691 alpha_mov1(code, ins->sreg1, alpha_pv);
3693 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3695 offset = (char *)code - (char *)cfg->native_code;
3698 ALPHA_LOAD_GP(offset)
3699 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3700 alpha_lda(code, alpha_gp, alpha_gp, 0);
3704 case OP_FCALL_MEMBASE:
3705 case OP_CALL_MEMBASE:
3706 case OP_LCALL_MEMBASE:
3707 case OP_VCALL_MEMBASE:
3711 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3712 ins->inst_basereg, ins->inst_offset);
3713 call = (MonoCallInst*)ins;
3715 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3716 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3718 offset = (char *)code - (char *)cfg->native_code;
3721 ALPHA_LOAD_GP(offset)
3722 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3723 alpha_lda(code, alpha_gp, alpha_gp, 0);
3727 case OP_VOIDCALL_MEMBASE:
3731 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3732 ins->inst_basereg, ins->inst_offset);
3733 call = (MonoCallInst*)ins;
3735 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3736 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3738 offset = (char *)code - (char *)cfg->native_code;
3741 ALPHA_LOAD_GP(offset)
3742 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3743 alpha_lda(code, alpha_gp, alpha_gp, 0);
3747 case OP_START_HANDLER:
3749 // TODO - find out when we called by call_handler or resume_context
3750 // of by call_filter. There should be difference. For now just
3751 // handle - call_handler
3753 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3754 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3756 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3757 ins->inst_left->inst_offset);
3763 // Keep in sync with start_handler
3764 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3765 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3767 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3768 ins->inst_left->inst_offset);
3770 alpha_ret(code, alpha_ra, 1);
3776 // Keep in sync with start_handler
3777 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3778 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3780 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3781 ins->inst_left->inst_offset);
3783 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3784 alpha_mov1(code, ins->sreg1, alpha_r0);
3786 alpha_ret(code, alpha_ra, 1);
3790 case OP_CALL_HANDLER:
3794 offset = (char *)code - (char *)cfg->native_code;
3796 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3797 offset, ins->inst_target_bb);
3799 mono_add_patch_info (cfg, offset,
3801 ins->inst_target_bb);
3802 alpha_bsr(code, alpha_ra, 0);
3807 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3809 alpha_mov1(code, ins->sreg1, alpha_a0);
3810 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3811 (gpointer)"mono_arch_throw_exception");
3815 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3817 alpha_mov1(code, ins->sreg1, alpha_a0);
3818 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3819 (gpointer)"mono_arch_rethrow_exception");
3825 * Note: this 'frame destruction' logic is useful for tail calls,
3826 too. Keep in sync with the code in emit_epilog.
3829 AlphaGotData ge_data;
3831 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3833 /* FIXME: no tracing support... */
3834 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3835 code = mono_arch_instrument_epilog (cfg,
3836 mono_profiler_method_leave, code, FALSE);
3837 g_assert (!cfg->method->save_lmf);
3839 alpha_mov1( code, alpha_fp, alpha_sp );
3841 code = emit_load_volatile_arguments (cfg, code);
3843 offset = cfg->arch.params_stack_size;
3845 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3846 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3847 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3849 ge_data.data.p = ins->inst_p0;
3850 add_got_entry(cfg, GT_PTR, ge_data,
3851 (char *)code - (char *)cfg->native_code,
3852 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3853 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3855 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3860 mono_add_patch_info (cfg, offset,
3861 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3864 case OP_MEMORY_BARRIER:
3865 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3870 // Float register contains a value which we need to check
3872 double ni = -1.0 / 0.0;
3873 double pi = 1.0 / 0.0;
3874 AlphaGotData ge_data;
3876 CFG_DEBUG(4) g_print("ALPHA_TODO: [chfinite] sreg1=%d\n", ins->sreg1);
3877 alpha_cmptun_su(code, ins->sreg1, ins->sreg1, alpha_at);
3879 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3881 // Negative infinity
3882 ge_data.data.d = ni;
3883 add_got_entry(cfg, GT_DOUBLE, ge_data,
3884 (char *)code - (char *)cfg->native_code,
3885 MONO_PATCH_INFO_NONE, 0);
3886 alpha_ldt(code, alpha_at, alpha_gp, 0);
3888 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3891 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3893 // Positive infinity
3894 ge_data.data.d = pi;
3895 add_got_entry(cfg, GT_DOUBLE, ge_data,
3896 (char *)code - (char *)cfg->native_code,
3897 MONO_PATCH_INFO_NONE, 0);
3898 alpha_ldt(code, alpha_at, alpha_gp, 0);
3900 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3903 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3907 CFG_DEBUG(4) g_print("ALPHA_TODO: [fdiv] dest=%d, sreg1=%d, sreg2=%d\n",
3908 ins->dreg, ins->sreg1, ins->sreg2);
3909 alpha_divt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
3914 g_warning ("unknown opcode %s in %s()\n",
3915 mono_inst_name (ins->opcode), __FUNCTION__);
3917 // g_assert_not_reached ();
3921 if ( (((char *)code) -
3922 ((char *)cfg->native_code) -
3925 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3926 mono_inst_name (ins->opcode), max_len,
3927 ((char *)code) - ((char *)cfg->native_code) - offset );
3928 //g_assert_not_reached ();
3933 last_offset = offset;
3936 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3939 /*========================= End of Function ========================*/
3944 /*------------------------------------------------------------------*/
3946 /* Name - mono_arch_cpu_optimizazions */
3948 /* Function - Returns the optimizations supported on this CPU */
3950 /*------------------------------------------------------------------*/
3953 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3957 if (getenv("MONO_ALPHA_DEBUG"))
3958 mini_alpha_verbose_level = 1;
3960 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3962 /*----------------------------------------------------------*/
3963 /* no alpha-specific optimizations yet */
3964 /*----------------------------------------------------------*/
3965 *exclude_mask = MONO_OPT_LINEARS;
3966 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3970 /*========================= End of Function ========================*/
3972 /*------------------------------------------------------------------*/
3974 /* Name - mono_arch_flush_icache */
3976 /* Function - Flush the CPU icache. */
3978 /*------------------------------------------------------------------*/
3981 mono_arch_flush_icache (guint8 *code, gint size)
3983 //ALPHA_DEBUG("mono_arch_flush_icache");
3985 /* flush instruction cache to see trampoline code */
3986 asm volatile("imb":::"memory");
3989 /*========================= End of Function ========================*/
3991 /*------------------------------------------------------------------*/
3993 /* Name - mono_arch_regname */
3995 /* Function - Returns the name of the register specified by */
3996 /* the input parameter. */
3998 /*------------------------------------------------------------------*/
4001 mono_arch_regname (int reg) {
4002 static const char * rnames[] = {
4003 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
4004 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
4005 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
4006 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
4007 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
4008 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
4009 "alpha_r30", "alpha_r31"
4012 if (reg >= 0 && reg < 32)
4013 return rnames [reg];
4017 /*========================= End of Function ========================*/
4019 /*------------------------------------------------------------------*/
4021 /* Name - mono_arch_fregname */
4023 /* Function - Returns the name of the register specified by */
4024 /* the input parameter. */
4026 /*------------------------------------------------------------------*/
4029 mono_arch_fregname (int reg) {
4030 static const char * rnames[] = {
4031 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4032 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4033 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4034 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4035 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4036 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4037 "alpha_f30", "alpha_f31"
4040 if (reg >= 0 && reg < 32)
4041 return rnames [reg];
4046 /*========================= End of Function ========================*/
4048 /*------------------------------------------------------------------*/
4050 /* Name - mono_arch_patch_code */
4052 /* Function - Process the patch data created during the */
4053 /* instruction build process. This resolves jumps, */
4054 /* calls, variables etc. */
4056 /*------------------------------------------------------------------*/
4059 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
4060 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4062 MonoJumpInfo *patch_info;
4063 gboolean compile_aot = !run_cctors;
4065 ALPHA_DEBUG("mono_arch_patch_code");
4067 for (patch_info = ji; patch_info; patch_info = patch_info->next)
4069 unsigned char *ip = patch_info->ip.i + code;
4070 const unsigned char *target;
4072 target = mono_resolve_patch_target (method, domain,
4073 code, patch_info, run_cctors);
4077 switch (patch_info->type)
4080 case MONO_PATCH_INFO_BB:
4081 case MONO_PATCH_INFO_LABEL:
4084 /* No need to patch these */
4089 switch (patch_info->type)
4091 case MONO_PATCH_INFO_NONE:
4094 case MONO_PATCH_INFO_GOT_OFFSET:
4096 unsigned int *ip2 = (unsigned int *)ip;
4097 unsigned int inst = *ip2;
4098 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
4100 g_assert(!(off & 0xFFFF8000));
4108 case MONO_PATCH_INFO_CLASS_INIT:
4110 /* Might already been changed to a nop */
4111 unsigned int* ip2 = (unsigned int *)ip;
4112 unsigned long t_addr = (unsigned long)target;
4114 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
4115 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
4117 // amd64_call_code (ip2, 0);
4121 // case MONO_PATCH_INFO_METHOD_REL:
4122 case MONO_PATCH_INFO_R8:
4123 case MONO_PATCH_INFO_R4:
4124 g_assert_not_reached ();
4126 case MONO_PATCH_INFO_BB:
4129 case MONO_PATCH_INFO_METHOD:
4130 case MONO_PATCH_INFO_METHODCONST:
4131 case MONO_PATCH_INFO_INTERNAL_METHOD:
4132 case MONO_PATCH_INFO_METHOD_JUMP:
4134 volatile unsigned int *p = (unsigned int *)ip;
4135 unsigned long t_addr;
4142 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4144 if (target != ((void *)t_addr))
4146 t_addr = (unsigned long)target;
4147 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4148 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4153 case MONO_PATCH_INFO_ABS:
4155 volatile unsigned int *p = (unsigned int *)ip;
4156 unsigned long t_addr;
4162 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4167 case MONO_PATCH_INFO_SWITCH:
4169 unsigned int *pcode = (unsigned int *)ip;
4170 unsigned long t_addr;
4172 t_addr = (unsigned long)target;
4174 if (((unsigned long)ip) % 8)
4180 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4181 alpha_nop(pcode); // TODO optimize later
4182 alpha_bsr(pcode, alpha_at, 2);
4184 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4186 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4189 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4199 volatile unsigned int *p = (unsigned int *)ip;
4200 unsigned int alpha_ins = *p;
4201 unsigned int opcode;
4204 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4206 if (opcode >= 0x30 && opcode <= 0x3f)
4208 // This is branch with offset instruction
4209 br_offset = (target - ip - 4);
4211 g_assert(!(br_offset & 3));
4213 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4221 /*========================= End of Function ========================*/
4222 /*------------------------------------------------------------------*/
4224 /* Name - mono_arch_emit_this_vret_args */
4228 /*------------------------------------------------------------------*/
4231 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4232 int this_reg, int this_type, int vt_reg)
4234 MonoCallInst *call = (MonoCallInst*)inst;
4235 CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, inst->signature, FALSE);
4237 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4243 if (cinfo->ret.storage == ArgValuetypeInReg)
4246 * The valuetype is in RAX:RDX after the call, need to be copied to
4247 * the stack. Push the address here, so the call instruction can
4250 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4251 //vtarg->sreg1 = vt_reg;
4252 //mono_bblock_add_inst (cfg->cbb, vtarg);
4255 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4260 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4261 vtarg->sreg1 = vt_reg;
4262 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4263 mono_bblock_add_inst (cfg->cbb, vtarg);
4265 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4266 cinfo->ret.reg, FALSE);
4270 /* add the this argument */
4274 MONO_INST_NEW (cfg, this, OP_MOVE);
4275 this->type = this_type;
4276 this->sreg1 = this_reg;
4277 this->dreg = mono_regstate_next_int (cfg->rs);
4278 mono_bblock_add_inst (cfg->cbb, this);
4280 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4281 cinfo->args [0].reg, FALSE);
4287 /*========================= End of Function ========================*/
4289 /*------------------------------------------------------------------*/
4291 /* Name - mono_arch_is_inst_imm */
4293 /* Function - Determine if operand qualifies as an immediate */
4294 /* value. For Alpha this is a value 0 - 255 */
4296 /* Returns - True|False - is [not] immediate value. */
4298 /*------------------------------------------------------------------*/
4301 mono_arch_is_inst_imm (gint64 imm)
4303 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4305 return (imm & ~(0x0FFL)) ? 0 : 1;
4308 /*------------------------------------------------------------------*/
4310 /* Name - mono_arch_setup_jit_tls_data */
4312 /* Function - Setup the JIT's Thread Level Specific Data. */
4314 /*------------------------------------------------------------------*/
4317 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4319 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4321 if (!tls_offset_inited) {
4322 tls_offset_inited = TRUE;
4325 if (!lmf_addr_key_inited) {
4326 lmf_addr_key_inited = TRUE;
4327 pthread_key_create (&lmf_addr_key, NULL);
4330 pthread_setspecific (lmf_addr_key, &tls->lmf);
4333 /*------------------------------------------------------------------*/
4335 /* Name - mono_arch_cpu_init */
4337 /* Function - Perform CPU specific initialization to execute */
4340 /*------------------------------------------------------------------*/
4343 mono_arch_cpu_init (void)
4345 unsigned long amask, implver;
4346 register long v0 __asm__("$0") = -1;
4348 ALPHA_DEBUG("mono_arch_cpu_init");
4350 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
4352 __asm__ (".long 0x47e03d80" : "=r"(v0));
4358 //printf("amask: %x, implver: %x", amask, implver);
4362 * Initialize architecture specific code.
4365 mono_arch_init (void)
4370 * Cleanup architecture specific code.
4373 mono_arch_cleanup (void)
4380 * Obtain information about a call according to the calling convention.
4382 * For x86 ELF, see the "System V Application Binary Interface Intel386
4383 * Architecture Processor Supplment, Fourth Edition" document for more
4385 * For x86 win32, see ???.
4388 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
4390 guint32 i, gr, fr, *pgr, *pfr;
4392 int n = sig->hasthis + sig->param_count;
4393 guint32 stack_size = 0;
4396 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4411 ret_type = mono_type_get_underlying_type (sig->ret);
4412 switch (ret_type->type) {
4413 case MONO_TYPE_BOOLEAN:
4418 case MONO_TYPE_CHAR:
4424 case MONO_TYPE_FNPTR:
4425 case MONO_TYPE_CLASS:
4426 case MONO_TYPE_OBJECT:
4427 case MONO_TYPE_SZARRAY:
4428 case MONO_TYPE_ARRAY:
4429 case MONO_TYPE_STRING:
4430 cinfo->ret.storage = ArgInIReg;
4431 cinfo->ret.reg = alpha_r0;
4435 cinfo->ret.storage = ArgInIReg;
4436 cinfo->ret.reg = alpha_r0;
4439 cinfo->ret.storage = ArgInFloatReg;
4440 cinfo->ret.reg = alpha_f0;
4443 cinfo->ret.storage = ArgInDoubleReg;
4444 cinfo->ret.reg = alpha_f0;
4446 case MONO_TYPE_GENERICINST:
4447 if (!mono_type_generic_inst_is_valuetype (sig->ret))
4449 cinfo->ret.storage = ArgInIReg;
4450 cinfo->ret.reg = alpha_r0;
4454 case MONO_TYPE_VALUETYPE:
4456 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4458 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE,
4459 &tmp_gr, &tmp_fr, &tmp_stacksize);
4461 if (cinfo->ret.storage == ArgOnStack)
4462 /* The caller passes the address where the value
4464 add_general (pgr, &stack_size, &cinfo->ret);
4467 case MONO_TYPE_TYPEDBYREF:
4468 /* Same as a valuetype with size 24 */
4469 add_general (pgr, &stack_size, &cinfo->ret);
4472 case MONO_TYPE_VOID:
4475 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4481 add_general (pgr, &stack_size, cinfo->args + 0);
4483 if (!sig->pinvoke &&
4484 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4487 fr = FLOAT_PARAM_REGS;
4489 /* Emit the signature cookie just before the implicit arguments
4491 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4494 for (i = 0; i < sig->param_count; ++i)
4496 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4499 if (!sig->pinvoke &&
4500 (sig->call_convention == MONO_CALL_VARARG) &&
4501 (i == sig->sentinelpos))
4503 /* We allways pass the sig cookie on the stack for simpl
4506 * Prevent implicit arguments + the sig cookie from being passed
4510 fr = FLOAT_PARAM_REGS;
4512 /* Emit the signature cookie just before the implicit arguments */
4513 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4516 if (sig->params [i]->byref) {
4517 add_general (pgr, &stack_size, ainfo);
4521 ptype = mono_type_get_underlying_type (sig->params [i]);
4523 switch (ptype->type) {
4524 case MONO_TYPE_BOOLEAN:
4527 add_general (pgr, &stack_size, ainfo);
4531 case MONO_TYPE_CHAR:
4532 add_general (pgr, &stack_size, ainfo);
4536 add_general (pgr, &stack_size, ainfo);
4541 case MONO_TYPE_FNPTR:
4542 case MONO_TYPE_CLASS:
4543 case MONO_TYPE_OBJECT:
4544 case MONO_TYPE_STRING:
4545 case MONO_TYPE_SZARRAY:
4546 case MONO_TYPE_ARRAY:
4547 add_general (pgr, &stack_size, ainfo);
4549 case MONO_TYPE_GENERICINST:
4550 if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
4552 add_general (pgr, &stack_size, ainfo);
4556 case MONO_TYPE_VALUETYPE:
4558 /* We allways pass valuetypes on the stack */
4559 add_valuetype (gsctx, sig, ainfo, sig->params [i],
4560 FALSE, pgr, pfr, &stack_size);
4562 case MONO_TYPE_TYPEDBYREF:
4563 stack_size += sizeof (MonoTypedRef);
4564 ainfo->storage = ArgOnStack;
4568 add_general (pgr, &stack_size, ainfo);
4571 add_float (pfr, &stack_size, ainfo, FALSE);
4574 add_float (pfr, &stack_size, ainfo, TRUE);
4577 g_assert_not_reached ();
4581 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4582 (n > 0) && (sig->sentinelpos == sig->param_count))
4585 fr = FLOAT_PARAM_REGS;
4587 /* Emit the signature cookie just before the implicit arguments
4589 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4592 cinfo->stack_usage = stack_size;
4593 cinfo->reg_usage = gr;
4594 cinfo->freg_usage = fr;
4599 static const char *CvtMonoType(MonoTypeEnum t)
4604 return "MONO_TYPE_END";
4605 case MONO_TYPE_VOID:
4606 return "MONO_TYPE_VOID";
4607 case MONO_TYPE_BOOLEAN:
4608 return "MONO_TYPE_BOOLEAN";
4609 case MONO_TYPE_CHAR:
4610 return "MONO_TYPE_CHAR";
4612 return "MONO_TYPE_I1";
4614 return "MONO_TYPE_U1";
4616 return "MONO_TYPE_I2";
4618 return "MONO_TYPE_U2";
4620 return "MONO_TYPE_I4";
4622 return "MONO_TYPE_U4";
4624 return "MONO_TYPE_I8";
4626 return "MONO_TYPE_U8";
4628 return "MONO_TYPE_R4";
4630 return "MONO_TYPE_R8";
4631 case MONO_TYPE_STRING:
4632 return "MONO_TYPE_STRING";
4634 return "MONO_TYPE_PTR";
4635 case MONO_TYPE_BYREF:
4636 return "MONO_TYPE_BYREF";
4637 case MONO_TYPE_VALUETYPE:
4638 return "MONO_TYPE_VALUETYPE";
4639 case MONO_TYPE_CLASS:
4640 return "MONO_TYPE_CLASS";
4642 return "MONO_TYPE_VAR";
4643 case MONO_TYPE_ARRAY:
4644 return "MONO_TYPE_ARRAY";
4645 case MONO_TYPE_GENERICINST:
4646 return "MONO_TYPE_GENERICINST";
4647 case MONO_TYPE_TYPEDBYREF:
4648 return "MONO_TYPE_TYPEDBYREF";
4650 return "MONO_TYPE_I";
4652 return "MONO_TYPE_U";
4653 case MONO_TYPE_FNPTR:
4654 return "MONO_TYPE_FNPTR";
4655 case MONO_TYPE_OBJECT:
4656 return "MONO_TYPE_OBJECT";
4657 case MONO_TYPE_SZARRAY:
4658 return "MONO_TYPE_SZARRAY";
4659 case MONO_TYPE_MVAR:
4660 return "MONO_TYPE_MVAR";
4661 case MONO_TYPE_CMOD_REQD:
4662 return "MONO_TYPE_CMOD_REQD";
4663 case MONO_TYPE_CMOD_OPT:
4664 return "MONO_TYPE_CMOD_OPT";
4665 case MONO_TYPE_INTERNAL:
4666 return "MONO_TYPE_INTERNAL";
4667 case MONO_TYPE_MODIFIER:
4668 return "MONO_TYPE_MODIFIER";
4669 case MONO_TYPE_SENTINEL:
4670 return "MONO_TYPE_SENTINEL";
4671 case MONO_TYPE_PINNED:
4672 return "MONO_TYPE_PINNED";
4680 /*------------------------------------------------------------------*/
4682 /* Name - mono_arch_call_opcode */
4684 /* Function - Take the arguments and generate the arch-specific */
4685 /* instructions to properly call the function. This */
4686 /* includes pushing, moving argments to the correct */
4689 * This method is called during converting method to IR
4690 * We need to generate IR ints to follow calling convention
4691 * cfg - points to currently compiled unit
4693 * call - points to structure that describes what we are going to
4694 * call (at least number of parameters required for the call)
4697 * On return we need to pass back modified call structure
4699 /*------------------------------------------------------------------*/
4702 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4703 MonoCallInst *call, int is_virtual)
4706 MonoMethodSignature *sig;
4711 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4713 sig = call->signature;
4714 n = sig->param_count + sig->hasthis;
4716 // Collect info about method we age going to call
4717 cinfo = get_call_info (cfg->generic_sharing_context, sig, sig->pinvoke);
4719 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4720 sig->pinvoke ? "PInvoke" : "Managed",
4721 sig->param_count, sig->hasthis,
4722 CvtMonoType(sig->ret->type), sig->ret->type);
4724 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4725 cfg->arch.params_stack_size = cinfo->stack_usage;
4727 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4728 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4730 for (i = 0; i < n; ++i)
4732 ArgInfo *ainfo = cinfo->args + i;
4734 /* Emit the signature cookie just before the implicit arguments
4736 if (!sig->pinvoke &&
4737 (sig->call_convention == MONO_CALL_VARARG) &&
4740 MonoMethodSignature *tmp_sig;
4743 /* FIXME: Add support for signature tokens to AOT */
4744 cfg->disable_aot = TRUE;
4745 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4748 * mono_ArgIterator_Setup assumes the signature cookie is
4749 * passed first and all the arguments which were before it are
4750 * passed on the stack after the signature. So compensate by
4751 * passing a different signature.
4753 tmp_sig = mono_metadata_signature_dup (call->signature);
4754 tmp_sig->param_count -= call->signature->sentinelpos;
4755 tmp_sig->sentinelpos = 0;
4756 memcpy (tmp_sig->params,
4757 call->signature->params + call->signature->sentinelpos,
4758 tmp_sig->param_count * sizeof (MonoType*));
4760 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4761 sig_arg->inst_p0 = tmp_sig;
4763 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4764 arg->inst_left = sig_arg;
4765 arg->type = STACK_PTR;
4766 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4769 if (is_virtual && i == 0) {
4770 /* the argument will be attached to the call instrucion
4772 in = call->args [i];
4776 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4777 in = call->args [i];
4778 arg->cil_code = in->cil_code;
4779 arg->inst_left = in;
4780 arg->type = in->type;
4781 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4783 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4785 if (sig->hasthis && (i == 0))
4786 arg_type = &mono_defaults.object_class->byval_arg;
4788 arg_type = sig->params [i - sig->hasthis];
4790 if ((i >= sig->hasthis) &&
4791 (MONO_TYPE_ISSTRUCT(arg_type)))
4796 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4797 size = sizeof (MonoTypedRef);
4798 align = sizeof (gpointer);
4802 size = mono_type_native_stack_size (&in->klass->byval_arg,
4805 size = mini_type_stack_size (cfg->generic_sharing_context, &in->klass->byval_arg, &align);
4807 if (ainfo->storage == ArgAggregate)
4809 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4812 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4814 vtaddr = mono_compile_create_var (cfg,
4815 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4818 * Part of the structure is passed in registers.
4820 for (j = 0; j < ainfo->nregs; ++j)
4822 int offset, load_op, dest_reg, arg_storage;
4824 slot = ainfo->reg + j;
4825 load_op = CEE_LDIND_I;
4827 dest_reg = ainfo->reg + j;
4828 arg_storage = ArgInIReg;
4830 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4831 load->ssa_op = MONO_SSA_LOAD;
4832 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4834 NEW_ICONST (cfg, offset_ins, offset);
4835 MONO_INST_NEW (cfg, load2, CEE_ADD);
4836 load2->inst_left = load;
4837 load2->inst_right = offset_ins;
4839 MONO_INST_NEW (cfg, load, load_op);
4840 load->inst_left = load2;
4845 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4847 add_outarg_reg (cfg, call, set_reg, arg_storage,
4849 if (&set_reg->node != call->out_args.next)
4851 MONO_INST_LIST_ADD (&set_reg->node, &call->out_args);
4856 * Part of the structure is passed on the stack.
4858 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4862 slot = ainfo->reg + j;
4864 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4865 load->ssa_op = MONO_SSA_LOAD;
4866 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4868 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4869 MONO_INST_NEW (cfg, load2, CEE_ADD);
4870 load2->inst_left = load;
4871 load2->inst_right = offset_ins;
4873 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4874 load->inst_left = load2;
4879 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4881 outarg->inst_left = load;
4882 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4883 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4885 if (&outarg->node != call->out_args.next)
4887 MONO_INST_LIST_ADD (&outarg->node, &call->out_args);
4891 /* Trees can't be shared so make a copy*/
4892 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4893 arg->cil_code = in->cil_code;
4894 arg->ssa_op = MONO_SSA_STORE;
4895 arg->inst_left = vtaddr;
4896 arg->inst_right = in;
4897 arg->type = in->type;
4898 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4902 MonoInst *stack_addr;
4904 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4906 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4907 stack_addr->inst_basereg = alpha_sp;
4908 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4909 stack_addr->inst_offset = ainfo->offset;
4910 //stack_addr->inst_offset = 16 + ainfo->offset;
4911 stack_addr->inst_imm = size;
4913 arg->opcode = OP_OUTARG_VT;
4914 arg->inst_right = stack_addr;
4918 arg->opcode = OP_OUTARG_VT;
4919 arg->klass = in->klass;
4920 arg->backend.is_pinvoke = sig->pinvoke;
4921 arg->inst_imm = size; */
4925 CFG_DEBUG(3) g_print("simple\n");
4927 switch (ainfo->storage)
4930 add_outarg_reg (cfg, call, arg, ainfo->storage,
4934 arg->opcode = OP_OUTARG;
4935 //arg->dreg = -((n - i) * 8);
4936 arg->dreg = ainfo->offset;
4937 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4939 if (!sig->params[i-sig->hasthis]->byref) {
4940 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4941 arg->opcode = OP_OUTARG_R4;
4943 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4944 arg->opcode = OP_OUTARG_R8;
4948 case ArgInDoubleReg:
4949 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4952 g_assert_not_reached ();
4958 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4960 if (cinfo->ret.storage == ArgValuetypeInReg) {
4961 MonoInst *zero_inst;
4963 * After the call, the struct is in registers, but needs to be saved
4964 to the memory pointed
4965 * to by vt_arg in this_vret_args. This means that vt_ar
4966 g needs to be saved somewhere
4967 * before calling the function. So we add a dummy instru
4968 ction to represent pushing the
4969 * struct return address to the stack. The return addres
4970 s will be saved to this stack slot
4971 * by the code emitted in this_vret_args.
4973 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4974 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
4975 zero_inst->inst_p0 = 0;
4976 arg->inst_left = zero_inst;
4977 arg->type = STACK_PTR;
4978 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4981 /* if the function returns a struct, the called method a
4982 lready does a ret $0x4 */
4983 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4984 ; //cinfo->stack_usage -= 4;
4987 // stack_usage shows how much stack we would need to do the call
4988 // (for example for params that we pass on stack
4989 call->stack_usage = cinfo->stack_usage;
4991 // Save all used regs to do the call in compile unit structure
4992 cfg->used_int_regs |= call->used_iregs;
4999 /*========================= End of Function ========================*/
5001 /*------------------------------------------------------------------*/
5003 /* Name - mono_arch_register_lowlevel_calls */
5005 /* Function - Register routines to help with --trace operation. */
5007 /*------------------------------------------------------------------*/
5010 mono_arch_register_lowlevel_calls (void)
5012 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
5014 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
5018 /*========================= End of Function ========================*/
5020 /*------------------------------------------------------------------*/
5022 /* Name - mono_arch_global_int_regs */
5024 /* Function - Return a list of usable integer registers. */
5026 /*------------------------------------------------------------------*/
5029 mono_arch_get_global_int_regs (MonoCompile *cfg)
5033 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5035 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5036 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5037 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5038 regs = g_list_prepend (regs, (gpointer)alpha_r12);
5039 regs = g_list_prepend (regs, (gpointer)alpha_r13);
5040 regs = g_list_prepend (regs, (gpointer)alpha_r14);
5045 /*========================= End of Function ========================*/
5047 /*------------------------------------------------------------------*/
5049 /* Name - mono_arch_get_allocatable_int_vars */
5053 /*------------------------------------------------------------------*/
5056 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
5060 MonoMethodSignature *sig;
5061 MonoMethodHeader *header;
5064 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5066 header = mono_method_get_header (cfg->method);
5068 sig = mono_method_signature (cfg->method);
5070 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5072 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5074 MonoInst *ins = cfg->args [i];
5076 ArgInfo *ainfo = &cinfo->args [i];
5079 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5082 // if (ainfo->storage == ArgInIReg) {
5083 // /* The input registers are non-volatile */
5084 // ins->opcode = OP_REGVAR;
5085 //ins->dreg = 32 + ainfo->reg;
5089 for (i = 0; i < cfg->num_varinfo; i++)
5091 MonoInst *ins = cfg->varinfo [i];
5092 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
5095 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
5099 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
5100 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
5103 if (mono_is_regsize_var (ins->inst_vtype))
5105 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
5106 g_assert (i == vmv->idx);
5107 vars = g_list_prepend (vars, vmv);
5111 vars = mono_varlist_sort (cfg, vars, 0);
5116 /*========================= End of Function ========================*/
5118 /*------------------------------------------------------------------*/
5120 /* Name - mono_arch_get_domain_intrinsic */
5126 /*------------------------------------------------------------------*/
5129 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5133 if (appdomain_tls_offset == -1)
5136 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5137 ins->inst_offset = appdomain_tls_offset;
5141 /*========================= End of Function ========================*/
5143 /*------------------------------------------------------------------*/
5145 /* Name - mono_arch_get_thread_intrinsic */
5151 /*------------------------------------------------------------------*/
5154 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5158 if (thread_tls_offset == -1)
5161 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5162 ins->inst_offset = thread_tls_offset;
5166 /*========================= End of Function ========================*/
5168 /*------------------------------------------------------------------*/
5170 /* Name - mono_arch_get_inst_for_method */
5172 /* Function - Check for opcodes we can handle directly in */
5175 /*------------------------------------------------------------------*/
5178 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5179 MonoMethodSignature *fsig, MonoInst **args)
5181 MonoInst *ins = NULL;
5183 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5185 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5190 /*========================= End of Function ========================*/
5192 /*------------------------------------------------------------------*/
5194 /* Name - mono_arch_create_class_init_trampoline */
5196 /* Function - Creates a trampoline function to run a type init- */
5197 /* ializer. If the trampoline is called, it calls */
5198 /* mono_runtime_class_init with the given vtable, */
5199 /* then patches the caller code so it does not get */
5200 /* called any more. */
5202 /* Parameter - vtable - The type to initialize */
5204 /* Returns - A pointer to the newly created code */
5206 /*------------------------------------------------------------------*/
5209 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5211 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5218 /*------------------------------------------------------------------*/
5220 /* Name - mono_arch_instrument_prolog */
5222 /* Function - Create an "instrumented" prolog. */
5224 /*------------------------------------------------------------------*/
5227 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5228 gboolean enable_arguments)
5230 unsigned int *code = p;
5233 CallInfo *cinfo = NULL;
5234 MonoMethodSignature *sig;
5236 int i, n, stack_area = 0;
5237 AlphaGotData ge_data;
5239 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5241 /* Keep this in sync with mono_arch_get_argument_info */
5242 if (enable_arguments)
5244 /* Allocate a new area on the stack and save arguments there */
5245 sig = mono_method_signature (cfg->method);
5247 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5249 n = sig->param_count + sig->hasthis;
5251 stack_area = ALIGN_TO (n * 8, 8);
5253 // Correct stack by calculated value
5255 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5257 for (i = 0; i < n; ++i)
5259 inst = cfg->args [i];
5261 if (inst->opcode == OP_REGVAR)
5263 switch(cinfo->args[i].storage)
5265 case ArgInDoubleReg:
5266 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5269 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5272 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5277 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5278 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5283 offset = (char *)code - (char *)cfg->native_code;
5285 ge_data.data.p = cfg->method;
5287 add_got_entry(cfg, GT_PTR, ge_data,
5288 (char *)code - (char *)cfg->native_code,
5289 MONO_PATCH_INFO_METHODCONST, cfg->method);
5290 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5292 alpha_mov1(code, alpha_sp, alpha_a1);
5294 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5296 if (enable_arguments)
5298 // Correct stack back by calculated value
5300 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5308 /*========================= End of Function ========================*/
5318 /*------------------------------------------------------------------*/
5320 /* Name - mono_arch_instrument_epilog */
5322 /* Function - Create an epilog that will handle the returned */
5323 /* values used in instrumentation. */
5325 /*------------------------------------------------------------------*/
5328 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p,
5329 gboolean enable_arguments)
5331 unsigned int *code = p;
5332 int save_mode = SAVE_NONE;
5334 MonoMethod *method = cfg->method;
5335 AlphaGotData ge_data;
5336 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5338 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5342 case MONO_TYPE_VOID:
5343 /* special case string .ctor icall */
5344 if (strcmp (".ctor", method->name) &&
5345 method->klass == mono_defaults.string_class)
5346 save_mode = SAVE_R0;
5348 save_mode = SAVE_NONE;
5352 save_mode = SAVE_R0;
5356 save_mode = SAVE_XMM;
5358 case MONO_TYPE_VALUETYPE:
5359 save_mode = SAVE_STRUCT;
5362 save_mode = SAVE_R0;
5366 /* Save the result and copy it into the proper argument register */
5370 alpha_lda(code, alpha_sp, alpha_sp, -8);
5371 alpha_stq(code, alpha_r0, alpha_sp, 0);
5373 if (enable_arguments)
5374 alpha_mov1(code, alpha_r0, alpha_a1);
5379 if (enable_arguments)
5380 alpha_lda(code, alpha_a1, alpha_zero, 0);
5384 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5385 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5387 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5389 * The result is already in the proper argument register so no copying
5396 g_assert_not_reached ();
5399 offset = (char *)code - (char *)cfg->native_code;
5401 ge_data.data.p = cfg->method;
5403 add_got_entry(cfg, GT_PTR, ge_data,
5404 (char *)code - (char *)cfg->native_code,
5405 MONO_PATCH_INFO_METHODCONST, cfg->method);
5407 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5409 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5411 /* Restore result */
5415 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5416 alpha_lda(code, alpha_sp, alpha_sp, 8);
5422 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5423 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5424 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5429 g_assert_not_reached ();
5435 /*========================= End of Function ========================*/
5437 /*------------------------------------------------------------------*/
5439 /* Name - mono_arch_allocate_vars */
5441 /* Function - Set var information according to the calling */
5442 /* convention for Alpha. The local var stuff should */
5443 /* most likely be split in another method. */
5445 /* Parameter - @m - Compile unit. */
5447 * This method is called right before working with BBs. Conversion to
5448 * IR was done and some analises what registers would be used.
5449 * Collect info about registers we used - if we want to use a register
5450 * we need to allocate space for it and save on the stack in method
5453 * Alpha calling convertion:
5454 * FP -> Stack top <- SP
5455 * 0: Stack params to call others
5457 * RA <- arch.params_stack_size
5460 * [LMF info] <- arch.lmf_offset
5462 * [possible return values allocated on stack]
5466 * . caller saved regs <- arch.reg_save_area_offset
5467 * . a0 <- arch.args_save_area_offset
5473 * ------------------------
5474 * . a6 - passed args on stack
5477 /*------------------------------------------------------------------*/
5480 mono_arch_allocate_vars (MonoCompile *cfg)
5482 MonoMethodSignature *sig;
5483 MonoMethodHeader *header;
5485 int i, offset = 0, a_off = 0;
5486 guint32 locals_stack_size, locals_stack_align = 0;
5490 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5492 header = mono_method_get_header (cfg->method);
5494 sig = mono_method_signature (cfg->method);
5496 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5498 /* if (cfg->arch.omit_fp) {
5499 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5500 cfg->frame_reg = AMD64_RSP;
5505 /* Locals are allocated forwards from FP. After
5506 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5507 * (starting from offset 16).
5508 * FIXME: Check there Arg6...Argn are supposed to be
5510 cfg->frame_reg = alpha_fp;
5511 // offset = MONO_ALPHA_VARS_OFFSET;
5514 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5515 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5516 offset += cfg->arch.params_stack_size;
5518 offset += 16; // Size to save RA & FP
5520 if (cfg->method->save_lmf)
5522 /* Reserve stack space for saving LMF + argument regs */
5523 guint32 size = sizeof (MonoLMF);
5525 //if (lmf_tls_offset == -1)
5526 // /* Need to save argument regs too */
5527 // size += (AMD64_NREG * 8) + (8 * 8);
5529 cfg->arch.lmf_offset = offset;
5532 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5533 cfg->method->name, cfg->arch.lmf_offset, size);
5536 if (sig->ret->type != MONO_TYPE_VOID)
5538 switch (cinfo->ret.storage)
5542 case ArgInDoubleReg:
5543 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5544 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5545 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5547 /* The register is volatile */
5548 cfg->ret->opcode = OP_REGOFFSET;
5549 cfg->ret->inst_basereg = cfg->frame_reg;
5551 /*if (cfg->arch.omit_fp) {
5552 cfg->ret->inst_offset = offset;
5556 cfg->ret->inst_offset = offset;
5557 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5563 cfg->ret->opcode = OP_REGVAR;
5564 cfg->ret->inst_c0 = cinfo->ret.reg;
5567 case ArgValuetypeInReg:
5568 /* Allocate a local to hold the result, the epilog will
5569 copy it to the correct place */
5570 // g_assert (!cfg->arch.omit_fp);
5572 cfg->ret->opcode = OP_REGOFFSET;
5573 cfg->ret->inst_basereg = cfg->frame_reg;
5574 cfg->ret->inst_offset = offset;
5577 g_assert_not_reached ();
5579 cfg->ret->dreg = cfg->ret->inst_c0;
5582 /* Allocate locals */
5583 offsets = mono_allocate_stack_slots_full (cfg,
5584 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5586 &locals_stack_align);
5588 //g_assert((locals_stack_size % 8) == 0);
5589 if (locals_stack_size % 8)
5591 locals_stack_size += 8 - (locals_stack_size % 8);
5594 /* if (locals_stack_align)
5596 offset += (locals_stack_align - 1);
5597 offset &= ~(locals_stack_align - 1);
5601 cfg->arch.localloc_offset = offset;
5603 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5604 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5605 locals_stack_size, locals_stack_size);
5607 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5609 if (offsets [i] != -1) {
5610 MonoInst *inst = cfg->varinfo [i];
5611 inst->opcode = OP_REGOFFSET;
5612 inst->inst_basereg = cfg->frame_reg;
5613 //if (cfg->arch.omit_fp)
5614 // inst->inst_offset = (offset + offsets [i]);
5616 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5618 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5619 CFG_DEBUG(3) mono_print_tree_nl (inst);
5623 // TODO check how offsets[i] are calculated
5624 // it seems they are points to the end on data. Like 8, but it actually - 0
5626 offset += locals_stack_size; //+8;
5628 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5629 // g_assert (!cfg->arch.omit_fp);
5630 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5631 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5634 // Save offset for caller saved regs
5635 cfg->arch.reg_save_area_offset = offset;
5637 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5639 // Reserve space for caller saved registers
5640 for (i = 0; i < MONO_MAX_IREGS; ++i)
5641 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5642 (cfg->used_int_regs & (1 << i)))
5644 offset += sizeof (gpointer);
5647 // Save offset to args regs
5648 cfg->arch.args_save_area_offset = offset;
5650 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5652 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5654 ArgInfo *ainfo = &cinfo->args [i];
5656 switch(ainfo->storage)
5660 case ArgInDoubleReg:
5661 offset += sizeof (gpointer);
5664 offset += ainfo->nregs * sizeof (gpointer);
5671 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5674 // Reserve space for method params
5675 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5677 inst = cfg->args [i];
5679 if (inst->opcode != OP_REGVAR)
5681 ArgInfo *ainfo = &cinfo->args [i];
5682 gboolean inreg = TRUE;
5685 if (sig->hasthis && (i == 0))
5686 arg_type = &mono_defaults.object_class->byval_arg;
5688 arg_type = sig->params [i - sig->hasthis];
5690 /* FIXME: Allocate volatile arguments to registers */
5691 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5695 * Under AMD64, all registers used to pass arguments to functions
5696 * are volatile across calls. For Alpha too.
5697 * FIXME: Optimize this.
5701 if (inreg && (ainfo->storage == ArgInIReg)
5702 //&& cfg->used_int_regs & (1 << ainfo->reg)
5706 if (//(ainfo->storage == ArgInIReg) ||
5707 (ainfo->storage == ArgInFloatReg) ||
5708 (ainfo->storage == ArgInDoubleReg) ||
5709 (ainfo->storage == ArgValuetypeInReg))
5712 inst->opcode = OP_REGOFFSET;
5714 switch (ainfo->storage)
5718 case ArgInDoubleReg:
5719 inst->opcode = OP_REGVAR;
5720 inst->dreg = ainfo->reg;
5723 // g_assert (!cfg->arch.omit_fp);
5724 inst->opcode = OP_REGOFFSET;
5725 inst->inst_basereg = cfg->frame_reg;
5727 // "offset" here will point to the end of
5728 // array of saved ret,locals, args
5729 // Ideally it would point to "a7"
5730 inst->inst_offset = ainfo->offset + offset;
5732 case ArgValuetypeInReg:
5742 if (!inreg && (ainfo->storage != ArgOnStack))
5744 inst->opcode = OP_REGOFFSET;
5745 inst->inst_basereg = cfg->frame_reg;
5747 /* These arguments are saved to the stack in the prolog */
5748 /*if (cfg->arch.omit_fp) {
5749 inst->inst_offset = offset;
5750 offset += (ainfo->storage == ArgValuetypeInReg) ?
5751 2 * sizeof (gpointer) : sizeof (gpointer);
5754 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5755 // 2 * sizeof (gpointer) : sizeof (gpointer);
5757 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5758 switch(ainfo->storage)
5761 a_off += ainfo->nslots * 8;
5764 a_off += sizeof (gpointer);
5766 // (/*(ainfo->reg - 16)*/ i * 8);
5772 cfg->stack_offset = offset;
5777 /*========================= End of Function ========================*/
5779 /*------------------------------------------------------------------*/
5781 /* Name - mono_arch_print_tree */
5783 /* Function - Print platform-specific opcode details. */
5785 /* Returns - 1 - opcode details have been printed */
5786 /* 0 - opcode details have not been printed */
5788 /*------------------------------------------------------------------*/
5791 mono_arch_print_tree (MonoInst *tree, int arity)
5795 ALPHA_DEBUG("mono_arch_print_tree");
5797 switch (tree->opcode) {
5804 /*========================= End of Function ========================*/
5808 ** mono_arch_get_vcall_slot_addr
5809 ** is called by mono_magic_trampoline to determine that the JIT compiled
5810 ** method is called via vtable slot. We need to analyze call sequence
5811 ** and determine that. In case it is true - we need to return address
5814 ** code - points to the next instruction after call
5815 ** reg - points to saved regs before the call (this is done
5816 ** by mono_magic_trampoline function
5820 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
5822 unsigned int *pc = (unsigned int *)code;
5824 int start_index = -2;
5826 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5829 // Check if we have parameters on stack
5830 if ((pc[-2] & 0xFFFF0000) == 0x23DE0000) // lda sp,-n(sp)
5833 // Check for (call_membase):
5834 // -4: mov v0,a0 - load this ???
5835 // -3: ldq v0,0(v0) - load vtable
5836 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5837 if ((pc[start_index-1] & 0xFC00FFFF) == 0xA4000000 &&
5838 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5841 disp = pc[start_index] & 0xFFFF;
5842 reg = (pc[start_index-1] >> AXP_REG1_SHIFT) & AXP_REG_MASK;
5843 //reg = 0; // For now
5845 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5847 return (gpointer)(((guint64)(regs [reg])) + disp);
5850 // Check for interface call
5853 // -3: ldq v0,-n(v0)
5854 // -2: ldq t12,0(v0)
5855 if ((pc[start_index-2] & 0xFC00FFFF) == 0xA4000000 &&
5856 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5857 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5860 disp = pc[start_index] & 0xFFFF;;
5863 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5865 return (gpointer)(((guint64)(regs [reg])) + disp);
5872 mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
5874 unsigned int *pc = (unsigned int *)code;
5876 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_this_arg_from_call] code: %p regs: %p",
5879 if (MONO_TYPE_ISSTRUCT (sig->ret))
5880 return (gpointer)regs [alpha_a1];
5882 return (gpointer)regs [alpha_a0];
5886 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5888 unsigned int *code, *start;
5889 MonoDomain *domain = mono_domain_get ();
5892 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_delegate_invoke_impl]");
5894 /* FIXME: Support more cases */
5895 if (MONO_TYPE_ISSTRUCT (sig->ret))
5902 mono_arch_get_patch_offset (guint8 *code)
5908 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5910 /* FIXME: implement */
5911 g_assert_not_reached ();