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;
94 /*====================== End of Global Variables ===================*/
96 gpointer mono_arch_get_lmf_addr (void);
103 ArgValuetypeInReg, // ??
114 /* Only if storage == ArgAggregate */
116 //AggregateType atype; // So far use only AggregateNormal
122 // guint32 struct_ret; /// ???
126 gboolean need_stack_align;
133 static CallInfo* get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke);
134 static unsigned int *emit_call(MonoCompile *cfg, unsigned int *code,
135 guint32 patch_type, gconstpointer data);
138 static int param_regs [] =
145 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
148 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
150 ainfo->offset = *stack_size;
152 if (*gr >= PARAM_REGS)
154 ainfo->storage = ArgOnStack;
155 (*stack_size) += sizeof (gpointer);
159 ainfo->storage = ArgInIReg;
160 ainfo->reg = param_regs [*gr];
165 #define FLOAT_PARAM_REGS 6
166 static int fparam_regs [] = { alpha_fa0, alpha_fa1, alpha_fa2, alpha_fa3,
167 alpha_fa4, alpha_fa5 };
170 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo,
173 ainfo->offset = *stack_size;
175 if (*gr >= FLOAT_PARAM_REGS)
177 ainfo->storage = ArgOnStack;
178 (*stack_size) += sizeof (gpointer);
182 /* A double register */
184 ainfo->storage = ArgInDoubleReg;
186 ainfo->storage = ArgInFloatReg;
188 ainfo->reg = fparam_regs [*gr];
194 add_valuetype (MonoGenericSharingContext *ctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
196 guint32 *gr, guint32 *fr, guint32 *stack_size)
200 MonoMarshalType *info;
201 //gboolean is_hfa = TRUE;
202 //guint32 hfa_type = 0;
204 klass = mono_class_from_mono_type (type);
205 if (type->type == MONO_TYPE_TYPEDBYREF)
206 size = 3 * sizeof (gpointer);
207 else if (sig->pinvoke)
208 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
210 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
212 if (!sig->pinvoke || (size == 0) || is_return) {
213 /* Allways pass in memory */
214 ainfo->offset = *stack_size;
215 *stack_size += ALIGN_TO (size, 8);
216 ainfo->storage = ArgOnStack;
221 info = mono_marshal_load_type_info (klass);
224 ainfo->storage = ArgAggregate;
225 //ainfo->atype = AggregateNormal;
228 /* This also handles returning of TypedByRef used by some icalls */
231 ainfo->reg = IA64_R8;
232 ainfo->nregs = (size + 7) / 8;
233 ainfo->nslots = ainfo->nregs;
240 ainfo->reg = param_regs [*gr];
241 ainfo->offset = *stack_size;
242 ainfo->nslots = (size + 7) / 8;
244 if (((*gr) + ainfo->nslots) <= 6) {
245 /* Fits entirely in registers */
246 ainfo->nregs = ainfo->nslots;
247 (*gr) += ainfo->nregs;
251 ainfo->nregs = 6 - (*gr);
253 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
257 // This function is called from mono_arch_call_opcode and
258 // should determine which registers will be used to do the call
259 // For Alpha we could calculate number of parameter used for each
260 // call and allocate space in stack only for whose "a0-a5" registers
261 // that will be used in calls
263 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
264 ArgStorage storage, int reg, MonoInst *tree)
269 arg->opcode = OP_OUTARG_REG;
270 arg->inst_left = tree;
271 arg->inst_right = (MonoInst*)call;
272 arg->backend.reg3 = reg;
273 call->used_iregs |= 1 << reg;
276 arg->opcode = OP_OUTARG_FREG;
277 arg->inst_left = tree;
278 arg->inst_right = (MonoInst*)call;
279 arg->backend.reg3 = reg;
280 call->used_fregs |= 1 << reg;
283 arg->opcode = OP_OUTARG_FREG;
284 arg->inst_left = tree;
285 arg->inst_right = (MonoInst*)call;
286 arg->backend.reg3 = reg;
287 call->used_fregs |= 1 << reg;
290 g_assert_not_reached ();
294 static void add_got_entry(MonoCompile *cfg, AlphaGotType ge_type,
295 AlphaGotData ge_data,
296 int ip, MonoJumpInfoType type, gconstpointer target)
298 AlphaGotEntry *AGE = mono_mempool_alloc (cfg->mempool,
299 sizeof (AlphaGotEntry));
306 AGE->value.data.i = ge_data.data.i;
309 AGE->value.data.l = ge_data.data.l;
312 AGE->value.data.p = ge_data.data.p;
315 AGE->value.data.f = ge_data.data.f;
318 AGE->value.data.d = ge_data.data.d;
321 AGE->value.data.l = ip;
327 if (type != MONO_PATCH_INFO_NONE)
329 mono_add_patch_info(cfg, ip, type, target);
330 AGE->patch_info = cfg->patch_info;
335 if (AGE->type != GT_LD_GTADDR)
337 mono_add_patch_info(cfg, ip, MONO_PATCH_INFO_GOT_OFFSET, 0);
338 AGE->got_patch_info = cfg->patch_info;
341 AGE->next = cfg->arch.got_data;
343 cfg->arch.got_data = AGE;
346 /*------------------------------------------------------------------*/
348 /* Name - mono_arch_create_vars */
355 * cfg - pointer to compile unit
358 * This method is called right before starting converting compiled
359 * method to IR. I guess we could find out how many arguments we
360 * should expect, what type and what return value would be.
361 * After that we could correct "cfg" structure, or "arch" part of
365 /*------------------------------------------------------------------*/
368 mono_arch_create_vars (MonoCompile *cfg)
370 MonoMethodSignature *sig;
373 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
375 sig = mono_method_signature (cfg->method);
377 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
379 if (cinfo->ret.storage == ArgValuetypeInReg)
380 cfg->ret_var_is_local = TRUE;
386 /*------------------------------------------------------------------*/
388 /* Name - mono_arch_get_lmf_addr */
394 /*------------------------------------------------------------------*/
397 mono_arch_get_lmf_addr (void)
399 ALPHA_DEBUG("mono_arch_get_lmf_addr");
401 return pthread_getspecific (lmf_addr_key);
404 /*========================= End of Function ========================*/
406 /*------------------------------------------------------------------*/
408 /* Name - mono_arch_free_jit_tls_data */
410 /* Function - Free tls data. */
412 /*------------------------------------------------------------------*/
415 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
417 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
420 /*========================= End of Function ========================*/
423 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
427 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE pass\n");
429 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
430 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
438 * OP_MOVE reg, reg except special case (mov at, at)
440 if (ins->dreg == ins->sreg1 &&
441 ins->dreg != alpha_at)
453 if (last_ins && last_ins->opcode == OP_MOVE &&
454 ins->sreg1 == last_ins->dreg &&
455 last_ins->dreg != alpha_at &&
456 ins->dreg == last_ins->sreg1)
465 /* remove unnecessary multiplication with 1 */
466 if (ins->inst_imm == 1)
468 if (ins->dreg != ins->sreg1)
470 ins->opcode = OP_MOVE;
481 case OP_LOADI8_MEMBASE:
482 case OP_LOAD_MEMBASE:
484 * Note: if reg1 = reg2 the load op is removed
486 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
487 * OP_LOADI8_MEMBASE offset(basereg), reg2
489 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
493 (last_ins->opcode == OP_STOREI8_MEMBASE_REG ||
494 last_ins->opcode == OP_STORE_MEMBASE_REG) &&
495 ins->inst_basereg == last_ins->inst_destbasereg &&
496 ins->inst_offset == last_ins->inst_offset)
498 if (ins->dreg == last_ins->sreg1)
505 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
506 ins->opcode = OP_MOVE;
507 ins->sreg1 = last_ins->sreg1;
513 case OP_LOAD_MEMBASE:
514 case OP_LOADI4_MEMBASE:
516 * Note: if reg1 = reg2 the load op is removed
518 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
519 * OP_LOAD_MEMBASE offset(basereg), reg2
521 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
524 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
525 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
526 ins->inst_basereg == last_ins->inst_destbasereg &&
527 ins->inst_offset == last_ins->inst_offset)
529 if (ins->dreg == last_ins->sreg1)
536 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
537 ins->opcode = OP_MOVE;
538 ins->sreg1 = last_ins->sreg1;
542 * Note: reg1 must be different from the basereg in the second load
543 * Note: if reg1 = reg2 is equal then second load is removed
545 * OP_LOAD_MEMBASE offset(basereg), reg1
546 * OP_LOAD_MEMBASE offset(basereg), reg2
548 * OP_LOAD_MEMBASE offset(basereg), reg1
552 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
553 || last_ins->opcode == OP_LOAD_MEMBASE) &&
554 ins->inst_basereg != last_ins->dreg &&
555 ins->inst_basereg == last_ins->inst_basereg &&
556 ins->inst_offset == last_ins->inst_offset)
558 if (ins->dreg == last_ins->dreg)
565 ins->opcode = OP_MOVE;
566 ins->sreg1 = last_ins->dreg;
569 //g_assert_not_reached ();
579 // Convert to opposite branch opcode
580 static guint16 cvt_branch_opcode(guint16 opcode)
585 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
590 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
594 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
598 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
602 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
606 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
610 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
614 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
618 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
622 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
626 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
630 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
634 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
638 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
642 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
646 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
650 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
654 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
658 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
662 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
666 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
670 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
674 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
678 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
682 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
689 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
694 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
696 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
702 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
713 return OP_ALPHA_CMP_EQ;
715 return OP_ALPHA_CMP_ULE;
717 return OP_ALPHA_CMP_LE;
719 return OP_ALPHA_CMP_LT;
721 return OP_ALPHA_CMP_ULT;
726 case OP_ICOMPARE_IMM:
732 return OP_ALPHA_CMP_IMM_EQ;
734 return OP_ALPHA_CMP_IMM_ULE;
736 return OP_ALPHA_CMP_IMM_LE;
738 return OP_ALPHA_CMP_IMM_LT;
740 return OP_ALPHA_CMP_IMM_ULT;
745 g_assert_not_reached();
750 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
752 // Instead of compare+b<cond>,
753 // Alpha has compare<cond>+br<cond>
754 // we need to convert
755 // Handle floating compare here too
761 // Convert cmp + beq -> cmpeq + bne
762 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
763 next->opcode = cvt_branch_opcode(next->opcode);
768 // cmp + ibne_un -> cmpeq + beq
769 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
770 next->opcode = cvt_branch_opcode(next->opcode);
775 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
776 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
777 next->opcode = cvt_branch_opcode(next->opcode);
782 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
783 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
784 next->opcode = cvt_branch_opcode(next->opcode);
789 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
790 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
791 next->opcode = cvt_branch_opcode(next->opcode);
796 // lcmp + blt.un -> cmpult + bne
797 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
798 next->opcode = cvt_branch_opcode(next->opcode);
803 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
804 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
805 next->opcode = cvt_branch_opcode(next->opcode);
810 //lcmp + bge.un -> cmpult + beq
811 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
812 next->opcode = cvt_branch_opcode(next->opcode);
817 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
818 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
819 next->opcode = cvt_branch_opcode(next->opcode);
824 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
825 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
826 next->opcode = cvt_branch_opcode(next->opcode);
832 // cmp + cgt_un -> cmpule + beq
833 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
838 // cmp + iceq -> cmpeq + bne
839 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
844 // cmp + int_cgt -> cmple + beq
845 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
850 // cmp + int_clt -> cmplt + bne
851 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
856 // cmp + int_clt_un -> cmpult + bne
857 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
861 // The conditional exceptions will be handled in
862 // output_basic_blocks. Here we just determine correct
865 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
868 case OP_COND_EXC_GT_UN:
869 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
873 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
876 case OP_COND_EXC_LT_UN:
877 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
880 case OP_COND_EXC_LE_UN:
881 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
884 case OP_COND_EXC_NE_UN:
885 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
889 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
894 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
895 mono_inst_name(next->opcode), next->opcode);
897 // g_assert_not_reached();
905 * mono_arch_lowering_pass:
907 * Converts complex opcodes into simpler ones so that each IR instruction
908 * corresponds to one machine instruction.
911 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
913 MonoInst *ins, *n, *next, *temp;
915 if (bb->max_vreg > cfg->rs->next_vreg)
916 cfg->rs->next_vreg = bb->max_vreg;
919 * FIXME: Need to add more instructions, but the current machine
920 * description can't model some parts of the composite instructions like
924 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
932 NEW_INS (cfg, ins, temp, OP_I8CONST);
933 temp->inst_c0 = ins->inst_imm;
934 temp->dreg = mono_regstate_next_int (cfg->rs);
939 ins->opcode = CEE_MUL;
942 ins->opcode = OP_LDIV;
945 ins->opcode = OP_LREM;
948 ins->opcode = OP_IDIV;
951 ins->opcode = OP_IREM;
955 ins->sreg2 = temp->dreg;
963 // Instead of compare+b<cond>/fcompare+b<cond>,
964 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
965 // we need to convert
966 next = mono_inst_list_next (&ins->node, &bb->ins_list);
969 cvt_cmp_branch(ins, next);
974 if (!alpha_is_imm (ins->inst_imm))
976 NEW_INS (cfg, ins, temp, OP_I8CONST);
977 temp->inst_c0 = ins->inst_imm;
978 temp->dreg = mono_regstate_next_int (cfg->rs);
979 ins->opcode = OP_COMPARE;
980 ins->sreg2 = temp->dreg;
982 // We should try to reevaluate new IR opcode
986 next = mono_inst_list_next (&ins->node, &bb->ins_list);
989 cvt_cmp_branch(ins, next);
993 case OP_ICOMPARE_IMM:
994 if (!alpha_is_imm (ins->inst_imm))
996 NEW_INS (cfg, ins, temp, OP_ICONST);
997 temp->inst_c0 = ins->inst_imm;
998 temp->dreg = mono_regstate_next_int (cfg->rs);
999 ins->opcode = OP_ICOMPARE;
1000 ins->sreg2 = temp->dreg;
1002 // We should try to reevaluate new IR opcode
1006 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1009 cvt_cmp_branch(ins, next);
1013 case OP_STORE_MEMBASE_IMM:
1014 case OP_STOREI8_MEMBASE_IMM:
1015 if (ins->inst_imm != 0)
1017 NEW_INS (cfg, ins, temp, OP_I8CONST);
1018 temp->inst_c0 = ins->inst_imm;
1019 temp->dreg = mono_regstate_next_int (cfg->rs);
1020 ins->opcode = OP_STOREI8_MEMBASE_REG;
1021 ins->sreg1 = temp->dreg;
1025 case OP_STOREI4_MEMBASE_IMM:
1026 if (ins->inst_imm != 0)
1029 NEW_INS (cfg, ins, temp, OP_ICONST);
1030 temp->inst_c0 = ins->inst_imm;
1031 temp->dreg = mono_regstate_next_int (cfg->rs);
1032 ins->opcode = OP_STOREI4_MEMBASE_REG;
1033 ins->sreg1 = temp->dreg;
1037 case OP_STOREI1_MEMBASE_IMM:
1038 if (ins->inst_imm != 0 || !bwx_supported)
1041 NEW_INS (cfg, ins, temp, OP_ICONST);
1042 temp->inst_c0 = ins->inst_imm;
1043 temp->dreg = mono_regstate_next_int (cfg->rs);
1044 ins->opcode = OP_STOREI1_MEMBASE_REG;
1045 ins->sreg1 = temp->dreg;
1049 case OP_STOREI2_MEMBASE_IMM:
1050 if (ins->inst_imm != 0 || !bwx_supported)
1053 NEW_INS (cfg, ins, temp, OP_ICONST);
1054 temp->inst_c0 = ins->inst_imm;
1055 temp->dreg = mono_regstate_next_int (cfg->rs);
1056 ins->opcode = OP_STOREI2_MEMBASE_REG;
1057 ins->sreg1 = temp->dreg;
1068 case OP_ISHR_UN_IMM:
1069 if (!alpha_is_imm(ins->inst_imm))
1072 NEW_INS (cfg, ins, temp, OP_ICONST);
1073 temp->inst_c0 = ins->inst_imm;
1074 temp->dreg = mono_regstate_next_int (cfg->rs);
1079 ins->opcode = OP_IADD;
1082 ins->opcode = OP_ISUB;
1085 ins->opcode = OP_IAND;
1088 ins->opcode = OP_IOR;
1091 ins->opcode = OP_IXOR;
1094 ins->opcode = OP_ISHL;
1097 ins->opcode = OP_ISHR;
1099 case OP_ISHR_UN_IMM:
1100 ins->opcode = OP_ISHR_UN;
1106 ins->sreg2 = temp->dreg;
1112 if (!alpha_is_imm(ins->inst_imm))
1115 NEW_INS (cfg, ins, temp, OP_ICONST);
1116 temp->inst_c0 = ins->inst_imm;
1117 temp->dreg = mono_regstate_next_int (cfg->rs);
1122 ins->opcode = CEE_ADD;
1125 ins->opcode = CEE_SUB;
1128 ins->opcode = CEE_AND;
1131 ins->opcode = CEE_SHL;
1137 ins->sreg2 = temp->dreg;
1141 if (!alpha_is_imm(ins->inst_imm))
1144 NEW_INS(cfg, ins, temp, OP_ICONST);
1145 temp->inst_c0 = ins->inst_imm;
1146 temp->dreg = mono_regstate_next_int(cfg->rs);
1147 ins->sreg2 = temp->dreg;
1148 ins->opcode = OP_LSHR;
1152 if (!alpha_is_imm(ins->inst_imm))
1155 NEW_INS(cfg, ins, temp, OP_ICONST);
1156 temp->inst_c0 = ins->inst_imm;
1157 temp->dreg = mono_regstate_next_int(cfg->rs);
1158 ins->sreg2 = temp->dreg;
1159 ins->opcode = OP_LSHL;
1168 bb->max_vreg = cfg->rs->next_vreg;
1171 /*------------------------------------------------------------------*/
1173 /* Name - mono_arch_local_regalloc. */
1175 /* Function - We first scan the list of instructions and we */
1176 /* save the liveness information of each register */
1177 /* (when the register is first used, when its value */
1178 /* is set etc.). We also reverse the list of instr- */
1179 /* uctions (in the InstList list) because assigning */
1180 /* registers backwards allows for more tricks to be */
1183 /*------------------------------------------------------------------*/
1186 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1188 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_local_regalloc");
1190 if (MONO_INST_LIST_EMPTY (&bb->ins_list))
1193 mono_arch_lowering_pass (cfg, bb);
1195 mono_local_regalloc(cfg, bb);
1198 /*========================= End of Function ========================*/
1200 #define AXP_GENERAL_REGS 6
1201 #define AXP_MIN_STACK_SIZE 24
1203 /* A typical Alpha stack frame looks like this */
1205 fun: // called from outside the module.
1206 ldgp gp,0(pv) // load the global pointer
1207 fun..ng: // called from inside the module.
1208 lda sp, -SIZE( sp ) // grow the stack downwards.
1210 stq ra, 0(sp) // save the return address.
1212 stq s0, 8(sp) // callee-saved registers.
1213 stq s1, 16(sp) // ...
1215 // Move the arguments to the argument registers...
1217 mov addr, pv // Load the callee address
1218 jsr ra, (pv) // call the method.
1219 ldgp gp, 0(ra) // restore gp
1221 // return value is in v0
1223 ldq ra, 0(sp) // free stack frame
1224 ldq s0, 8(sp) // restore callee-saved registers.
1226 ldq sp, 32(sp) // restore stack pointer
1228 ret zero, (ra), 1 // return.
1231 // our call must look like this.
1237 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1238 stq ra, SIZE-48(sp) // store ra
1239 stq fp, SIZE-40(sp) // store fp (frame pointer)
1240 stq a0, SIZE-32(sp) // store args. a0 = func
1241 stq a1, SIZE-24(sp) // a1 = retval
1242 stq a2, SIZE-16(sp) // a2 = this
1243 stq a3, SIZE-8(sp) // a3 = args
1244 mov sp, fp // set frame pointer
1264 jsr ra, (pv) // call func
1265 ldgp gp, 0(ra) // restore gp.
1266 mov v0, t1 // move return value into t1
1269 ldq t0, SIZE-24(fp) // load retval into t2
1270 stl t1, 0(t0) // store value.
1281 * emit_load_volatile_arguments:
1283 * Load volatile arguments from the stack to the original input registers.
1284 * Required before a tail call.
1286 static unsigned int*
1287 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1289 MonoMethod *method = cfg->method;
1290 MonoMethodSignature *sig;
1295 /* FIXME: Generate intermediate code instead */
1297 sig = mono_method_signature (method);
1299 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1301 if (sig->ret->type != MONO_TYPE_VOID) {
1302 if ((cinfo->ret.storage == ArgInIReg) &&
1303 (cfg->ret->opcode != OP_REGVAR))
1305 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1306 cfg->ret->inst_offset);
1310 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1312 ArgInfo *ainfo = &cinfo->args [i];
1313 MonoInst *inst = cfg->args [i];
1315 switch(ainfo->storage)
1318 // We need to save all used a0-a5 params
1319 //for (i=0; i<PARAM_REGS; i++)
1321 // if (i < cinfo->reg_usage)
1323 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1324 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1326 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1327 ainfo->reg, inst->inst_offset/*offset*/);
1331 case ArgInDoubleReg:
1333 // We need to save all used af0-af5 params
1334 //for (i=0; i<PARAM_REGS; i++)
1336 // if (i < cinfo->freg_usage)
1338 switch(cinfo->args[i].storage)
1341 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1342 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1344 case ArgInDoubleReg:
1345 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1346 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1352 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1353 ainfo->reg, /*offset*/inst->inst_offset);
1362 /*------------------------------------------------------------------*/
1364 /* Name - mono_arch_emit_prolog */
1366 /* Function - Create the instruction sequence for a function */
1369 * How to handle consts and method addreses:
1370 * For method we will allocate array of qword after method epiloge.
1371 * These qword will hold readonly info to method to properly to run.
1372 * For example: qword constants, method addreses
1373 * GP will point to start of data. Offsets to the data will be equal
1374 * to "address" of data - start of GP. (GP = 0 during method jiting).
1375 * GP is easily calculated from passed PV (method start address).
1376 * The patch will update GP loadings.
1377 * The GOT section should be more than 32Kb.
1378 * The patch code should put proper offset since the real position of
1379 * qword array will be known after the function epiloge.
1381 /*------------------------------------------------------------------*/
1384 mono_arch_emit_prolog (MonoCompile *cfg)
1386 MonoMethod *method = cfg->method;
1387 MonoMethodSignature *sig = mono_method_signature (method);
1388 //int alloc_size, code_size, max_offset, quad;
1391 int i, stack_size, offset;
1392 gint32 lmf_offset = cfg->arch.lmf_offset;
1394 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1396 // FIXME: Use just one field to hold calculated stack size
1397 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1398 cfg->arch.got_data = 0;
1400 cfg->code_size = 512;
1402 code = (unsigned int *)g_malloc(cfg->code_size);
1403 cfg->native_code = (void *)code;
1405 // Emit method prolog
1406 // Calculate GP from passed PV, allocate stack
1408 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1409 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1410 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1412 offset = cfg->arch.params_stack_size;
1414 /* store call convention parameters on stack */
1415 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1416 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1418 /* set the frame pointer */
1419 alpha_mov1( code, alpha_sp, alpha_fp );
1422 if (method->save_lmf)
1425 alpha_stq(code, alpha_pv, alpha_fp,
1426 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1428 alpha_stq(code, alpha_sp, alpha_fp,
1429 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1431 alpha_stq(code, alpha_fp, alpha_fp,
1432 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1434 alpha_stq(code, alpha_gp, alpha_fp,
1435 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1438 alpha_stq(code, alpha_pv, alpha_fp,
1439 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1442 /* Save (global) regs */
1443 offset = cfg->arch.reg_save_area_offset;
1445 for (i = 0; i < MONO_MAX_IREGS; ++i)
1446 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1447 (cfg->used_int_regs & (1 << i)) &&
1448 !( ALPHA_ARGS_REGS & (1 << i)) )
1450 alpha_stq(code, i, alpha_fp, offset);
1451 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1456 offset = cfg->arch.args_save_area_offset;
1458 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1460 if (sig->ret->type != MONO_TYPE_VOID)
1462 if ((cinfo->ret.storage == ArgInIReg) &&
1463 (cfg->ret->opcode != OP_REGVAR))
1465 /* Save volatile arguments to the stack */
1466 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1467 cfg->ret->inst_offset);
1471 /* Keep this in sync with emit_load_volatile_arguments */
1472 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1474 ArgInfo *ainfo = &cinfo->args [i];
1475 MonoInst *inst = cfg->args [i];
1478 switch(ainfo->storage)
1481 // We need to save all used a0-a5 params
1483 if (inst->opcode == OP_REGVAR)
1485 alpha_mov1(code, ainfo->reg, inst->dreg);
1486 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1487 ainfo->reg, inst->dreg);
1491 alpha_stq(code, ainfo->reg, inst->inst_basereg,
1494 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1495 ainfo->reg, inst->inst_offset);
1503 for(j=0; j<ainfo->nregs; j++)
1505 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1506 ainfo->reg + j, inst->inst_offset + (8*j));
1507 alpha_stq(code, (ainfo->reg+j), inst->inst_basereg,
1508 (inst->inst_offset + (8*j)));
1513 case ArgInDoubleReg:
1515 // We need to save all used af0-af5 params
1517 switch(cinfo->args[i].storage)
1520 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1521 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1523 case ArgInDoubleReg:
1524 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1525 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1531 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1532 ainfo->reg, /*offset*/inst->inst_offset);
1539 offset = cfg->arch.reg_save_area_offset;
1542 for (i = 0; i < MONO_MAX_VREGS; ++i)
1543 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1544 (cfg->used_int_regs & (1 << i)) &&
1545 !( ALPHA_ARGS_REGS & (1 << i)) )
1547 alpha_stq(code, i, alpha_fp, offset);
1548 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1553 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1555 if (method->save_lmf)
1558 * The call might clobber argument registers, but they are already
1559 * saved to the stack/global regs.
1562 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1563 (gpointer)"mono_get_lmf_addr");
1566 alpha_stq(code, alpha_r0, alpha_fp,
1567 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1568 // Load "previous_lmf" member of MonoLMF struct
1569 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1571 // Save it to MonoLMF struct
1572 alpha_stq(code, alpha_r1, alpha_fp,
1573 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1576 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1577 alpha_stq(code, alpha_r1, alpha_r0, 0);
1582 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1583 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1586 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1588 g_assert (cfg->code_len < cfg->code_size);
1590 return (gint8 *)code;
1593 /*========================= End of Function ========================*/
1595 /*------------------------------------------------------------------*/
1597 /* Name - mono_arch_flush_register_windows */
1603 /*------------------------------------------------------------------*/
1606 mono_arch_flush_register_windows (void)
1608 ALPHA_DEBUG("mono_arch_flush_register_windows");
1610 /*========================= End of Function ========================*/
1612 /*------------------------------------------------------------------*/
1614 /* Name - mono_arch_regalloc_cost */
1616 /* Function - Determine the cost, in the number of memory */
1617 /* references, of the action of allocating the var- */
1618 /* iable VMV into a register during global register */
1621 /* Returns - Cost */
1623 /*------------------------------------------------------------------*/
1626 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1628 MonoInst *ins = cfg->varinfo [vmv->idx];
1631 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1633 if (cfg->method->save_lmf)
1634 /* The register is already saved */
1635 /* substract 1 for the invisible store in the prolog */
1636 return (ins->opcode == OP_ARG) ? 1 : 0;
1639 return (ins->opcode == OP_ARG) ? 2 : 1;
1642 /*========================= End of Function ========================*/
1646 ** This method emits call sequience
1649 static unsigned int *
1650 emit_call(MonoCompile *cfg, unsigned int *code,
1651 guint32 patch_type, gconstpointer data)
1654 AlphaGotData ge_data;
1656 offset = (char *)code - (char *)cfg->native_code;
1658 ge_data.data.p = (void *)data;
1659 add_got_entry(cfg, GT_PTR, ge_data,
1660 offset, patch_type, data);
1662 // Load call address into PV
1663 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1666 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1668 offset = (char *)code - (char *)cfg->native_code;
1671 ALPHA_LOAD_GP(offset)
1672 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1673 alpha_lda(code, alpha_gp, alpha_gp, 0);
1678 /*------------------------------------------------------------------*/
1680 /* Name - arch_get_argument_info */
1682 /* Function - Gathers information on parameters such as size, */
1683 /* alignment, and padding. arg_info should be large */
1684 /* enough to hold param_count + 1 entries. */
1686 /* Parameters - @csig - Method signature */
1687 /* @param_count - No. of parameters to consider */
1688 /* @arg_info - An array to store the result info */
1690 /* Returns - Size of the activation frame */
1692 /*------------------------------------------------------------------*/
1695 mono_arch_get_argument_info (MonoMethodSignature *csig,
1697 MonoJitArgumentInfo *arg_info)
1700 CallInfo *cinfo = get_call_info (NULL, csig, FALSE);
1701 guint32 args_size = cinfo->stack_usage;
1703 ALPHA_DEBUG("mono_arch_get_argument_info");
1705 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1708 arg_info [0].offset = 0;
1711 for (k = 0; k < param_count; k++)
1713 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1717 // The size is checked only for valuetype in trace.c
1718 arg_info [k + 1].size = 8;
1726 /*------------------------------------------------------------------*/
1728 /* Name - mono_arch_emit_epilog */
1730 /* Function - Emit the instructions for a function epilog. */
1732 /*------------------------------------------------------------------*/
1735 mono_arch_emit_epilog (MonoCompile *cfg)
1737 MonoMethod *method = cfg->method;
1740 int max_epilog_size = 128;
1741 int stack_size = cfg->arch.stack_size;
1743 gint32 lmf_offset = cfg->arch.lmf_offset;
1745 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1747 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1749 cfg->code_size *= 2;
1750 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1751 mono_jit_stats.code_reallocs++;
1754 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1756 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1757 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1760 if (method->save_lmf)
1762 /* Restore previous lmf */
1763 alpha_ldq(code, alpha_at, alpha_fp,
1764 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1765 alpha_ldq(code, alpha_ra, alpha_fp,
1766 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1767 alpha_stq(code, alpha_at, alpha_ra, 0);
1771 alpha_mov1( code, alpha_fp, alpha_sp );
1773 // Restore saved regs
1774 offset = cfg->arch.reg_save_area_offset;
1776 for (i = 0; i < MONO_MAX_IREGS; ++i)
1777 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1778 (cfg->used_int_regs & (1 << i)) &&
1779 !( ALPHA_ARGS_REGS & (1 << i)) )
1781 alpha_ldq(code, i, alpha_sp, offset);
1782 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1787 /* restore fp, ra, sp */
1788 offset = cfg->arch.params_stack_size;
1790 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1791 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1792 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1795 alpha_ret( code, alpha_ra, 1 );
1797 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1799 g_assert (cfg->code_len < cfg->code_size);
1802 /*========================= End of Function ========================*/
1804 /*------------------------------------------------------------------*/
1806 /* Name - mono_arch_emit_exceptions */
1808 /* Function - Emit the blocks to handle exception conditions. */
1810 /*------------------------------------------------------------------*/
1813 mono_arch_emit_exceptions (MonoCompile *cfg)
1815 MonoJumpInfo *patch_info;
1817 unsigned int *code, *got_start;
1818 unsigned long *corlib_exc_adr;
1819 MonoClass *exc_classes [16];
1820 guint8 *exc_throw_start [16], *exc_throw_end [16];
1821 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1822 AlphaGotEntry *got_data;
1824 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1826 /* Compute needed space */
1827 for (patch_info = cfg->patch_info; patch_info;
1828 patch_info = patch_info->next)
1830 if (patch_info->type == MONO_PATCH_INFO_EXC)
1832 if (patch_info->type == MONO_PATCH_INFO_R8)
1833 code_size += 8 + 7; /* sizeof (double) + alignment */
1834 if (patch_info->type == MONO_PATCH_INFO_R4)
1835 code_size += 4 + 7; /* sizeof (float) + alignment */
1838 // Reserve space for GOT entries
1839 for (got_data = cfg->arch.got_data; got_data;
1840 got_data = got_data->next)
1842 // Reserve space for 8 byte const (for now)
1843 if (got_data->type != GT_LD_GTADDR)
1847 while (cfg->code_len + code_size > (cfg->code_size - 16))
1849 cfg->code_size *= 2;
1850 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1851 mono_jit_stats.code_reallocs++;
1854 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1856 // Set code alignment
1857 if (((unsigned long)code) % 8)
1862 /* Add code to store conts and modify patch into to store offset in got */
1863 for (got_data = cfg->arch.got_data; got_data;
1864 got_data = got_data->next)
1866 unsigned long data = got_data->value.data.l;
1867 MonoJumpInfo *got_ref = got_data->got_patch_info;
1869 // Modify loading of GP
1870 if (got_data->type == GT_LD_GTADDR)
1872 short high_off, low_off;
1873 unsigned int *ldgp_code =
1874 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1875 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1877 high_off = got_off / 0x10000;
1878 low_off = got_off % 0x10000;
1882 // Set offset from current point to GOT array
1883 // modify the following code sequence
1884 // ldah gp, 0(pv) or ldah gp, 0(ra)
1886 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1888 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1893 patch_info = got_data->patch_info;
1895 // Check code alignment
1896 if (((unsigned long)code) % 8)
1899 got_ref->data.offset = ((char *)code - (char *)got_start);
1902 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1904 *code = (unsigned int)(data & 0xFFFFFFFF);
1906 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1911 corlib_exc_adr = (unsigned long *)code;
1913 /* add code to raise exceptions */
1915 for (patch_info = cfg->patch_info; patch_info;
1916 patch_info = patch_info->next)
1918 switch (patch_info->type)
1920 case MONO_PATCH_INFO_EXC:
1922 MonoClass *exc_class;
1923 unsigned int *buf, *buf2;
1928 // Add patch info to call mono_arch_throw_corlib_exception
1929 // method to raise corlib exception
1930 // Will be added at the begining of the patch info list
1931 mono_add_patch_info(cfg,
1932 ((char *)code - (char *)cfg->native_code),
1933 MONO_PATCH_INFO_INTERNAL_METHOD,
1934 "mono_arch_throw_corlib_exception");
1936 // Skip longword before starting the code
1941 exc_class = mono_class_from_name (mono_defaults.corlib,
1942 "System", patch_info->data.name);
1944 g_assert (exc_class);
1945 throw_ip = patch_info->ip.i;
1947 //x86_breakpoint (code);
1948 /* Find a throw sequence for the same exception class */
1949 for (i = 0; i < nthrows; ++i)
1950 if (exc_classes [i] == exc_class)
1957 // Patch original branch (patch info) to jump here
1958 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1959 patch_info->data.target =
1960 (char *)code - (char *)cfg->native_code;
1962 alpha_lda(code, alpha_a1, alpha_zero,
1963 -((short)((((char *)exc_throw_end[i] -
1964 (char *)cfg->native_code)) - throw_ip) - 4) );
1966 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
1968 alpha_bsr(code, alpha_zero, br_offset);
1974 // Save exception token type as first 32bit word for new
1975 // exception handling jump code
1976 *code = exc_class->type_token;
1979 // Patch original branch (patch info) to jump here
1980 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1981 patch_info->data.target =
1982 (char *)code - (char *)cfg->native_code;
1985 alpha_lda(code, alpha_a1, alpha_zero, 0);
1989 exc_classes [nthrows] = exc_class;
1990 exc_throw_start [nthrows] = code;
1993 // Load exception token
1994 alpha_ldl(code, alpha_a0, alpha_gp,
1995 ((char *)buf - (char *)got_start /*cfg->native_code*/));
1996 // Load corlib exception raiser code address
1997 alpha_ldq(code, alpha_pv, alpha_gp,
1998 ((char *)corlib_exc_adr -
1999 (char *)got_start /*cfg->native_code*/));
2001 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
2002 //patch_info->data.name = "mono_arch_throw_corlib_exception";
2003 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
2004 //patch_info->type = MONO_PATCH_INFO_NONE;
2005 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
2007 if (cfg->compile_aot)
2009 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
2010 //amd64_call_reg (code, GP_SCRATCH_REG);
2012 /* The callee is in memory allocated using
2014 alpha_jsr(code, alpha_ra, alpha_pv, 0);
2017 alpha_lda(buf2, alpha_a1, alpha_zero,
2018 -((short)(((char *)code - (char *)cfg->native_code) -
2023 exc_throw_end [nthrows] = code;
2035 /* Handle relocations with RIP relative addressing */
2036 for (patch_info = cfg->patch_info; patch_info;
2037 patch_info = patch_info->next)
2039 gboolean remove = FALSE;
2041 switch (patch_info->type)
2043 case MONO_PATCH_INFO_R8:
2047 code = (guint8*)ALIGN_TO (code, 8);
2049 pos = cfg->native_code + patch_info->ip.i;
2051 *(double*)code = *(double*)patch_info->data.target;
2054 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2056 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2062 case MONO_PATCH_INFO_R4:
2066 code = (guint8*)ALIGN_TO (code, 8);
2068 pos = cfg->native_code + patch_info->ip.i;
2070 *(float*)code = *(float*)patch_info->data.target;
2073 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2075 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2087 if (patch_info == cfg->patch_info)
2088 cfg->patch_info = patch_info->next;
2093 for (tmp = cfg->patch_info; tmp->next != patch_info;
2096 tmp->next = patch_info->next;
2101 cfg->code_len = (char *)code - (char *)cfg->native_code;
2103 g_assert (cfg->code_len < cfg->code_size);
2107 /*========================= End of Function ========================*/
2109 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2110 offset = ((char *)code - \
2111 (char *)cfg->native_code); \
2112 if (Tins->flags & MONO_INST_BRLABEL) \
2114 if (Tins->inst_i0->inst_c0) \
2116 CFG_DEBUG(3) g_print("inst_c0: %0lX, data: %p]\n", \
2117 Tins->inst_i0->inst_c0, \
2118 cfg->native_code + Tins->inst_i0->inst_c0); \
2119 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2123 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n", \
2124 offset, Tins->inst_i0); \
2125 mono_add_patch_info (cfg, offset, \
2126 MONO_PATCH_INFO_LABEL, Tins->inst_i0); \
2127 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2132 if (Tins->inst_true_bb->native_offset) \
2134 long br_offset = (char *)cfg->native_code + \
2135 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2136 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2137 Tins->inst_target_bb->native_offset, \
2138 cfg->native_code + \
2139 Tins->inst_true_bb->native_offset); \
2140 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2144 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2145 offset, Tins->inst_target_bb); \
2146 mono_add_patch_info (cfg, offset, \
2147 MONO_PATCH_INFO_BB, \
2148 Tins->inst_true_bb); \
2149 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2154 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2157 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2162 mono_add_patch_info (cfg, \
2164 (char *)cfg->native_code), \
2165 MONO_PATCH_INFO_EXC, EXC_NAME); \
2166 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2170 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2175 /*------------------------------------------------------------------*/
2177 /* Name - mono_arch_output_basic_block */
2179 /* Function - Perform the "real" work of emitting instructions */
2180 /* that will do the work of in the basic block. */
2182 /*------------------------------------------------------------------*/
2185 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2190 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2191 guint last_offset = 0;
2194 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2196 if (cfg->opt & MONO_OPT_PEEPHOLE)
2197 peephole_pass (cfg, bb);
2199 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2200 bb->block_num, bb, bb->native_offset);
2202 cpos = bb->max_offset;
2204 offset = ((char *)code) - ((char *)cfg->native_code);
2206 mono_debug_open_block (cfg, bb, offset);
2208 MONO_BB_FOR_EACH_INS (bb, ins) {
2209 offset = ((char *)code) - ((char *)cfg->native_code);
2211 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2213 if (offset > (cfg->code_size - max_len - 16))
2215 cfg->code_size *= 2;
2216 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2217 code = (unsigned int *)(cfg->native_code + offset);
2218 mono_jit_stats.code_reallocs++;
2221 mono_debug_record_line_number (cfg, ins, offset);
2223 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2224 mono_inst_name(ins->opcode));
2226 switch (ins->opcode)
2229 // Shift 64 bit value right
2230 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2231 ins->dreg, ins->sreg1, ins->sreg2);
2232 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2236 // Shift 64 bit value right
2237 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2238 ins->dreg, ins->sreg1, ins->sreg2);
2239 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2243 // Shift 64 bit value right by constant
2244 g_assert(alpha_is_imm(ins->inst_imm));
2245 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2246 ins->dreg, ins->sreg1, ins->inst_imm);
2247 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2251 // Shift 32 bit value left
2252 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2253 ins->dreg, ins->sreg1, ins->sreg2);
2254 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2255 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2259 // Shift 32 bit value left by constant
2260 g_assert(alpha_is_imm(ins->inst_imm));
2261 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2262 ins->dreg, ins->sreg1, ins->inst_imm);
2263 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2264 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2268 g_assert(alpha_is_imm(ins->inst_imm));
2269 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2270 ins->dreg, ins->sreg1, ins->inst_imm);
2271 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2275 g_assert(alpha_is_imm(ins->inst_imm));
2276 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2277 ins->dreg, ins->sreg1, ins->inst_imm);
2278 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2283 // Shift 32 bit value left
2284 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2285 ins->dreg, ins->sreg1, ins->sreg2);
2286 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2290 // Shift 64 bit value left
2291 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2292 ins->dreg, ins->sreg1, ins->sreg2);
2293 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2298 // Shift 32 bit value right
2299 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2300 ins->dreg, ins->sreg1, ins->sreg2);
2301 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2302 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2306 // Shift 32 bit value rigth by constant
2307 g_assert(alpha_is_imm(ins->inst_imm));
2308 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2309 ins->dreg, ins->sreg1, ins->inst_imm);
2310 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2311 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2315 // Shift 32 bit unsigned value right
2316 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2317 ins->dreg, ins->sreg1, ins->sreg2);
2318 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2319 alpha_srl(code, alpha_at /*ins->dreg*/, ins->sreg2, ins->dreg);
2322 case OP_ISHR_UN_IMM:
2323 // Shift 32 bit unassigned value rigth by constant
2324 g_assert(alpha_is_imm(ins->inst_imm));
2325 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2326 ins->dreg, ins->sreg1, ins->inst_imm);
2327 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2328 alpha_srl_(code, alpha_at /*ins->dreg*/, ins->inst_imm, ins->dreg);
2331 case OP_LSHR_UN_IMM:
2332 // Shift 64 bit unassigned value rigth by constant
2333 g_assert(alpha_is_imm(ins->inst_imm));
2334 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2335 ins->dreg, ins->sreg1, ins->inst_imm);
2336 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2340 // Sum two 64 bits regs
2341 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2342 ins->dreg, ins->sreg1, ins->sreg2);
2343 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2347 // Subtract two 64 bit regs
2348 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2349 ins->dreg, ins->sreg1, ins->sreg2);
2350 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2354 // Add imm value to 64 bits int
2355 g_assert(alpha_is_imm(ins->inst_imm));
2356 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2357 ins->dreg, ins->sreg1, ins->inst_imm);
2358 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2362 // Add two 32 bit ints
2363 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2364 ins->dreg, ins->sreg1, ins->sreg2);
2365 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2369 // Add two 32 bit ints with overflow detection
2370 // Use AT to hold flag of signed overflow
2371 // Use t12(PV) to hold unsigned overflow
2372 // Use RA to hold intermediate result
2373 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2374 ins->dreg, ins->sreg1, ins->sreg2);
2375 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2376 alpha_ble(code, ins->sreg2, 2);
2378 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2379 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2380 alpha_br(code, alpha_zero, 1);
2382 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2383 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2385 /* res <u sreg1 => unsigned overflow */
2386 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2388 alpha_mov1(code, alpha_ra, ins->dreg);
2392 // Add two 64 bit ints with overflow detection
2393 // Use AT to hold flag of signed overflow
2394 // Use t12(PV) to hold unsigned overflow
2395 // Use RA to hold intermediate result
2396 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2397 ins->dreg, ins->sreg1, ins->sreg2);
2398 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2399 alpha_ble(code, ins->sreg2, 2);
2401 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2402 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2403 alpha_br(code, alpha_zero, 1);
2405 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2406 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2408 /* res <u sreg1 => unsigned overflow */
2409 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2411 alpha_mov1(code, alpha_ra, ins->dreg);
2415 // Add imm value to 32 bits int
2416 g_assert(alpha_is_imm(ins->inst_imm));
2417 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2418 ins->dreg, ins->sreg1, ins->inst_imm);
2419 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2423 // Substract to 32 bit ints
2424 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2425 ins->dreg, ins->sreg1, ins->sreg2);
2426 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2430 // Sub imm value from 32 bits int
2431 g_assert(alpha_is_imm(ins->inst_imm));
2432 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2433 ins->dreg, ins->sreg1, ins->inst_imm);
2434 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2438 // Sub to 32 bit ints with overflow detection
2439 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2440 ins->dreg, ins->sreg1, ins->sreg2);
2441 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2442 alpha_ble(code, ins->sreg2, 2);
2444 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2445 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2446 alpha_br(code, alpha_zero, 1);
2448 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2449 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2451 /* sreg1 <u sreg2 => unsigned overflow */
2452 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2454 alpha_mov1(code, alpha_ra, ins->dreg);
2458 // Sub to 64 bit ints with overflow detection
2459 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2460 ins->dreg, ins->sreg1, ins->sreg2);
2462 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2463 alpha_ble(code, ins->sreg2, 2);
2465 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2466 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2467 alpha_br(code, alpha_zero, 1);
2469 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2470 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2472 /* sreg1 <u sreg2 => unsigned overflow */
2473 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2475 alpha_mov1(code, alpha_ra, ins->dreg);
2480 // AND to 32 bit ints
2481 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2482 ins->dreg, ins->sreg1, ins->sreg2);
2483 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2488 // AND imm value with 32 bit int
2489 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2490 ins->dreg, ins->sreg1, ins->inst_imm);
2492 g_assert(alpha_is_imm(ins->inst_imm));
2493 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2499 // OR two 32/64 bit ints
2500 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2501 ins->dreg, ins->sreg1, ins->sreg2);
2502 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2506 // OR imm value with 32 bit int
2507 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2508 ins->dreg, ins->sreg1, ins->inst_imm);
2510 g_assert(alpha_is_imm(ins->inst_imm));
2511 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2517 // XOR two 32/64 bit ints
2518 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2519 ins->dreg, ins->sreg1, ins->sreg2);
2520 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2524 // XOR imm value with 32 bit int
2525 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2526 ins->dreg, ins->sreg1, ins->inst_imm);
2528 g_assert(alpha_is_imm(ins->inst_imm));
2529 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2535 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2536 ins->dreg, ins->sreg1);
2537 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2542 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2543 ins->dreg, ins->sreg1);
2544 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2549 // NOT 32/64 bit reg
2550 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2551 ins->dreg, ins->sreg1);
2552 alpha_not(code, ins->sreg1, ins->dreg);
2560 case OP_IMUL_OVF_UN:
2563 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",
2564 ins->dreg, ins->sreg1, ins->sreg2);
2568 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2569 ins->dreg, ins->sreg1, ins->sreg2);
2570 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2574 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2575 ins->dreg, ins->sreg1, ins->inst_imm);
2579 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2581 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2585 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2586 ins->dreg, ins->sreg1);
2587 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2588 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2592 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2593 ins->dreg, ins->sreg1);
2594 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2595 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2599 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2600 ins->dreg, ins->sreg1);
2601 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2602 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2606 // Actually ICONST is 32 bits long
2607 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2608 ins->dreg, ins->inst_c0);
2611 if (ins->inst_c0 == 0)
2613 alpha_clr(code, ins->dreg);
2617 // if -32768 < const <= 32767
2618 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2620 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2621 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2622 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2626 int lo = (char *)code - (char *)cfg->native_code;
2627 AlphaGotData ge_data;
2629 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2630 ge_data.data.l = ins->inst_c0;
2632 add_got_entry(cfg, GT_LONG, ge_data,
2633 lo, MONO_PATCH_INFO_NONE, 0);
2634 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2636 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2637 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2645 // To load 64 bit values we will have to use ldah/lda combination
2646 // and temporary register. As temporary register use r28
2647 // Divide 64 bit value in two parts and load upper 32 bits into
2648 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2649 // dreg from temp reg
2650 // the 32 bit value could be loaded with ldah/lda
2651 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2652 ins->dreg, ins->inst_c0);
2655 if (ins->inst_c0 == 0)
2657 alpha_clr(code, ins->dreg);
2661 // if -32768 < const <= 32767
2662 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2663 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2666 AlphaGotData ge_data;
2668 lo = (char *)code - (char *)cfg->native_code;
2670 ge_data.data.l = ins->inst_c0;
2672 add_got_entry(cfg, GT_LONG, ge_data,
2673 lo, MONO_PATCH_INFO_NONE, 0);
2674 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2681 double d = *(double *)ins->inst_p0;
2682 AlphaGotData ge_data;
2684 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2688 add_got_entry(cfg, GT_DOUBLE, ge_data,
2689 (char *)code - (char *)cfg->native_code,
2690 MONO_PATCH_INFO_NONE, 0);
2691 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2698 float d = *(float *)ins->inst_p0;
2699 AlphaGotData ge_data;
2701 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2705 add_got_entry(cfg, GT_FLOAT, ge_data,
2706 (char *)code - (char *)cfg->native_code,
2707 MONO_PATCH_INFO_NONE, 0);
2708 alpha_lds(code, ins->dreg, alpha_gp, 0);
2713 case OP_LOADU4_MEMBASE:
2714 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2715 ins->dreg, ins->inst_basereg, ins->inst_offset);
2717 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2718 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2721 case OP_LOADU1_MEMBASE:
2722 // Load unassigned byte from REGOFFSET
2723 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2724 ins->dreg, ins->inst_basereg, ins->inst_offset);
2726 alpha_ldbu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2729 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2731 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2732 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2736 case OP_LOADU2_MEMBASE:
2737 // Load unassigned word from REGOFFSET
2738 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2739 ins->dreg, ins->inst_basereg, ins->inst_offset);
2742 alpha_ldwu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2745 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2747 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2748 (ins->inst_offset+1));
2749 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2750 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2751 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2752 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2756 case OP_LOAD_MEMBASE:
2757 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2758 ins->dreg, ins->inst_basereg, ins->inst_offset);
2759 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2762 case OP_LOADI8_MEMBASE:
2763 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2764 ins->dreg, ins->inst_basereg, ins->inst_offset);
2765 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2768 case OP_LOADI4_MEMBASE:
2769 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2770 ins->dreg, ins->inst_basereg, ins->inst_offset);
2771 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2774 case OP_LOADI1_MEMBASE:
2775 // Load sign-extended byte from REGOFFSET
2776 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2777 ins->dreg, ins->inst_basereg, ins->inst_offset);
2780 alpha_ldbu(code, ins->dreg, ins->inst_basereg,
2782 alpha_sextb(code, ins->dreg, ins->dreg);
2786 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2788 alpha_lda(code, alpha_at, ins->inst_basereg,
2789 (ins->inst_offset+1));
2790 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2791 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2795 case OP_LOADI2_MEMBASE:
2796 // Load sign-extended word from REGOFFSET
2797 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2798 ins->dreg, ins->inst_basereg, ins->inst_offset);
2801 alpha_ldwu(code, ins->dreg, ins->inst_basereg,
2803 alpha_sextw(code, ins->dreg, ins->dreg);
2807 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2809 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2810 (ins->inst_offset+1));
2811 alpha_lda(code, alpha_at, ins->inst_basereg,
2812 (ins->inst_offset+2));
2813 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2814 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2815 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2816 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2820 case OP_STOREI1_MEMBASE_IMM:
2821 // Store signed byte at REGOFFSET
2822 // Valid only for storing 0
2823 // storei1_membase_reg will do the rest
2825 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2826 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2827 g_assert(ins->inst_imm == 0);
2830 alpha_stb(code, alpha_zero, ins->inst_destbasereg,
2833 g_assert_not_reached();
2837 case OP_STOREI1_MEMBASE_REG:
2838 // Store byte at REGOFFSET
2839 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2840 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2843 alpha_stb(code, ins->sreg1, ins->inst_destbasereg,
2848 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2850 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2852 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2853 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2854 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2855 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2860 case OP_STOREI2_MEMBASE_IMM:
2861 // Store signed word at REGOFFSET
2862 // Now work only for storing 0
2863 // For now storei2_membase_reg will do the work
2865 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2866 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2868 g_assert(ins->inst_imm == 0);
2871 alpha_stw(code, alpha_zero, ins->inst_destbasereg,
2874 g_assert_not_reached();
2878 case OP_STOREI2_MEMBASE_REG:
2879 // Store signed word from reg to REGOFFSET
2880 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2881 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2885 alpha_stw(code, ins->sreg1, ins->inst_destbasereg,
2890 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2892 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2893 (ins->inst_offset+1));
2894 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2896 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2897 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2898 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2899 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2900 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2901 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2902 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2903 (ins->inst_offset+1));
2904 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2910 case OP_STOREI4_MEMBASE_IMM:
2911 // We will get here only with ins->inst_imm = 0
2912 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2913 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2915 g_assert(ins->inst_imm == 0);
2917 alpha_stl(code, alpha_zero,
2918 ins->inst_destbasereg, ins->inst_offset);
2921 case OP_STORER4_MEMBASE_REG:
2922 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2923 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2924 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2927 case OP_STORER8_MEMBASE_REG:
2928 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2929 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2930 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2934 case OP_LOADR4_MEMBASE:
2935 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2936 ins->dreg, ins->inst_basereg, ins->inst_offset);
2937 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2940 case OP_LOADR8_MEMBASE:
2941 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2942 ins->dreg, ins->inst_basereg, ins->inst_offset);
2943 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2947 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2948 ins->sreg1, ins->dreg);
2949 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
2953 // Later check different rounding and exc modes
2954 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2955 ins->sreg1, ins->sreg2, ins->dreg);
2956 alpha_addt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2961 // Later check different rounding and exc modes
2962 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2963 ins->sreg1, ins->sreg2, ins->dreg);
2964 alpha_subt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2969 // Later check different rounding and exc modes
2970 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2971 ins->sreg1, ins->sreg2, ins->dreg);
2972 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
2976 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2977 ins->sreg1, ins->dreg);
2978 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
2981 case OP_ALPHA_TRAPB:
2982 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2987 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2988 ins->sreg1, ins->dreg);
2989 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
2992 case OP_STORE_MEMBASE_IMM:
2993 case OP_STOREI8_MEMBASE_IMM:
2994 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2995 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2996 g_assert(ins->inst_imm == 0);
2998 alpha_stq(code, alpha_zero,
2999 ins->inst_destbasereg, ins->inst_offset);
3002 case OP_STORE_MEMBASE_REG:
3003 case OP_STOREI8_MEMBASE_REG:
3004 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3005 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3006 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3009 case OP_STOREI4_MEMBASE_REG:
3010 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3011 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3012 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3015 case OP_ICOMPARE_IMM:
3016 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3017 ins->sreg1, ins->dreg, ins->inst_imm);
3019 g_assert_not_reached();
3023 case OP_COMPARE_IMM:
3024 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3025 ins->sreg1, ins->dreg, ins->inst_imm);
3027 g_assert_not_reached();
3031 case OP_COMPARE: // compare two 32 bit regs
3032 case OP_LCOMPARE: // compare two 64 bit regs
3033 case OP_FCOMPARE: // compare two floats
3034 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3035 ins->sreg1, ins->sreg2, ins->dreg);
3037 g_assert_not_reached();
3041 case OP_ALPHA_CMPT_UN:
3042 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3043 ins->sreg1, ins->sreg2, ins->dreg);
3044 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3047 case OP_ALPHA_CMPT_UN_SU:
3048 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3049 ins->sreg1, ins->sreg2, ins->dreg);
3050 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3053 case OP_ALPHA_CMPT_EQ:
3054 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3055 ins->sreg1, ins->sreg2, ins->dreg);
3056 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
3059 case OP_ALPHA_CMPT_EQ_SU:
3060 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3061 ins->sreg1, ins->sreg2, ins->dreg);
3062 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
3066 case OP_ALPHA_CMPT_LT:
3067 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3068 ins->sreg1, ins->sreg2, ins->dreg);
3069 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3072 case OP_ALPHA_CMPT_LT_SU:
3073 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3074 ins->sreg1, ins->sreg2, ins->dreg);
3075 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3078 case OP_ALPHA_CMPT_LE:
3079 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3080 ins->sreg1, ins->sreg2, ins->dreg);
3081 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3084 case OP_ALPHA_CMPT_LE_SU:
3085 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3086 ins->sreg1, ins->sreg2, ins->dreg);
3087 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3090 case OP_ALPHA_CMP_EQ:
3091 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3092 ins->sreg1, ins->sreg2, ins->dreg);
3093 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3096 case OP_ALPHA_CMP_IMM_EQ:
3097 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3098 ins->sreg1, ins->inst_imm, ins->dreg);
3099 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3102 case OP_ALPHA_CMP_IMM_ULE:
3103 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%d\n",
3104 ins->sreg1, ins->inst_imm, ins->dreg);
3105 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3108 case OP_ALPHA_CMP_ULT:
3109 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3110 ins->sreg1, ins->sreg2, ins->dreg);
3111 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3114 case OP_ALPHA_CMP_IMM_ULT:
3115 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3116 ins->sreg1, ins->inst_imm, ins->dreg);
3117 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3120 case OP_ALPHA_CMP_LE:
3121 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3122 ins->sreg1, ins->sreg2, ins->dreg);
3123 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3126 case OP_ALPHA_CMP_ULE:
3127 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3128 ins->sreg1, ins->sreg2, ins->dreg);
3129 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3133 case OP_ALPHA_CMP_IMM_LE:
3134 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%d\n",
3135 ins->sreg1, ins->inst_imm, ins->dreg);
3136 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3139 case OP_ALPHA_CMP_LT:
3140 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3141 ins->sreg1, ins->sreg2, ins->dreg);
3142 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3145 case OP_ALPHA_CMP_IMM_LT:
3146 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3147 ins->sreg1, ins->inst_imm, ins->dreg);
3148 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3151 case OP_COND_EXC_GT:
3152 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3153 (char *)ins->inst_p1);
3155 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3158 case OP_COND_EXC_GT_UN:
3159 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3160 (char *)ins->inst_p1);
3162 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3165 case OP_COND_EXC_LT:
3166 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3167 (char *)ins->inst_p1);
3169 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3172 case OP_COND_EXC_LT_UN:
3173 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3174 (char *)ins->inst_p1);
3176 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3180 case OP_COND_EXC_LE_UN:
3181 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3182 (char *)ins->inst_p1);
3183 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3186 case OP_COND_EXC_NE_UN:
3187 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3188 (char *)ins->inst_p1);
3189 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3192 case OP_COND_EXC_EQ:
3193 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3194 (char *)ins->inst_p1);
3195 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3198 case OP_COND_EXC_IOV:
3199 case OP_COND_EXC_OV:
3200 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3203 case OP_COND_EXC_IC:
3205 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3208 case CEE_CONV_OVF_U4:
3209 // Convert unsigned 32 bit value to 64 bit reg
3211 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3212 ins->sreg1, ins->dreg);
3213 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3214 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3215 alpha_mov1(code, ins->sreg1, ins->dreg);
3218 case CEE_CONV_OVF_I4_UN:
3219 // Convert unsigned 32 bit value to 64 bit reg
3221 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3222 ins->sreg1, ins->dreg);
3223 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3225 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3226 alpha_mov1(code, ins->sreg1, ins->dreg);
3230 // Move I1 (byte) to dreg(64 bits) and sign extend it
3232 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3233 ins->sreg1, ins->dreg);
3235 alpha_sextb(code, ins->sreg1, ins->dreg);
3238 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3239 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3240 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3245 // Move I2 (word) to dreg(64 bits) and sign extend it
3246 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3247 ins->sreg1, ins->dreg);
3249 alpha_sextw(code, ins->sreg1, ins->dreg);
3252 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3253 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3254 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3259 // Move I4 (long) to dreg(64 bits) and sign extend it
3260 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3261 ins->sreg1, ins->dreg);
3262 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3267 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3268 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3269 ins->sreg1, ins->dreg);
3270 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3271 alpha_mov1(code, ins->sreg1, ins->dreg);
3275 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3276 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3277 ins->sreg1, ins->dreg);
3278 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3282 // Move U2 (word) to dreg(64 bits) don't sign extend it
3283 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3284 ins->sreg1, ins->dreg);
3285 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3289 // Move U4 (long) to dreg(64 bits) don't sign extend it
3290 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3291 ins->sreg1, ins->dreg);
3292 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3297 // Move U4 (long) to dreg(64 bits) don't sign extend it
3298 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3299 ins->sreg1, ins->dreg);
3300 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3303 case OP_FCONV_TO_I4:
3304 case OP_FCONV_TO_I8:
3305 // Move float to 32 bit reg
3306 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3307 ins->sreg1, ins->dreg);
3308 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3309 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3310 alpha_lda(code, alpha_sp, alpha_sp, -8);
3311 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3312 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3313 alpha_lda(code, alpha_sp, alpha_sp, 8);
3316 case OP_FCONV_TO_I2:
3317 // Move float to 16 bit reg
3318 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3319 ins->sreg1, ins->dreg);
3320 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3321 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3322 alpha_lda(code, alpha_sp, alpha_sp, -8);
3323 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3324 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3325 alpha_lda(code, alpha_sp, alpha_sp, 8);
3326 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3327 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3330 case OP_FCONV_TO_U2:
3331 // Move float to 16 bit reg as unsigned
3332 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3333 ins->sreg1, ins->dreg);
3334 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3335 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3336 alpha_lda(code, alpha_sp, alpha_sp, -8);
3337 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3338 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3339 alpha_lda(code, alpha_sp, alpha_sp, 8);
3340 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3343 case OP_FCONV_TO_U1:
3344 // Move float to 8 bit reg as unsigned
3345 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3346 ins->sreg1, ins->dreg);
3347 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3348 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3349 alpha_lda(code, alpha_sp, alpha_sp, -8);
3350 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3351 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3352 alpha_lda(code, alpha_sp, alpha_sp, 8);
3353 alpha_and_(code, ins->dreg, 0xff, ins->dreg);
3356 case OP_FCONV_TO_I1:
3357 // Move float to 8 bit reg
3358 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3359 ins->sreg1, ins->dreg);
3360 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3361 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3362 alpha_lda(code, alpha_sp, alpha_sp, -8);
3363 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3364 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3365 alpha_lda(code, alpha_sp, alpha_sp, 8);
3366 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3367 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3371 case OP_LCONV_TO_R4:
3372 // Move 32/64 bit int into float
3373 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3374 ins->sreg1, ins->dreg);
3375 alpha_lda(code, alpha_sp, alpha_sp, -8);
3376 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3377 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3378 alpha_lda(code, alpha_sp, alpha_sp, 8);
3379 alpha_cvtqs(code, ins->dreg, ins->dreg);
3384 case OP_LCONV_TO_R8:
3385 // Move 32/64 bit int into double
3386 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3387 ins->sreg1, ins->dreg);
3388 alpha_lda(code, alpha_sp, alpha_sp, -8);
3389 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3390 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3391 alpha_lda(code, alpha_sp, alpha_sp, 8);
3392 alpha_cvtqt(code, ins->dreg, ins->dreg);
3396 case OP_FCONV_TO_R4:
3397 // Convert 64 bit float to 32 bit float (T -> S)
3398 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3399 ins->sreg1, ins->dreg);
3400 alpha_cvtts_su(code, ins->sreg1, ins->dreg);
3405 // Allocate sreg1 bytes on stack, round bytes by 8,
3406 // modify SP, set dreg to end of current stack frame
3407 // top of stack is used for call params
3408 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3409 ins->sreg1, ins->dreg);
3411 alpha_addq_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3412 alpha_bic_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3413 if (ins->flags & MONO_INST_INIT)
3414 alpha_mov1(code, ins->sreg1, ins->sreg2);
3416 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3417 if (cfg->arch.params_stack_size > 0)
3419 alpha_lda(code, ins->dreg, alpha_zero,
3420 (cfg->arch.params_stack_size));
3421 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3424 alpha_mov1(code, alpha_sp, ins->dreg);
3426 if (ins->flags & MONO_INST_INIT)
3428 // TODO: Optimize it later
3429 alpha_lda(code, ins->sreg2, ins->sreg2,
3430 -(MONO_ARCH_LOCALLOC_ALIGNMENT));
3431 alpha_blt(code, ins->sreg2, 3);
3432 alpha_addq(code, ins->sreg2, ins->dreg, alpha_at);
3433 alpha_stq(code, alpha_zero, alpha_at, 0);
3434 alpha_br(code, alpha_zero, -5);
3440 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3441 ins->sreg1, ins->dreg);
3442 alpha_mov1(code, ins->sreg1, ins->dreg);
3449 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3451 alpha_clr(code, ins->dreg);
3452 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3459 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3461 alpha_clr(code, ins->dreg);
3462 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3467 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3469 alpha_clr(code, ins->dreg);
3470 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3474 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3476 alpha_clr(code, ins->dreg);
3477 alpha_fbeq(code, alpha_at, 1);
3478 alpha_lda(code, ins->dreg, alpha_zero, 1);
3481 alpha_cvttq_c(code, alpha_at, alpha_at);
3482 alpha_lda(code, alpha_sp, alpha_sp, -8);
3483 alpha_stt(code, alpha_at, alpha_sp, 0);
3484 alpha_ldq(code, alpha_at, alpha_sp, 0);
3485 alpha_lda(code, alpha_sp, alpha_sp, 8);
3487 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3492 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3494 alpha_clr(code, ins->dreg);
3495 alpha_fbne(code, alpha_at, 1);
3496 alpha_lda(code, ins->dreg, alpha_zero, 1);
3499 alpha_cvttq_c(code, alpha_at, alpha_at);
3500 alpha_lda(code, alpha_sp, alpha_sp, -8);
3501 alpha_stt(code, alpha_at, alpha_sp, 0);
3502 alpha_ldq(code, alpha_at, alpha_sp, 0);
3503 alpha_lda(code, alpha_sp, alpha_sp, 8);
3505 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3511 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3513 alpha_clr(code, ins->dreg);
3514 alpha_fbeq(code, alpha_at, 1);
3515 alpha_lda(code, ins->dreg, alpha_zero, 1);
3519 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3522 alpha_clr(code, ins->dreg);
3523 alpha_fbne(code, (alpha_at+1), 1);
3524 alpha_fbeq(code, alpha_at, 1);
3525 alpha_lda(code, ins->dreg, alpha_zero, 1);
3530 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3531 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3535 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3536 alpha_fbeq(code, (alpha_at+1), 1);
3537 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3538 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3542 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3543 alpha_fbeq(code, (alpha_at+1), 1);
3544 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3545 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3549 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge] [");
3550 alpha_fbne(code, (alpha_at+1), 1);
3551 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3555 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3556 alpha_fbeq(code, (alpha_at+1), 1);
3557 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3558 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3562 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble] [");
3563 alpha_fbne(code, (alpha_at+1), 1);
3564 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3568 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3569 alpha_fbeq(code, (alpha_at+1), 1);
3570 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3571 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3575 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt] [");
3576 alpha_fbne(code, (alpha_at+1), 1);
3577 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3581 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3582 alpha_fbeq(code, (alpha_at+1), 1);
3583 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3584 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3588 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt] [");
3589 alpha_fbne(code, (alpha_at+1), 1);
3590 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3594 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3595 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3599 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3600 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3604 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3605 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3609 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3610 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3614 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3615 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3619 if (ins->flags & MONO_INST_BRLABEL)
3621 if (ins->inst_i0->inst_c0)
3623 CFG_DEBUG(4) g_print("inst_c0: %0lX, data: %p]\n",
3624 ins->inst_i0->inst_c0,
3625 cfg->native_code + ins->inst_i0->inst_c0);
3626 alpha_br(code, alpha_zero, 0);
3630 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n",
3631 offset, ins->inst_i0);
3632 mono_add_patch_info (cfg, offset,
3633 MONO_PATCH_INFO_LABEL, ins->inst_i0);
3635 alpha_br(code, alpha_zero, 0);
3640 if (ins->inst_target_bb->native_offset)
3642 // Somehow native offset is offset from
3643 // start of the code. So convert it to
3645 long br_offset = (char *)cfg->native_code +
3646 ins->inst_target_bb->native_offset - 4 - (char *)code;
3648 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3649 ins->inst_target_bb->native_offset,
3651 ins->inst_target_bb->native_offset);
3652 alpha_br(code, alpha_zero, br_offset/4);
3656 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3657 offset, ins->inst_target_bb);
3659 mono_add_patch_info (cfg, offset,
3661 ins->inst_target_bb);
3662 alpha_br(code, alpha_zero, 0);
3669 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3672 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3680 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3681 call = (MonoCallInst*)ins;
3683 if (ins->flags & MONO_INST_HAS_METHOD)
3685 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3686 code = emit_call (cfg, code,
3687 MONO_PATCH_INFO_METHOD, call->method);
3691 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3692 code = emit_call (cfg, code,
3693 MONO_PATCH_INFO_ABS, call->fptr);
3696 //code = emit_move_return_value (cfg, ins, code);
3703 case OP_VOIDCALL_REG:
3708 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3709 call = (MonoCallInst*)ins;
3711 alpha_mov1(code, ins->sreg1, alpha_pv);
3713 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3715 offset = (char *)code - (char *)cfg->native_code;
3718 ALPHA_LOAD_GP(offset)
3719 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3720 alpha_lda(code, alpha_gp, alpha_gp, 0);
3724 case OP_FCALL_MEMBASE:
3725 case OP_CALL_MEMBASE:
3726 case OP_LCALL_MEMBASE:
3727 case OP_VCALL_MEMBASE:
3731 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_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_VOIDCALL_MEMBASE:
3751 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3752 ins->inst_basereg, ins->inst_offset);
3753 call = (MonoCallInst*)ins;
3755 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3756 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3758 offset = (char *)code - (char *)cfg->native_code;
3761 ALPHA_LOAD_GP(offset)
3762 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3763 alpha_lda(code, alpha_gp, alpha_gp, 0);
3767 case OP_START_HANDLER:
3769 // TODO - find out when we called by call_handler or resume_context
3770 // of by call_filter. There should be difference. For now just
3771 // handle - call_handler
3773 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3774 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3776 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3777 ins->inst_left->inst_offset);
3783 // Keep in sync with start_handler
3784 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3785 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3787 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3788 ins->inst_left->inst_offset);
3790 alpha_ret(code, alpha_ra, 1);
3796 // Keep in sync with start_handler
3797 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3798 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3800 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3801 ins->inst_left->inst_offset);
3803 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3804 alpha_mov1(code, ins->sreg1, alpha_r0);
3806 alpha_ret(code, alpha_ra, 1);
3810 case OP_CALL_HANDLER:
3814 offset = (char *)code - (char *)cfg->native_code;
3816 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3817 offset, ins->inst_target_bb);
3819 mono_add_patch_info (cfg, offset,
3821 ins->inst_target_bb);
3822 alpha_bsr(code, alpha_ra, 0);
3827 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3829 alpha_mov1(code, ins->sreg1, alpha_a0);
3830 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3831 (gpointer)"mono_arch_throw_exception");
3835 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3837 alpha_mov1(code, ins->sreg1, alpha_a0);
3838 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3839 (gpointer)"mono_arch_rethrow_exception");
3845 * Note: this 'frame destruction' logic is useful for tail calls,
3846 too. Keep in sync with the code in emit_epilog.
3849 AlphaGotData ge_data;
3851 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3853 /* FIXME: no tracing support... */
3854 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3855 code = mono_arch_instrument_epilog (cfg,
3856 mono_profiler_method_leave, code, FALSE);
3857 g_assert (!cfg->method->save_lmf);
3859 alpha_mov1( code, alpha_fp, alpha_sp );
3861 code = emit_load_volatile_arguments (cfg, code);
3863 offset = cfg->arch.params_stack_size;
3865 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3866 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3867 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3869 ge_data.data.p = ins->inst_p0;
3870 add_got_entry(cfg, GT_PTR, ge_data,
3871 (char *)code - (char *)cfg->native_code,
3872 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3873 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3875 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3880 mono_add_patch_info (cfg, offset,
3881 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3884 case OP_MEMORY_BARRIER:
3885 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3890 // Float register contains a value which we need to check
3892 double ni = -1.0 / 0.0;
3893 double pi = 1.0 / 0.0;
3894 AlphaGotData ge_data;
3896 CFG_DEBUG(4) g_print("ALPHA_TODO: [chfinite] sreg1=%d\n", ins->sreg1);
3897 alpha_cmptun_su(code, ins->sreg1, ins->sreg1, alpha_at);
3899 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3901 // Negative infinity
3902 ge_data.data.d = ni;
3903 add_got_entry(cfg, GT_DOUBLE, ge_data,
3904 (char *)code - (char *)cfg->native_code,
3905 MONO_PATCH_INFO_NONE, 0);
3906 alpha_ldt(code, alpha_at, alpha_gp, 0);
3908 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3911 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3913 // Positive infinity
3914 ge_data.data.d = pi;
3915 add_got_entry(cfg, GT_DOUBLE, ge_data,
3916 (char *)code - (char *)cfg->native_code,
3917 MONO_PATCH_INFO_NONE, 0);
3918 alpha_ldt(code, alpha_at, alpha_gp, 0);
3920 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3923 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3927 CFG_DEBUG(4) g_print("ALPHA_TODO: [fdiv] dest=%d, sreg1=%d, sreg2=%d\n",
3928 ins->dreg, ins->sreg1, ins->sreg2);
3929 alpha_divt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
3934 g_warning ("unknown opcode %s in %s()\n",
3935 mono_inst_name (ins->opcode), __FUNCTION__);
3937 // g_assert_not_reached ();
3941 if ( (((char *)code) -
3942 ((char *)cfg->native_code) -
3945 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3946 mono_inst_name (ins->opcode), max_len,
3947 ((char *)code) - ((char *)cfg->native_code) - offset );
3948 //g_assert_not_reached ();
3953 last_offset = offset;
3956 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3959 /*========================= End of Function ========================*/
3964 /*------------------------------------------------------------------*/
3966 /* Name - mono_arch_cpu_optimizazions */
3968 /* Function - Returns the optimizations supported on this CPU */
3970 /*------------------------------------------------------------------*/
3973 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3977 if (getenv("MONO_ALPHA_DEBUG"))
3978 mini_alpha_verbose_level = 1;
3980 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3982 /*----------------------------------------------------------*/
3983 /* no alpha-specific optimizations yet */
3984 /*----------------------------------------------------------*/
3985 *exclude_mask = MONO_OPT_LINEARS;
3986 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3990 /*========================= End of Function ========================*/
3992 /*------------------------------------------------------------------*/
3994 /* Name - mono_arch_flush_icache */
3996 /* Function - Flush the CPU icache. */
3998 /*------------------------------------------------------------------*/
4001 mono_arch_flush_icache (guint8 *code, gint size)
4003 //ALPHA_DEBUG("mono_arch_flush_icache");
4005 /* flush instruction cache to see trampoline code */
4006 asm volatile("imb":::"memory");
4009 /*========================= End of Function ========================*/
4011 /*------------------------------------------------------------------*/
4013 /* Name - mono_arch_regname */
4015 /* Function - Returns the name of the register specified by */
4016 /* the input parameter. */
4018 /*------------------------------------------------------------------*/
4021 mono_arch_regname (int reg) {
4022 static const char * rnames[] = {
4023 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
4024 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
4025 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
4026 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
4027 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
4028 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
4029 "alpha_r30", "alpha_r31"
4032 if (reg >= 0 && reg < 32)
4033 return rnames [reg];
4037 /*========================= End of Function ========================*/
4039 /*------------------------------------------------------------------*/
4041 /* Name - mono_arch_fregname */
4043 /* Function - Returns the name of the register specified by */
4044 /* the input parameter. */
4046 /*------------------------------------------------------------------*/
4049 mono_arch_fregname (int reg) {
4050 static const char * rnames[] = {
4051 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4052 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4053 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4054 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4055 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4056 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4057 "alpha_f30", "alpha_f31"
4060 if (reg >= 0 && reg < 32)
4061 return rnames [reg];
4066 /*========================= End of Function ========================*/
4068 /*------------------------------------------------------------------*/
4070 /* Name - mono_arch_patch_code */
4072 /* Function - Process the patch data created during the */
4073 /* instruction build process. This resolves jumps, */
4074 /* calls, variables etc. */
4076 /*------------------------------------------------------------------*/
4079 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
4080 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4082 MonoJumpInfo *patch_info;
4083 gboolean compile_aot = !run_cctors;
4085 ALPHA_DEBUG("mono_arch_patch_code");
4087 for (patch_info = ji; patch_info; patch_info = patch_info->next)
4089 unsigned char *ip = patch_info->ip.i + code;
4090 const unsigned char *target;
4092 target = mono_resolve_patch_target (method, domain,
4093 code, patch_info, run_cctors);
4097 switch (patch_info->type)
4100 case MONO_PATCH_INFO_BB:
4101 case MONO_PATCH_INFO_LABEL:
4104 /* No need to patch these */
4109 switch (patch_info->type)
4111 case MONO_PATCH_INFO_NONE:
4114 case MONO_PATCH_INFO_GOT_OFFSET:
4116 unsigned int *ip2 = (unsigned int *)ip;
4117 unsigned int inst = *ip2;
4118 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
4120 g_assert(!(off & 0xFFFF8000));
4128 case MONO_PATCH_INFO_CLASS_INIT:
4130 /* Might already been changed to a nop */
4131 unsigned int* ip2 = (unsigned int *)ip;
4132 unsigned long t_addr = (unsigned long)target;
4134 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
4135 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
4137 // amd64_call_code (ip2, 0);
4141 // case MONO_PATCH_INFO_METHOD_REL:
4142 case MONO_PATCH_INFO_R8:
4143 case MONO_PATCH_INFO_R4:
4144 g_assert_not_reached ();
4146 case MONO_PATCH_INFO_BB:
4149 case MONO_PATCH_INFO_METHOD:
4150 case MONO_PATCH_INFO_METHODCONST:
4151 case MONO_PATCH_INFO_INTERNAL_METHOD:
4152 case MONO_PATCH_INFO_METHOD_JUMP:
4154 volatile unsigned int *p = (unsigned int *)ip;
4155 unsigned long t_addr;
4162 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4164 if (target != ((void *)t_addr))
4166 t_addr = (unsigned long)target;
4167 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4168 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4173 case MONO_PATCH_INFO_ABS:
4175 volatile unsigned int *p = (unsigned int *)ip;
4176 unsigned long t_addr;
4182 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4187 case MONO_PATCH_INFO_SWITCH:
4189 unsigned int *pcode = (unsigned int *)ip;
4190 unsigned long t_addr;
4192 t_addr = (unsigned long)target;
4194 if (((unsigned long)ip) % 8)
4200 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4201 alpha_nop(pcode); // TODO optimize later
4202 alpha_bsr(pcode, alpha_at, 2);
4204 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4206 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4209 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4219 volatile unsigned int *p = (unsigned int *)ip;
4220 unsigned int alpha_ins = *p;
4221 unsigned int opcode;
4224 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4226 if (opcode >= 0x30 && opcode <= 0x3f)
4228 // This is branch with offset instruction
4229 br_offset = (target - ip - 4);
4231 g_assert(!(br_offset & 3));
4233 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4241 /*========================= End of Function ========================*/
4242 /*------------------------------------------------------------------*/
4244 /* Name - mono_arch_emit_this_vret_args */
4248 /*------------------------------------------------------------------*/
4251 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4252 int this_reg, int this_type, int vt_reg)
4254 MonoCallInst *call = (MonoCallInst*)inst;
4255 CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, inst->signature, FALSE);
4257 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4263 if (cinfo->ret.storage == ArgValuetypeInReg)
4266 * The valuetype is in RAX:RDX after the call, need to be copied to
4267 * the stack. Push the address here, so the call instruction can
4270 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4271 //vtarg->sreg1 = vt_reg;
4272 //mono_bblock_add_inst (cfg->cbb, vtarg);
4275 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4280 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4281 vtarg->sreg1 = vt_reg;
4282 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4283 mono_bblock_add_inst (cfg->cbb, vtarg);
4285 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4286 cinfo->ret.reg, FALSE);
4290 /* add the this argument */
4294 MONO_INST_NEW (cfg, this, OP_MOVE);
4295 this->type = this_type;
4296 this->sreg1 = this_reg;
4297 this->dreg = mono_regstate_next_int (cfg->rs);
4298 mono_bblock_add_inst (cfg->cbb, this);
4300 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4301 cinfo->args [0].reg, FALSE);
4307 /*========================= End of Function ========================*/
4309 /*------------------------------------------------------------------*/
4311 /* Name - mono_arch_is_inst_imm */
4313 /* Function - Determine if operand qualifies as an immediate */
4314 /* value. For Alpha this is a value 0 - 255 */
4316 /* Returns - True|False - is [not] immediate value. */
4318 /*------------------------------------------------------------------*/
4321 mono_arch_is_inst_imm (gint64 imm)
4323 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4325 return (imm & ~(0x0FFL)) ? 0 : 1;
4328 /*------------------------------------------------------------------*/
4330 /* Name - mono_arch_setup_jit_tls_data */
4332 /* Function - Setup the JIT's Thread Level Specific Data. */
4334 /*------------------------------------------------------------------*/
4337 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4339 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4341 if (!tls_offset_inited) {
4342 tls_offset_inited = TRUE;
4345 if (!lmf_addr_key_inited) {
4346 lmf_addr_key_inited = TRUE;
4347 pthread_key_create (&lmf_addr_key, NULL);
4350 pthread_setspecific (lmf_addr_key, &tls->lmf);
4353 /*------------------------------------------------------------------*/
4355 /* Name - mono_arch_cpu_init */
4357 /* Function - Perform CPU specific initialization to execute */
4360 /*------------------------------------------------------------------*/
4363 mono_arch_cpu_init (void)
4365 unsigned long amask, implver;
4366 register long v0 __asm__("$0") = -1;
4368 ALPHA_DEBUG("mono_arch_cpu_init");
4370 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
4372 __asm__ (".long 0x47e03d80" : "=r"(v0));
4378 //printf("amask: %x, implver: %x", amask, implver);
4382 * Initialize architecture specific code.
4385 mono_arch_init (void)
4390 * Cleanup architecture specific code.
4393 mono_arch_cleanup (void)
4400 * Obtain information about a call according to the calling convention.
4402 * For x86 ELF, see the "System V Application Binary Interface Intel386
4403 * Architecture Processor Supplment, Fourth Edition" document for more
4405 * For x86 win32, see ???.
4408 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
4410 guint32 i, gr, fr, *pgr, *pfr;
4412 int n = sig->hasthis + sig->param_count;
4413 guint32 stack_size = 0;
4416 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4431 ret_type = mono_type_get_underlying_type (sig->ret);
4432 switch (ret_type->type) {
4433 case MONO_TYPE_BOOLEAN:
4438 case MONO_TYPE_CHAR:
4444 case MONO_TYPE_FNPTR:
4445 case MONO_TYPE_CLASS:
4446 case MONO_TYPE_OBJECT:
4447 case MONO_TYPE_SZARRAY:
4448 case MONO_TYPE_ARRAY:
4449 case MONO_TYPE_STRING:
4450 cinfo->ret.storage = ArgInIReg;
4451 cinfo->ret.reg = alpha_r0;
4455 cinfo->ret.storage = ArgInIReg;
4456 cinfo->ret.reg = alpha_r0;
4459 cinfo->ret.storage = ArgInFloatReg;
4460 cinfo->ret.reg = alpha_f0;
4463 cinfo->ret.storage = ArgInDoubleReg;
4464 cinfo->ret.reg = alpha_f0;
4466 case MONO_TYPE_GENERICINST:
4467 if (!mono_type_generic_inst_is_valuetype (sig->ret))
4469 cinfo->ret.storage = ArgInIReg;
4470 cinfo->ret.reg = alpha_r0;
4474 case MONO_TYPE_VALUETYPE:
4476 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4478 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE,
4479 &tmp_gr, &tmp_fr, &tmp_stacksize);
4481 if (cinfo->ret.storage == ArgOnStack)
4482 /* The caller passes the address where the value
4484 add_general (pgr, &stack_size, &cinfo->ret);
4487 case MONO_TYPE_TYPEDBYREF:
4488 /* Same as a valuetype with size 24 */
4489 add_general (pgr, &stack_size, &cinfo->ret);
4492 case MONO_TYPE_VOID:
4495 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4501 add_general (pgr, &stack_size, cinfo->args + 0);
4503 if (!sig->pinvoke &&
4504 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4507 fr = FLOAT_PARAM_REGS;
4509 /* Emit the signature cookie just before the implicit arguments
4511 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4514 for (i = 0; i < sig->param_count; ++i)
4516 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4519 if (!sig->pinvoke &&
4520 (sig->call_convention == MONO_CALL_VARARG) &&
4521 (i == sig->sentinelpos))
4523 /* We allways pass the sig cookie on the stack for simpl
4526 * Prevent implicit arguments + the sig cookie from being passed
4530 fr = FLOAT_PARAM_REGS;
4532 /* Emit the signature cookie just before the implicit arguments */
4533 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4536 if (sig->params [i]->byref) {
4537 add_general (pgr, &stack_size, ainfo);
4541 ptype = mono_type_get_underlying_type (sig->params [i]);
4543 switch (ptype->type) {
4544 case MONO_TYPE_BOOLEAN:
4547 add_general (pgr, &stack_size, ainfo);
4551 case MONO_TYPE_CHAR:
4552 add_general (pgr, &stack_size, ainfo);
4556 add_general (pgr, &stack_size, ainfo);
4561 case MONO_TYPE_FNPTR:
4562 case MONO_TYPE_CLASS:
4563 case MONO_TYPE_OBJECT:
4564 case MONO_TYPE_STRING:
4565 case MONO_TYPE_SZARRAY:
4566 case MONO_TYPE_ARRAY:
4567 add_general (pgr, &stack_size, ainfo);
4569 case MONO_TYPE_GENERICINST:
4570 if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
4572 add_general (pgr, &stack_size, ainfo);
4576 case MONO_TYPE_VALUETYPE:
4578 /* We allways pass valuetypes on the stack */
4579 add_valuetype (gsctx, sig, ainfo, sig->params [i],
4580 FALSE, pgr, pfr, &stack_size);
4582 case MONO_TYPE_TYPEDBYREF:
4583 stack_size += sizeof (MonoTypedRef);
4584 ainfo->storage = ArgOnStack;
4588 add_general (pgr, &stack_size, ainfo);
4591 add_float (pfr, &stack_size, ainfo, FALSE);
4594 add_float (pfr, &stack_size, ainfo, TRUE);
4597 g_assert_not_reached ();
4601 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4602 (n > 0) && (sig->sentinelpos == sig->param_count))
4605 fr = FLOAT_PARAM_REGS;
4607 /* Emit the signature cookie just before the implicit arguments
4609 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4612 cinfo->stack_usage = stack_size;
4613 cinfo->reg_usage = gr;
4614 cinfo->freg_usage = fr;
4619 static const char *CvtMonoType(MonoTypeEnum t)
4624 return "MONO_TYPE_END";
4625 case MONO_TYPE_VOID:
4626 return "MONO_TYPE_VOID";
4627 case MONO_TYPE_BOOLEAN:
4628 return "MONO_TYPE_BOOLEAN";
4629 case MONO_TYPE_CHAR:
4630 return "MONO_TYPE_CHAR";
4632 return "MONO_TYPE_I1";
4634 return "MONO_TYPE_U1";
4636 return "MONO_TYPE_I2";
4638 return "MONO_TYPE_U2";
4640 return "MONO_TYPE_I4";
4642 return "MONO_TYPE_U4";
4644 return "MONO_TYPE_I8";
4646 return "MONO_TYPE_U8";
4648 return "MONO_TYPE_R4";
4650 return "MONO_TYPE_R8";
4651 case MONO_TYPE_STRING:
4652 return "MONO_TYPE_STRING";
4654 return "MONO_TYPE_PTR";
4655 case MONO_TYPE_BYREF:
4656 return "MONO_TYPE_BYREF";
4657 case MONO_TYPE_VALUETYPE:
4658 return "MONO_TYPE_VALUETYPE";
4659 case MONO_TYPE_CLASS:
4660 return "MONO_TYPE_CLASS";
4662 return "MONO_TYPE_VAR";
4663 case MONO_TYPE_ARRAY:
4664 return "MONO_TYPE_ARRAY";
4665 case MONO_TYPE_GENERICINST:
4666 return "MONO_TYPE_GENERICINST";
4667 case MONO_TYPE_TYPEDBYREF:
4668 return "MONO_TYPE_TYPEDBYREF";
4670 return "MONO_TYPE_I";
4672 return "MONO_TYPE_U";
4673 case MONO_TYPE_FNPTR:
4674 return "MONO_TYPE_FNPTR";
4675 case MONO_TYPE_OBJECT:
4676 return "MONO_TYPE_OBJECT";
4677 case MONO_TYPE_SZARRAY:
4678 return "MONO_TYPE_SZARRAY";
4679 case MONO_TYPE_MVAR:
4680 return "MONO_TYPE_MVAR";
4681 case MONO_TYPE_CMOD_REQD:
4682 return "MONO_TYPE_CMOD_REQD";
4683 case MONO_TYPE_CMOD_OPT:
4684 return "MONO_TYPE_CMOD_OPT";
4685 case MONO_TYPE_INTERNAL:
4686 return "MONO_TYPE_INTERNAL";
4687 case MONO_TYPE_MODIFIER:
4688 return "MONO_TYPE_MODIFIER";
4689 case MONO_TYPE_SENTINEL:
4690 return "MONO_TYPE_SENTINEL";
4691 case MONO_TYPE_PINNED:
4692 return "MONO_TYPE_PINNED";
4700 /*------------------------------------------------------------------*/
4702 /* Name - mono_arch_call_opcode */
4704 /* Function - Take the arguments and generate the arch-specific */
4705 /* instructions to properly call the function. This */
4706 /* includes pushing, moving argments to the correct */
4709 * This method is called during converting method to IR
4710 * We need to generate IR ints to follow calling convention
4711 * cfg - points to currently compiled unit
4713 * call - points to structure that describes what we are going to
4714 * call (at least number of parameters required for the call)
4717 * On return we need to pass back modified call structure
4719 /*------------------------------------------------------------------*/
4722 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4723 MonoCallInst *call, int is_virtual)
4726 MonoMethodSignature *sig;
4731 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4733 sig = call->signature;
4734 n = sig->param_count + sig->hasthis;
4736 // Collect info about method we age going to call
4737 cinfo = get_call_info (cfg->generic_sharing_context, sig, sig->pinvoke);
4739 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4740 sig->pinvoke ? "PInvoke" : "Managed",
4741 sig->param_count, sig->hasthis,
4742 CvtMonoType(sig->ret->type), sig->ret->type);
4744 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4745 cfg->arch.params_stack_size = cinfo->stack_usage;
4747 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4748 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4750 for (i = 0; i < n; ++i)
4752 ArgInfo *ainfo = cinfo->args + i;
4754 /* Emit the signature cookie just before the implicit arguments
4756 if (!sig->pinvoke &&
4757 (sig->call_convention == MONO_CALL_VARARG) &&
4760 MonoMethodSignature *tmp_sig;
4763 /* FIXME: Add support for signature tokens to AOT */
4764 cfg->disable_aot = TRUE;
4765 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4768 * mono_ArgIterator_Setup assumes the signature cookie is
4769 * passed first and all the arguments which were before it are
4770 * passed on the stack after the signature. So compensate by
4771 * passing a different signature.
4773 tmp_sig = mono_metadata_signature_dup (call->signature);
4774 tmp_sig->param_count -= call->signature->sentinelpos;
4775 tmp_sig->sentinelpos = 0;
4776 memcpy (tmp_sig->params,
4777 call->signature->params + call->signature->sentinelpos,
4778 tmp_sig->param_count * sizeof (MonoType*));
4780 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4781 sig_arg->inst_p0 = tmp_sig;
4783 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4784 arg->inst_left = sig_arg;
4785 arg->type = STACK_PTR;
4786 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4789 if (is_virtual && i == 0) {
4790 /* the argument will be attached to the call instrucion
4792 in = call->args [i];
4796 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4797 in = call->args [i];
4798 arg->cil_code = in->cil_code;
4799 arg->inst_left = in;
4800 arg->type = in->type;
4801 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4803 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4805 if (sig->hasthis && (i == 0))
4806 arg_type = &mono_defaults.object_class->byval_arg;
4808 arg_type = sig->params [i - sig->hasthis];
4810 if ((i >= sig->hasthis) &&
4811 (MONO_TYPE_ISSTRUCT(arg_type)))
4816 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4817 size = sizeof (MonoTypedRef);
4818 align = sizeof (gpointer);
4822 size = mono_type_native_stack_size (&in->klass->byval_arg,
4825 size = mini_type_stack_size (cfg->generic_sharing_context, &in->klass->byval_arg, &align);
4827 if (ainfo->storage == ArgAggregate)
4829 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4832 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4834 vtaddr = mono_compile_create_var (cfg,
4835 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4838 * Part of the structure is passed in registers.
4840 for (j = 0; j < ainfo->nregs; ++j)
4842 int offset, load_op, dest_reg, arg_storage;
4844 slot = ainfo->reg + j;
4845 load_op = CEE_LDIND_I;
4847 dest_reg = ainfo->reg + j;
4848 arg_storage = ArgInIReg;
4850 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4851 load->ssa_op = MONO_SSA_LOAD;
4852 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4854 NEW_ICONST (cfg, offset_ins, offset);
4855 MONO_INST_NEW (cfg, load2, CEE_ADD);
4856 load2->inst_left = load;
4857 load2->inst_right = offset_ins;
4859 MONO_INST_NEW (cfg, load, load_op);
4860 load->inst_left = load2;
4865 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4867 add_outarg_reg (cfg, call, set_reg, arg_storage,
4869 if (&set_reg->node != call->out_args.next)
4871 MONO_INST_LIST_ADD (&set_reg->node, &call->out_args);
4876 * Part of the structure is passed on the stack.
4878 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4882 slot = ainfo->reg + j;
4884 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4885 load->ssa_op = MONO_SSA_LOAD;
4886 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4888 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4889 MONO_INST_NEW (cfg, load2, CEE_ADD);
4890 load2->inst_left = load;
4891 load2->inst_right = offset_ins;
4893 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4894 load->inst_left = load2;
4899 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4901 outarg->inst_left = load;
4902 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4903 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4905 if (&outarg->node != call->out_args.next)
4907 MONO_INST_LIST_ADD (&outarg->node, &call->out_args);
4911 /* Trees can't be shared so make a copy*/
4912 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4913 arg->cil_code = in->cil_code;
4914 arg->ssa_op = MONO_SSA_STORE;
4915 arg->inst_left = vtaddr;
4916 arg->inst_right = in;
4917 arg->type = in->type;
4918 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4922 MonoInst *stack_addr;
4924 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4926 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4927 stack_addr->inst_basereg = alpha_sp;
4928 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4929 stack_addr->inst_offset = ainfo->offset;
4930 //stack_addr->inst_offset = 16 + ainfo->offset;
4931 stack_addr->inst_imm = size;
4933 arg->opcode = OP_OUTARG_VT;
4934 arg->inst_right = stack_addr;
4938 arg->opcode = OP_OUTARG_VT;
4939 arg->klass = in->klass;
4940 arg->backend.is_pinvoke = sig->pinvoke;
4941 arg->inst_imm = size; */
4945 CFG_DEBUG(3) g_print("simple\n");
4947 switch (ainfo->storage)
4950 add_outarg_reg (cfg, call, arg, ainfo->storage,
4954 arg->opcode = OP_OUTARG;
4955 //arg->dreg = -((n - i) * 8);
4956 arg->dreg = ainfo->offset;
4957 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4959 if (!sig->params[i-sig->hasthis]->byref) {
4960 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4961 arg->opcode = OP_OUTARG_R4;
4963 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4964 arg->opcode = OP_OUTARG_R8;
4968 case ArgInDoubleReg:
4969 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4972 g_assert_not_reached ();
4978 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4980 if (cinfo->ret.storage == ArgValuetypeInReg) {
4981 MonoInst *zero_inst;
4983 * After the call, the struct is in registers, but needs to be saved
4984 to the memory pointed
4985 * to by vt_arg in this_vret_args. This means that vt_ar
4986 g needs to be saved somewhere
4987 * before calling the function. So we add a dummy instru
4988 ction to represent pushing the
4989 * struct return address to the stack. The return addres
4990 s will be saved to this stack slot
4991 * by the code emitted in this_vret_args.
4993 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4994 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
4995 zero_inst->inst_p0 = 0;
4996 arg->inst_left = zero_inst;
4997 arg->type = STACK_PTR;
4998 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
5001 /* if the function returns a struct, the called method a
5002 lready does a ret $0x4 */
5003 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
5004 ; //cinfo->stack_usage -= 4;
5007 // stack_usage shows how much stack we would need to do the call
5008 // (for example for params that we pass on stack
5009 call->stack_usage = cinfo->stack_usage;
5011 // Save all used regs to do the call in compile unit structure
5012 cfg->used_int_regs |= call->used_iregs;
5019 /*========================= End of Function ========================*/
5021 /*------------------------------------------------------------------*/
5023 /* Name - mono_arch_register_lowlevel_calls */
5025 /* Function - Register routines to help with --trace operation. */
5027 /*------------------------------------------------------------------*/
5030 mono_arch_register_lowlevel_calls (void)
5032 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
5034 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
5038 /*========================= End of Function ========================*/
5040 /*------------------------------------------------------------------*/
5042 /* Name - mono_arch_global_int_regs */
5044 /* Function - Return a list of usable integer registers. */
5046 /*------------------------------------------------------------------*/
5049 mono_arch_get_global_int_regs (MonoCompile *cfg)
5053 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5055 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5056 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5057 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5058 regs = g_list_prepend (regs, (gpointer)alpha_r12);
5059 regs = g_list_prepend (regs, (gpointer)alpha_r13);
5060 regs = g_list_prepend (regs, (gpointer)alpha_r14);
5065 /*========================= End of Function ========================*/
5067 /*------------------------------------------------------------------*/
5069 /* Name - mono_arch_get_allocatable_int_vars */
5073 /*------------------------------------------------------------------*/
5076 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
5080 MonoMethodSignature *sig;
5081 MonoMethodHeader *header;
5084 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5086 header = mono_method_get_header (cfg->method);
5088 sig = mono_method_signature (cfg->method);
5090 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5092 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5094 MonoInst *ins = cfg->args [i];
5096 ArgInfo *ainfo = &cinfo->args [i];
5099 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5102 // if (ainfo->storage == ArgInIReg) {
5103 // /* The input registers are non-volatile */
5104 // ins->opcode = OP_REGVAR;
5105 //ins->dreg = 32 + ainfo->reg;
5109 for (i = 0; i < cfg->num_varinfo; i++)
5111 MonoInst *ins = cfg->varinfo [i];
5112 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
5115 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
5119 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
5120 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
5123 if (mono_is_regsize_var (ins->inst_vtype))
5125 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
5126 g_assert (i == vmv->idx);
5127 vars = g_list_prepend (vars, vmv);
5131 vars = mono_varlist_sort (cfg, vars, 0);
5136 /*========================= End of Function ========================*/
5138 /*------------------------------------------------------------------*/
5140 /* Name - mono_arch_get_domain_intrinsic */
5146 /*------------------------------------------------------------------*/
5149 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5153 if (appdomain_tls_offset == -1)
5156 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5157 ins->inst_offset = appdomain_tls_offset;
5161 /*========================= End of Function ========================*/
5163 /*------------------------------------------------------------------*/
5165 /* Name - mono_arch_get_thread_intrinsic */
5171 /*------------------------------------------------------------------*/
5174 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5178 if (thread_tls_offset == -1)
5181 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5182 ins->inst_offset = thread_tls_offset;
5186 /*========================= End of Function ========================*/
5188 /*------------------------------------------------------------------*/
5190 /* Name - mono_arch_get_inst_for_method */
5192 /* Function - Check for opcodes we can handle directly in */
5195 /*------------------------------------------------------------------*/
5198 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5199 MonoMethodSignature *fsig, MonoInst **args)
5201 MonoInst *ins = NULL;
5203 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5205 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5207 if (cmethod->klass == mono_defaults.thread_class &&
5208 strcmp (cmethod->name, "MemoryBarrier") == 0) {
5209 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5215 /*========================= End of Function ========================*/
5217 /*------------------------------------------------------------------*/
5219 /* Name - mono_arch_create_class_init_trampoline */
5221 /* Function - Creates a trampoline function to run a type init- */
5222 /* ializer. If the trampoline is called, it calls */
5223 /* mono_runtime_class_init with the given vtable, */
5224 /* then patches the caller code so it does not get */
5225 /* called any more. */
5227 /* Parameter - vtable - The type to initialize */
5229 /* Returns - A pointer to the newly created code */
5231 /*------------------------------------------------------------------*/
5234 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5236 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5243 /*------------------------------------------------------------------*/
5245 /* Name - mono_arch_instrument_prolog */
5247 /* Function - Create an "instrumented" prolog. */
5249 /*------------------------------------------------------------------*/
5252 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5253 gboolean enable_arguments)
5255 unsigned int *code = p;
5258 CallInfo *cinfo = NULL;
5259 MonoMethodSignature *sig;
5261 int i, n, stack_area = 0;
5262 AlphaGotData ge_data;
5264 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5266 /* Keep this in sync with mono_arch_get_argument_info */
5267 if (enable_arguments)
5269 /* Allocate a new area on the stack and save arguments there */
5270 sig = mono_method_signature (cfg->method);
5272 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5274 n = sig->param_count + sig->hasthis;
5276 stack_area = ALIGN_TO (n * 8, 8);
5278 // Correct stack by calculated value
5280 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5282 for (i = 0; i < n; ++i)
5284 inst = cfg->args [i];
5286 if (inst->opcode == OP_REGVAR)
5288 switch(cinfo->args[i].storage)
5290 case ArgInDoubleReg:
5291 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5294 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5297 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5302 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5303 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5308 offset = (char *)code - (char *)cfg->native_code;
5310 ge_data.data.p = cfg->method;
5312 add_got_entry(cfg, GT_PTR, ge_data,
5313 (char *)code - (char *)cfg->native_code,
5314 MONO_PATCH_INFO_METHODCONST, cfg->method);
5315 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5317 alpha_mov1(code, alpha_sp, alpha_a1);
5319 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5321 if (enable_arguments)
5323 // Correct stack back by calculated value
5325 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5333 /*========================= End of Function ========================*/
5343 /*------------------------------------------------------------------*/
5345 /* Name - mono_arch_instrument_epilog */
5347 /* Function - Create an epilog that will handle the returned */
5348 /* values used in instrumentation. */
5350 /*------------------------------------------------------------------*/
5353 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p,
5354 gboolean enable_arguments)
5356 unsigned int *code = p;
5357 int save_mode = SAVE_NONE;
5359 MonoMethod *method = cfg->method;
5360 AlphaGotData ge_data;
5361 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5363 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5367 case MONO_TYPE_VOID:
5368 /* special case string .ctor icall */
5369 if (strcmp (".ctor", method->name) &&
5370 method->klass == mono_defaults.string_class)
5371 save_mode = SAVE_R0;
5373 save_mode = SAVE_NONE;
5377 save_mode = SAVE_R0;
5381 save_mode = SAVE_XMM;
5383 case MONO_TYPE_VALUETYPE:
5384 save_mode = SAVE_STRUCT;
5387 save_mode = SAVE_R0;
5391 /* Save the result and copy it into the proper argument register */
5395 alpha_lda(code, alpha_sp, alpha_sp, -8);
5396 alpha_stq(code, alpha_r0, alpha_sp, 0);
5398 if (enable_arguments)
5399 alpha_mov1(code, alpha_r0, alpha_a1);
5404 if (enable_arguments)
5405 alpha_lda(code, alpha_a1, alpha_zero, 0);
5409 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5410 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5412 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5414 * The result is already in the proper argument register so no copying
5421 g_assert_not_reached ();
5424 offset = (char *)code - (char *)cfg->native_code;
5426 ge_data.data.p = cfg->method;
5428 add_got_entry(cfg, GT_PTR, ge_data,
5429 (char *)code - (char *)cfg->native_code,
5430 MONO_PATCH_INFO_METHODCONST, cfg->method);
5432 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5434 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5436 /* Restore result */
5440 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5441 alpha_lda(code, alpha_sp, alpha_sp, 8);
5447 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5448 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5449 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5454 g_assert_not_reached ();
5460 /*========================= End of Function ========================*/
5462 /*------------------------------------------------------------------*/
5464 /* Name - mono_arch_allocate_vars */
5466 /* Function - Set var information according to the calling */
5467 /* convention for Alpha. The local var stuff should */
5468 /* most likely be split in another method. */
5470 /* Parameter - @m - Compile unit. */
5472 * This method is called right before working with BBs. Conversion to
5473 * IR was done and some analises what registers would be used.
5474 * Collect info about registers we used - if we want to use a register
5475 * we need to allocate space for it and save on the stack in method
5478 * Alpha calling convertion:
5479 * FP -> Stack top <- SP
5480 * 0: Stack params to call others
5482 * RA <- arch.params_stack_size
5485 * [LMF info] <- arch.lmf_offset
5487 * [possible return values allocated on stack]
5491 * . caller saved regs <- arch.reg_save_area_offset
5492 * . a0 <- arch.args_save_area_offset
5498 * ------------------------
5499 * . a6 - passed args on stack
5502 /*------------------------------------------------------------------*/
5505 mono_arch_allocate_vars (MonoCompile *cfg)
5507 MonoMethodSignature *sig;
5508 MonoMethodHeader *header;
5510 int i, offset = 0, a_off = 0;
5511 guint32 locals_stack_size, locals_stack_align = 0;
5515 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5517 header = mono_method_get_header (cfg->method);
5519 sig = mono_method_signature (cfg->method);
5521 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5523 /* if (cfg->arch.omit_fp) {
5524 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5525 cfg->frame_reg = AMD64_RSP;
5530 /* Locals are allocated forwards from FP. After
5531 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5532 * (starting from offset 16).
5533 * FIXME: Check there Arg6...Argn are supposed to be
5535 cfg->frame_reg = alpha_fp;
5536 // offset = MONO_ALPHA_VARS_OFFSET;
5539 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5540 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5541 offset += cfg->arch.params_stack_size;
5543 offset += 16; // Size to save RA & FP
5545 if (cfg->method->save_lmf)
5547 /* Reserve stack space for saving LMF + argument regs */
5548 guint32 size = sizeof (MonoLMF);
5550 //if (lmf_tls_offset == -1)
5551 // /* Need to save argument regs too */
5552 // size += (AMD64_NREG * 8) + (8 * 8);
5554 cfg->arch.lmf_offset = offset;
5557 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5558 cfg->method->name, cfg->arch.lmf_offset, size);
5561 if (sig->ret->type != MONO_TYPE_VOID)
5563 switch (cinfo->ret.storage)
5567 case ArgInDoubleReg:
5568 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5569 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5570 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5572 /* The register is volatile */
5573 cfg->ret->opcode = OP_REGOFFSET;
5574 cfg->ret->inst_basereg = cfg->frame_reg;
5576 /*if (cfg->arch.omit_fp) {
5577 cfg->ret->inst_offset = offset;
5581 cfg->ret->inst_offset = offset;
5582 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5588 cfg->ret->opcode = OP_REGVAR;
5589 cfg->ret->inst_c0 = cinfo->ret.reg;
5592 case ArgValuetypeInReg:
5593 /* Allocate a local to hold the result, the epilog will
5594 copy it to the correct place */
5595 // g_assert (!cfg->arch.omit_fp);
5597 cfg->ret->opcode = OP_REGOFFSET;
5598 cfg->ret->inst_basereg = cfg->frame_reg;
5599 cfg->ret->inst_offset = offset;
5602 g_assert_not_reached ();
5604 cfg->ret->dreg = cfg->ret->inst_c0;
5607 /* Allocate locals */
5608 offsets = mono_allocate_stack_slots_full (cfg,
5609 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5611 &locals_stack_align);
5613 //g_assert((locals_stack_size % 8) == 0);
5614 if (locals_stack_size % 8)
5616 locals_stack_size += 8 - (locals_stack_size % 8);
5619 /* if (locals_stack_align)
5621 offset += (locals_stack_align - 1);
5622 offset &= ~(locals_stack_align - 1);
5626 cfg->arch.localloc_offset = offset;
5628 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5629 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5630 locals_stack_size, locals_stack_size);
5632 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5634 if (offsets [i] != -1) {
5635 MonoInst *inst = cfg->varinfo [i];
5636 inst->opcode = OP_REGOFFSET;
5637 inst->inst_basereg = cfg->frame_reg;
5638 //if (cfg->arch.omit_fp)
5639 // inst->inst_offset = (offset + offsets [i]);
5641 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5643 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5644 CFG_DEBUG(3) mono_print_tree_nl (inst);
5648 // TODO check how offsets[i] are calculated
5649 // it seems they are points to the end on data. Like 8, but it actually - 0
5651 offset += locals_stack_size; //+8;
5653 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5654 // g_assert (!cfg->arch.omit_fp);
5655 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5656 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5659 // Save offset for caller saved regs
5660 cfg->arch.reg_save_area_offset = offset;
5662 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5664 // Reserve space for caller saved registers
5665 for (i = 0; i < MONO_MAX_IREGS; ++i)
5666 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5667 (cfg->used_int_regs & (1 << i)))
5669 offset += sizeof (gpointer);
5672 // Save offset to args regs
5673 cfg->arch.args_save_area_offset = offset;
5675 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5677 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5679 ArgInfo *ainfo = &cinfo->args [i];
5681 switch(ainfo->storage)
5685 case ArgInDoubleReg:
5686 offset += sizeof (gpointer);
5689 offset += ainfo->nregs * sizeof (gpointer);
5696 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5699 // Reserve space for method params
5700 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5702 inst = cfg->args [i];
5704 if (inst->opcode != OP_REGVAR)
5706 ArgInfo *ainfo = &cinfo->args [i];
5707 gboolean inreg = TRUE;
5710 if (sig->hasthis && (i == 0))
5711 arg_type = &mono_defaults.object_class->byval_arg;
5713 arg_type = sig->params [i - sig->hasthis];
5715 /* FIXME: Allocate volatile arguments to registers */
5716 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5720 * Under AMD64, all registers used to pass arguments to functions
5721 * are volatile across calls. For Alpha too.
5722 * FIXME: Optimize this.
5726 if (inreg && (ainfo->storage == ArgInIReg)
5727 //&& cfg->used_int_regs & (1 << ainfo->reg)
5731 if (//(ainfo->storage == ArgInIReg) ||
5732 (ainfo->storage == ArgInFloatReg) ||
5733 (ainfo->storage == ArgInDoubleReg) ||
5734 (ainfo->storage == ArgValuetypeInReg))
5737 inst->opcode = OP_REGOFFSET;
5739 switch (ainfo->storage)
5743 case ArgInDoubleReg:
5744 inst->opcode = OP_REGVAR;
5745 inst->dreg = ainfo->reg;
5748 // g_assert (!cfg->arch.omit_fp);
5749 inst->opcode = OP_REGOFFSET;
5750 inst->inst_basereg = cfg->frame_reg;
5752 // "offset" here will point to the end of
5753 // array of saved ret,locals, args
5754 // Ideally it would point to "a7"
5755 inst->inst_offset = ainfo->offset + offset;
5757 case ArgValuetypeInReg:
5767 if (!inreg && (ainfo->storage != ArgOnStack))
5769 inst->opcode = OP_REGOFFSET;
5770 inst->inst_basereg = cfg->frame_reg;
5772 /* These arguments are saved to the stack in the prolog */
5773 /*if (cfg->arch.omit_fp) {
5774 inst->inst_offset = offset;
5775 offset += (ainfo->storage == ArgValuetypeInReg) ?
5776 2 * sizeof (gpointer) : sizeof (gpointer);
5779 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5780 // 2 * sizeof (gpointer) : sizeof (gpointer);
5782 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5783 switch(ainfo->storage)
5786 a_off += ainfo->nslots * 8;
5789 a_off += sizeof (gpointer);
5791 // (/*(ainfo->reg - 16)*/ i * 8);
5797 cfg->stack_offset = offset;
5802 /*========================= End of Function ========================*/
5804 /*------------------------------------------------------------------*/
5806 /* Name - mono_arch_print_tree */
5808 /* Function - Print platform-specific opcode details. */
5810 /* Returns - 1 - opcode details have been printed */
5811 /* 0 - opcode details have not been printed */
5813 /*------------------------------------------------------------------*/
5816 mono_arch_print_tree (MonoInst *tree, int arity)
5820 ALPHA_DEBUG("mono_arch_print_tree");
5822 switch (tree->opcode) {
5829 /*========================= End of Function ========================*/
5833 ** mono_arch_get_vcall_slot_addr
5834 ** is called by mono_magic_trampoline to determine that the JIT compiled
5835 ** method is called via vtable slot. We need to analyze call sequence
5836 ** and determine that. In case it is true - we need to return address
5839 ** code - points to the next instruction after call
5840 ** reg - points to saved regs before the call (this is done
5841 ** by mono_magic_trampoline function
5845 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
5847 unsigned int *pc = (unsigned int *)code;
5849 int start_index = -2;
5851 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5854 // Check if we have parameters on stack
5855 if ((pc[-2] & 0xFFFF0000) == 0x23DE0000) // lda sp,-n(sp)
5858 // Check for (call_membase):
5859 // -4: mov v0,a0 - load this ???
5860 // -3: ldq v0,0(v0) - load vtable
5861 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5862 if ((pc[start_index-1] & 0xFC00FFFF) == 0xA4000000 &&
5863 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5866 disp = pc[start_index] & 0xFFFF;
5867 reg = (pc[start_index-1] >> AXP_REG1_SHIFT) & AXP_REG_MASK;
5868 //reg = 0; // For now
5870 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5872 return (gpointer)(((guint64)(regs [reg])) + disp);
5875 // Check for interface call
5878 // -3: ldq v0,-n(v0)
5879 // -2: ldq t12,0(v0)
5880 if ((pc[start_index-2] & 0xFC00FFFF) == 0xA4000000 &&
5881 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5882 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5885 disp = pc[start_index] & 0xFFFF;;
5888 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5890 return (gpointer)(((guint64)(regs [reg])) + disp);
5898 mono_arch_get_patch_offset (guint8 *code)