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 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
428 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
432 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE pass\n");
434 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
435 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
443 * OP_MOVE reg, reg except special case (mov at, at)
445 if (ins->dreg == ins->sreg1 &&
446 ins->dreg != alpha_at)
458 if (last_ins && last_ins->opcode == OP_MOVE &&
459 ins->sreg1 == last_ins->dreg &&
460 last_ins->dreg != alpha_at &&
461 ins->dreg == last_ins->sreg1)
470 /* remove unnecessary multiplication with 1 */
471 if (ins->inst_imm == 1)
473 if (ins->dreg != ins->sreg1)
475 ins->opcode = OP_MOVE;
486 case OP_LOADI8_MEMBASE:
487 case OP_LOAD_MEMBASE:
489 * Note: if reg1 = reg2 the load op is removed
491 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
492 * OP_LOADI8_MEMBASE offset(basereg), reg2
494 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
498 (last_ins->opcode == OP_STOREI8_MEMBASE_REG ||
499 last_ins->opcode == OP_STORE_MEMBASE_REG) &&
500 ins->inst_basereg == last_ins->inst_destbasereg &&
501 ins->inst_offset == last_ins->inst_offset)
503 if (ins->dreg == last_ins->sreg1)
510 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
511 ins->opcode = OP_MOVE;
512 ins->sreg1 = last_ins->sreg1;
518 case OP_LOAD_MEMBASE:
519 case OP_LOADI4_MEMBASE:
521 * Note: if reg1 = reg2 the load op is removed
523 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
524 * OP_LOAD_MEMBASE offset(basereg), reg2
526 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
529 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
530 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
531 ins->inst_basereg == last_ins->inst_destbasereg &&
532 ins->inst_offset == last_ins->inst_offset)
534 if (ins->dreg == last_ins->sreg1)
541 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
542 ins->opcode = OP_MOVE;
543 ins->sreg1 = last_ins->sreg1;
547 * Note: reg1 must be different from the basereg in the second load
548 * Note: if reg1 = reg2 is equal then second load is removed
550 * OP_LOAD_MEMBASE offset(basereg), reg1
551 * OP_LOAD_MEMBASE offset(basereg), reg2
553 * OP_LOAD_MEMBASE offset(basereg), reg1
557 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
558 || last_ins->opcode == OP_LOAD_MEMBASE) &&
559 ins->inst_basereg != last_ins->dreg &&
560 ins->inst_basereg == last_ins->inst_basereg &&
561 ins->inst_offset == last_ins->inst_offset)
563 if (ins->dreg == last_ins->dreg)
570 ins->opcode = OP_MOVE;
571 ins->sreg1 = last_ins->dreg;
574 //g_assert_not_reached ();
582 // Convert to opposite branch opcode
583 static guint16 cvt_branch_opcode(guint16 opcode)
588 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
593 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
597 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
601 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
605 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
609 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
613 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
617 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
621 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
625 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
629 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
633 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
637 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
641 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
645 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
649 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
653 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
657 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
661 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
665 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
669 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
673 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
677 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
681 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
685 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
692 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
697 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
699 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
705 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
716 return OP_ALPHA_CMP_EQ;
718 return OP_ALPHA_CMP_ULE;
720 return OP_ALPHA_CMP_LE;
722 return OP_ALPHA_CMP_LT;
724 return OP_ALPHA_CMP_ULT;
729 case OP_ICOMPARE_IMM:
735 return OP_ALPHA_CMP_IMM_EQ;
737 return OP_ALPHA_CMP_IMM_ULE;
739 return OP_ALPHA_CMP_IMM_LE;
741 return OP_ALPHA_CMP_IMM_LT;
743 return OP_ALPHA_CMP_IMM_ULT;
748 g_assert_not_reached();
753 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
755 // Instead of compare+b<cond>,
756 // Alpha has compare<cond>+br<cond>
757 // we need to convert
758 // Handle floating compare here too
764 // Convert cmp + beq -> cmpeq + bne
765 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
766 next->opcode = cvt_branch_opcode(next->opcode);
771 // cmp + ibne_un -> cmpeq + beq
772 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
773 next->opcode = cvt_branch_opcode(next->opcode);
778 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
779 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
780 next->opcode = cvt_branch_opcode(next->opcode);
785 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
786 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
787 next->opcode = cvt_branch_opcode(next->opcode);
792 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
793 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
794 next->opcode = cvt_branch_opcode(next->opcode);
799 // lcmp + blt.un -> cmpult + bne
800 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
801 next->opcode = cvt_branch_opcode(next->opcode);
806 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
807 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
808 next->opcode = cvt_branch_opcode(next->opcode);
813 //lcmp + bge.un -> cmpult + beq
814 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
815 next->opcode = cvt_branch_opcode(next->opcode);
820 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
821 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
822 next->opcode = cvt_branch_opcode(next->opcode);
827 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
828 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
829 next->opcode = cvt_branch_opcode(next->opcode);
835 // cmp + cgt_un -> cmpule + beq
836 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
841 // cmp + iceq -> cmpeq + bne
842 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
847 // cmp + int_cgt -> cmple + beq
848 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
853 // cmp + int_clt -> cmplt + bne
854 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
859 // cmp + int_clt_un -> cmpult + bne
860 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
864 // The conditional exceptions will be handled in
865 // output_basic_blocks. Here we just determine correct
868 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
871 case OP_COND_EXC_GT_UN:
872 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
876 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
879 case OP_COND_EXC_LT_UN:
880 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
883 case OP_COND_EXC_LE_UN:
884 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
887 case OP_COND_EXC_NE_UN:
888 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
892 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
897 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
898 mono_inst_name(next->opcode), next->opcode);
900 // g_assert_not_reached();
908 * mono_arch_lowering_pass:
910 * Converts complex opcodes into simpler ones so that each IR instruction
911 * corresponds to one machine instruction.
914 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
916 MonoInst *ins, *n, *next, *temp;
918 if (bb->max_vreg > cfg->rs->next_vreg)
919 cfg->rs->next_vreg = bb->max_vreg;
922 * FIXME: Need to add more instructions, but the current machine
923 * description can't model some parts of the composite instructions like
927 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
935 NEW_INS (cfg, ins, temp, OP_I8CONST);
936 temp->inst_c0 = ins->inst_imm;
937 temp->dreg = mono_regstate_next_int (cfg->rs);
942 ins->opcode = CEE_MUL;
945 ins->opcode = OP_LDIV;
948 ins->opcode = OP_LREM;
951 ins->opcode = OP_IDIV;
954 ins->opcode = OP_IREM;
958 ins->sreg2 = temp->dreg;
966 // Instead of compare+b<cond>/fcompare+b<cond>,
967 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
968 // we need to convert
969 next = mono_inst_list_next (&ins->node, &bb->ins_list);
972 cvt_cmp_branch(ins, next);
977 if (!alpha_is_imm (ins->inst_imm))
979 NEW_INS (cfg, ins, temp, OP_I8CONST);
980 temp->inst_c0 = ins->inst_imm;
981 temp->dreg = mono_regstate_next_int (cfg->rs);
982 ins->opcode = OP_COMPARE;
983 ins->sreg2 = temp->dreg;
985 // We should try to reevaluate new IR opcode
989 next = mono_inst_list_next (&ins->node, &bb->ins_list);
992 cvt_cmp_branch(ins, next);
996 case OP_ICOMPARE_IMM:
997 if (!alpha_is_imm (ins->inst_imm))
999 NEW_INS (cfg, ins, temp, OP_ICONST);
1000 temp->inst_c0 = ins->inst_imm;
1001 temp->dreg = mono_regstate_next_int (cfg->rs);
1002 ins->opcode = OP_ICOMPARE;
1003 ins->sreg2 = temp->dreg;
1005 // We should try to reevaluate new IR opcode
1009 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1012 cvt_cmp_branch(ins, next);
1016 case OP_STORE_MEMBASE_IMM:
1017 case OP_STOREI8_MEMBASE_IMM:
1018 if (ins->inst_imm != 0)
1020 NEW_INS (cfg, ins, temp, OP_I8CONST);
1021 temp->inst_c0 = ins->inst_imm;
1022 temp->dreg = mono_regstate_next_int (cfg->rs);
1023 ins->opcode = OP_STOREI8_MEMBASE_REG;
1024 ins->sreg1 = temp->dreg;
1028 case OP_STOREI4_MEMBASE_IMM:
1029 if (ins->inst_imm != 0)
1032 NEW_INS (cfg, ins, temp, OP_ICONST);
1033 temp->inst_c0 = ins->inst_imm;
1034 temp->dreg = mono_regstate_next_int (cfg->rs);
1035 ins->opcode = OP_STOREI4_MEMBASE_REG;
1036 ins->sreg1 = temp->dreg;
1040 case OP_STOREI1_MEMBASE_IMM:
1041 if (ins->inst_imm != 0 || !bwx_supported)
1044 NEW_INS (cfg, ins, temp, OP_ICONST);
1045 temp->inst_c0 = ins->inst_imm;
1046 temp->dreg = mono_regstate_next_int (cfg->rs);
1047 ins->opcode = OP_STOREI1_MEMBASE_REG;
1048 ins->sreg1 = temp->dreg;
1052 case OP_STOREI2_MEMBASE_IMM:
1053 if (ins->inst_imm != 0 || !bwx_supported)
1056 NEW_INS (cfg, ins, temp, OP_ICONST);
1057 temp->inst_c0 = ins->inst_imm;
1058 temp->dreg = mono_regstate_next_int (cfg->rs);
1059 ins->opcode = OP_STOREI2_MEMBASE_REG;
1060 ins->sreg1 = temp->dreg;
1071 case OP_ISHR_UN_IMM:
1072 if (!alpha_is_imm(ins->inst_imm))
1075 NEW_INS (cfg, ins, temp, OP_ICONST);
1076 temp->inst_c0 = ins->inst_imm;
1077 temp->dreg = mono_regstate_next_int (cfg->rs);
1082 ins->opcode = OP_IADD;
1085 ins->opcode = OP_ISUB;
1088 ins->opcode = OP_IAND;
1091 ins->opcode = OP_IOR;
1094 ins->opcode = OP_IXOR;
1097 ins->opcode = OP_ISHL;
1100 ins->opcode = OP_ISHR;
1102 case OP_ISHR_UN_IMM:
1103 ins->opcode = OP_ISHR_UN;
1109 ins->sreg2 = temp->dreg;
1115 if (!alpha_is_imm(ins->inst_imm))
1118 NEW_INS (cfg, ins, temp, OP_ICONST);
1119 temp->inst_c0 = ins->inst_imm;
1120 temp->dreg = mono_regstate_next_int (cfg->rs);
1125 ins->opcode = CEE_ADD;
1128 ins->opcode = CEE_SUB;
1131 ins->opcode = CEE_AND;
1134 ins->opcode = CEE_SHL;
1140 ins->sreg2 = temp->dreg;
1144 if (!alpha_is_imm(ins->inst_imm))
1147 NEW_INS(cfg, ins, temp, OP_ICONST);
1148 temp->inst_c0 = ins->inst_imm;
1149 temp->dreg = mono_regstate_next_int(cfg->rs);
1150 ins->sreg2 = temp->dreg;
1151 ins->opcode = OP_LSHR;
1155 if (!alpha_is_imm(ins->inst_imm))
1158 NEW_INS(cfg, ins, temp, OP_ICONST);
1159 temp->inst_c0 = ins->inst_imm;
1160 temp->dreg = mono_regstate_next_int(cfg->rs);
1161 ins->sreg2 = temp->dreg;
1162 ins->opcode = OP_LSHL;
1171 bb->max_vreg = cfg->rs->next_vreg;
1174 /*========================= End of Function ========================*/
1176 #define AXP_GENERAL_REGS 6
1177 #define AXP_MIN_STACK_SIZE 24
1179 /* A typical Alpha stack frame looks like this */
1181 fun: // called from outside the module.
1182 ldgp gp,0(pv) // load the global pointer
1183 fun..ng: // called from inside the module.
1184 lda sp, -SIZE( sp ) // grow the stack downwards.
1186 stq ra, 0(sp) // save the return address.
1188 stq s0, 8(sp) // callee-saved registers.
1189 stq s1, 16(sp) // ...
1191 // Move the arguments to the argument registers...
1193 mov addr, pv // Load the callee address
1194 jsr ra, (pv) // call the method.
1195 ldgp gp, 0(ra) // restore gp
1197 // return value is in v0
1199 ldq ra, 0(sp) // free stack frame
1200 ldq s0, 8(sp) // restore callee-saved registers.
1202 ldq sp, 32(sp) // restore stack pointer
1204 ret zero, (ra), 1 // return.
1207 // our call must look like this.
1213 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1214 stq ra, SIZE-48(sp) // store ra
1215 stq fp, SIZE-40(sp) // store fp (frame pointer)
1216 stq a0, SIZE-32(sp) // store args. a0 = func
1217 stq a1, SIZE-24(sp) // a1 = retval
1218 stq a2, SIZE-16(sp) // a2 = this
1219 stq a3, SIZE-8(sp) // a3 = args
1220 mov sp, fp // set frame pointer
1240 jsr ra, (pv) // call func
1241 ldgp gp, 0(ra) // restore gp.
1242 mov v0, t1 // move return value into t1
1245 ldq t0, SIZE-24(fp) // load retval into t2
1246 stl t1, 0(t0) // store value.
1257 * emit_load_volatile_arguments:
1259 * Load volatile arguments from the stack to the original input registers.
1260 * Required before a tail call.
1262 static unsigned int*
1263 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1265 MonoMethod *method = cfg->method;
1266 MonoMethodSignature *sig;
1271 /* FIXME: Generate intermediate code instead */
1273 sig = mono_method_signature (method);
1275 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1277 if (sig->ret->type != MONO_TYPE_VOID) {
1278 if ((cinfo->ret.storage == ArgInIReg) &&
1279 (cfg->ret->opcode != OP_REGVAR))
1281 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1282 cfg->ret->inst_offset);
1286 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1288 ArgInfo *ainfo = &cinfo->args [i];
1289 MonoInst *inst = cfg->args [i];
1291 switch(ainfo->storage)
1294 // We need to save all used a0-a5 params
1295 //for (i=0; i<PARAM_REGS; i++)
1297 // if (i < cinfo->reg_usage)
1299 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1300 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1302 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1303 ainfo->reg, inst->inst_offset/*offset*/);
1307 case ArgInDoubleReg:
1309 // We need to save all used af0-af5 params
1310 //for (i=0; i<PARAM_REGS; i++)
1312 // if (i < cinfo->freg_usage)
1314 switch(cinfo->args[i].storage)
1317 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1318 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1320 case ArgInDoubleReg:
1321 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1322 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1328 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1329 ainfo->reg, /*offset*/inst->inst_offset);
1338 /*------------------------------------------------------------------*/
1340 /* Name - mono_arch_emit_prolog */
1342 /* Function - Create the instruction sequence for a function */
1345 * How to handle consts and method addreses:
1346 * For method we will allocate array of qword after method epiloge.
1347 * These qword will hold readonly info to method to properly to run.
1348 * For example: qword constants, method addreses
1349 * GP will point to start of data. Offsets to the data will be equal
1350 * to "address" of data - start of GP. (GP = 0 during method jiting).
1351 * GP is easily calculated from passed PV (method start address).
1352 * The patch will update GP loadings.
1353 * The GOT section should be more than 32Kb.
1354 * The patch code should put proper offset since the real position of
1355 * qword array will be known after the function epiloge.
1357 /*------------------------------------------------------------------*/
1360 mono_arch_emit_prolog (MonoCompile *cfg)
1362 MonoMethod *method = cfg->method;
1363 MonoMethodSignature *sig = mono_method_signature (method);
1364 //int alloc_size, code_size, max_offset, quad;
1367 int i, stack_size, offset;
1368 gint32 lmf_offset = cfg->arch.lmf_offset;
1370 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1372 // FIXME: Use just one field to hold calculated stack size
1373 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1374 cfg->arch.got_data = 0;
1376 cfg->code_size = 512;
1378 code = (unsigned int *)g_malloc(cfg->code_size);
1379 cfg->native_code = (void *)code;
1381 // Emit method prolog
1382 // Calculate GP from passed PV, allocate stack
1384 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1385 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1386 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1388 offset = cfg->arch.params_stack_size;
1390 /* store call convention parameters on stack */
1391 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1392 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1394 /* set the frame pointer */
1395 alpha_mov1( code, alpha_sp, alpha_fp );
1398 if (method->save_lmf)
1401 alpha_stq(code, alpha_pv, alpha_fp,
1402 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1404 alpha_stq(code, alpha_sp, alpha_fp,
1405 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1407 alpha_stq(code, alpha_fp, alpha_fp,
1408 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1410 alpha_stq(code, alpha_gp, alpha_fp,
1411 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1414 alpha_stq(code, alpha_pv, alpha_fp,
1415 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1418 /* Save (global) regs */
1419 offset = cfg->arch.reg_save_area_offset;
1421 for (i = 0; i < MONO_MAX_IREGS; ++i)
1422 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1423 (cfg->used_int_regs & (1 << i)) &&
1424 !( ALPHA_ARGS_REGS & (1 << i)) )
1426 alpha_stq(code, i, alpha_fp, offset);
1427 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1432 offset = cfg->arch.args_save_area_offset;
1434 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1436 if (sig->ret->type != MONO_TYPE_VOID)
1438 if ((cinfo->ret.storage == ArgInIReg) &&
1439 (cfg->ret->opcode != OP_REGVAR))
1441 /* Save volatile arguments to the stack */
1442 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1443 cfg->ret->inst_offset);
1447 /* Keep this in sync with emit_load_volatile_arguments */
1448 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1450 ArgInfo *ainfo = &cinfo->args [i];
1451 MonoInst *inst = cfg->args [i];
1454 switch(ainfo->storage)
1457 // We need to save all used a0-a5 params
1459 if (inst->opcode == OP_REGVAR)
1461 alpha_mov1(code, ainfo->reg, inst->dreg);
1462 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1463 ainfo->reg, inst->dreg);
1467 alpha_stq(code, ainfo->reg, inst->inst_basereg,
1470 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1471 ainfo->reg, inst->inst_offset);
1479 for(j=0; j<ainfo->nregs; j++)
1481 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1482 ainfo->reg + j, inst->inst_offset + (8*j));
1483 alpha_stq(code, (ainfo->reg+j), inst->inst_basereg,
1484 (inst->inst_offset + (8*j)));
1489 case ArgInDoubleReg:
1491 // We need to save all used af0-af5 params
1493 switch(cinfo->args[i].storage)
1496 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1497 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1499 case ArgInDoubleReg:
1500 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1501 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1507 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1508 ainfo->reg, /*offset*/inst->inst_offset);
1515 offset = cfg->arch.reg_save_area_offset;
1518 for (i = 0; i < MONO_MAX_VREGS; ++i)
1519 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1520 (cfg->used_int_regs & (1 << i)) &&
1521 !( ALPHA_ARGS_REGS & (1 << i)) )
1523 alpha_stq(code, i, alpha_fp, offset);
1524 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1529 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1531 if (method->save_lmf)
1534 * The call might clobber argument registers, but they are already
1535 * saved to the stack/global regs.
1538 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1539 (gpointer)"mono_get_lmf_addr");
1542 alpha_stq(code, alpha_r0, alpha_fp,
1543 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1544 // Load "previous_lmf" member of MonoLMF struct
1545 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1547 // Save it to MonoLMF struct
1548 alpha_stq(code, alpha_r1, alpha_fp,
1549 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1552 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1553 alpha_stq(code, alpha_r1, alpha_r0, 0);
1558 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1559 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1562 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1564 g_assert (cfg->code_len < cfg->code_size);
1566 return (gint8 *)code;
1569 /*========================= End of Function ========================*/
1571 /*------------------------------------------------------------------*/
1573 /* Name - mono_arch_flush_register_windows */
1579 /*------------------------------------------------------------------*/
1582 mono_arch_flush_register_windows (void)
1584 ALPHA_DEBUG("mono_arch_flush_register_windows");
1586 /*========================= End of Function ========================*/
1588 /*------------------------------------------------------------------*/
1590 /* Name - mono_arch_regalloc_cost */
1592 /* Function - Determine the cost, in the number of memory */
1593 /* references, of the action of allocating the var- */
1594 /* iable VMV into a register during global register */
1597 /* Returns - Cost */
1599 /*------------------------------------------------------------------*/
1602 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1604 MonoInst *ins = cfg->varinfo [vmv->idx];
1607 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1609 if (cfg->method->save_lmf)
1610 /* The register is already saved */
1611 /* substract 1 for the invisible store in the prolog */
1612 return (ins->opcode == OP_ARG) ? 1 : 0;
1615 return (ins->opcode == OP_ARG) ? 2 : 1;
1618 /*========================= End of Function ========================*/
1622 ** This method emits call sequience
1625 static unsigned int *
1626 emit_call(MonoCompile *cfg, unsigned int *code,
1627 guint32 patch_type, gconstpointer data)
1630 AlphaGotData ge_data;
1632 offset = (char *)code - (char *)cfg->native_code;
1634 ge_data.data.p = (void *)data;
1635 add_got_entry(cfg, GT_PTR, ge_data,
1636 offset, patch_type, data);
1638 // Load call address into PV
1639 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1642 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1644 offset = (char *)code - (char *)cfg->native_code;
1647 ALPHA_LOAD_GP(offset)
1648 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1649 alpha_lda(code, alpha_gp, alpha_gp, 0);
1654 /*------------------------------------------------------------------*/
1656 /* Name - arch_get_argument_info */
1658 /* Function - Gathers information on parameters such as size, */
1659 /* alignment, and padding. arg_info should be large */
1660 /* enough to hold param_count + 1 entries. */
1662 /* Parameters - @csig - Method signature */
1663 /* @param_count - No. of parameters to consider */
1664 /* @arg_info - An array to store the result info */
1666 /* Returns - Size of the activation frame */
1668 /*------------------------------------------------------------------*/
1671 mono_arch_get_argument_info (MonoMethodSignature *csig,
1673 MonoJitArgumentInfo *arg_info)
1676 CallInfo *cinfo = get_call_info (NULL, csig, FALSE);
1677 guint32 args_size = cinfo->stack_usage;
1679 ALPHA_DEBUG("mono_arch_get_argument_info");
1681 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1684 arg_info [0].offset = 0;
1687 for (k = 0; k < param_count; k++)
1689 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1693 // The size is checked only for valuetype in trace.c
1694 arg_info [k + 1].size = 8;
1702 /*------------------------------------------------------------------*/
1704 /* Name - mono_arch_emit_epilog */
1706 /* Function - Emit the instructions for a function epilog. */
1708 /*------------------------------------------------------------------*/
1711 mono_arch_emit_epilog (MonoCompile *cfg)
1713 MonoMethod *method = cfg->method;
1716 int max_epilog_size = 128;
1717 int stack_size = cfg->arch.stack_size;
1719 gint32 lmf_offset = cfg->arch.lmf_offset;
1721 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1723 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1725 cfg->code_size *= 2;
1726 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1727 mono_jit_stats.code_reallocs++;
1730 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1732 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1733 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1736 if (method->save_lmf)
1738 /* Restore previous lmf */
1739 alpha_ldq(code, alpha_at, alpha_fp,
1740 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1741 alpha_ldq(code, alpha_ra, alpha_fp,
1742 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1743 alpha_stq(code, alpha_at, alpha_ra, 0);
1747 alpha_mov1( code, alpha_fp, alpha_sp );
1749 // Restore saved regs
1750 offset = cfg->arch.reg_save_area_offset;
1752 for (i = 0; i < MONO_MAX_IREGS; ++i)
1753 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1754 (cfg->used_int_regs & (1 << i)) &&
1755 !( ALPHA_ARGS_REGS & (1 << i)) )
1757 alpha_ldq(code, i, alpha_sp, offset);
1758 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1763 /* restore fp, ra, sp */
1764 offset = cfg->arch.params_stack_size;
1766 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1767 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1768 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1771 alpha_ret( code, alpha_ra, 1 );
1773 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1775 g_assert (cfg->code_len < cfg->code_size);
1778 /*========================= End of Function ========================*/
1780 /*------------------------------------------------------------------*/
1782 /* Name - mono_arch_emit_exceptions */
1784 /* Function - Emit the blocks to handle exception conditions. */
1786 /*------------------------------------------------------------------*/
1789 mono_arch_emit_exceptions (MonoCompile *cfg)
1791 MonoJumpInfo *patch_info;
1793 unsigned int *code, *got_start;
1794 unsigned long *corlib_exc_adr;
1795 MonoClass *exc_classes [16];
1796 guint8 *exc_throw_start [16], *exc_throw_end [16];
1797 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1798 AlphaGotEntry *got_data;
1800 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1802 /* Compute needed space */
1803 for (patch_info = cfg->patch_info; patch_info;
1804 patch_info = patch_info->next)
1806 if (patch_info->type == MONO_PATCH_INFO_EXC)
1808 if (patch_info->type == MONO_PATCH_INFO_R8)
1809 code_size += 8 + 7; /* sizeof (double) + alignment */
1810 if (patch_info->type == MONO_PATCH_INFO_R4)
1811 code_size += 4 + 7; /* sizeof (float) + alignment */
1814 // Reserve space for GOT entries
1815 for (got_data = cfg->arch.got_data; got_data;
1816 got_data = got_data->next)
1818 // Reserve space for 8 byte const (for now)
1819 if (got_data->type != GT_LD_GTADDR)
1823 while (cfg->code_len + code_size > (cfg->code_size - 16))
1825 cfg->code_size *= 2;
1826 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1827 mono_jit_stats.code_reallocs++;
1830 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1832 // Set code alignment
1833 if (((unsigned long)code) % 8)
1838 /* Add code to store conts and modify patch into to store offset in got */
1839 for (got_data = cfg->arch.got_data; got_data;
1840 got_data = got_data->next)
1842 unsigned long data = got_data->value.data.l;
1843 MonoJumpInfo *got_ref = got_data->got_patch_info;
1845 // Modify loading of GP
1846 if (got_data->type == GT_LD_GTADDR)
1848 short high_off, low_off;
1849 unsigned int *ldgp_code =
1850 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1851 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1853 high_off = got_off / 0x10000;
1854 low_off = got_off % 0x10000;
1858 // Set offset from current point to GOT array
1859 // modify the following code sequence
1860 // ldah gp, 0(pv) or ldah gp, 0(ra)
1862 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1864 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1869 patch_info = got_data->patch_info;
1871 // Check code alignment
1872 if (((unsigned long)code) % 8)
1875 got_ref->data.offset = ((char *)code - (char *)got_start);
1878 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1880 *code = (unsigned int)(data & 0xFFFFFFFF);
1882 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1887 corlib_exc_adr = (unsigned long *)code;
1889 /* add code to raise exceptions */
1891 for (patch_info = cfg->patch_info; patch_info;
1892 patch_info = patch_info->next)
1894 switch (patch_info->type)
1896 case MONO_PATCH_INFO_EXC:
1898 MonoClass *exc_class;
1899 unsigned int *buf, *buf2;
1904 // Add patch info to call mono_arch_throw_corlib_exception
1905 // method to raise corlib exception
1906 // Will be added at the begining of the patch info list
1907 mono_add_patch_info(cfg,
1908 ((char *)code - (char *)cfg->native_code),
1909 MONO_PATCH_INFO_INTERNAL_METHOD,
1910 "mono_arch_throw_corlib_exception");
1912 // Skip longword before starting the code
1917 exc_class = mono_class_from_name (mono_defaults.corlib,
1918 "System", patch_info->data.name);
1920 g_assert (exc_class);
1921 throw_ip = patch_info->ip.i;
1923 //x86_breakpoint (code);
1924 /* Find a throw sequence for the same exception class */
1925 for (i = 0; i < nthrows; ++i)
1926 if (exc_classes [i] == exc_class)
1933 // Patch original branch (patch info) to jump here
1934 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1935 patch_info->data.target =
1936 (char *)code - (char *)cfg->native_code;
1938 alpha_lda(code, alpha_a1, alpha_zero,
1939 -((short)((((char *)exc_throw_end[i] -
1940 (char *)cfg->native_code)) - throw_ip) - 4) );
1942 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
1944 alpha_bsr(code, alpha_zero, br_offset);
1950 // Save exception token type as first 32bit word for new
1951 // exception handling jump code
1952 *code = exc_class->type_token;
1955 // Patch original branch (patch info) to jump here
1956 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1957 patch_info->data.target =
1958 (char *)code - (char *)cfg->native_code;
1961 alpha_lda(code, alpha_a1, alpha_zero, 0);
1965 exc_classes [nthrows] = exc_class;
1966 exc_throw_start [nthrows] = code;
1969 // Load exception token
1970 alpha_ldl(code, alpha_a0, alpha_gp,
1971 ((char *)buf - (char *)got_start /*cfg->native_code*/));
1972 // Load corlib exception raiser code address
1973 alpha_ldq(code, alpha_pv, alpha_gp,
1974 ((char *)corlib_exc_adr -
1975 (char *)got_start /*cfg->native_code*/));
1977 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
1978 //patch_info->data.name = "mono_arch_throw_corlib_exception";
1979 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
1980 //patch_info->type = MONO_PATCH_INFO_NONE;
1981 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
1983 if (cfg->compile_aot)
1985 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
1986 //amd64_call_reg (code, GP_SCRATCH_REG);
1988 /* The callee is in memory allocated using
1990 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1993 alpha_lda(buf2, alpha_a1, alpha_zero,
1994 -((short)(((char *)code - (char *)cfg->native_code) -
1999 exc_throw_end [nthrows] = code;
2011 /* Handle relocations with RIP relative addressing */
2012 for (patch_info = cfg->patch_info; patch_info;
2013 patch_info = patch_info->next)
2015 gboolean remove = FALSE;
2017 switch (patch_info->type)
2019 case MONO_PATCH_INFO_R8:
2023 code = (guint8*)ALIGN_TO (code, 8);
2025 pos = cfg->native_code + patch_info->ip.i;
2027 *(double*)code = *(double*)patch_info->data.target;
2030 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2032 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2038 case MONO_PATCH_INFO_R4:
2042 code = (guint8*)ALIGN_TO (code, 8);
2044 pos = cfg->native_code + patch_info->ip.i;
2046 *(float*)code = *(float*)patch_info->data.target;
2049 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2051 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2063 if (patch_info == cfg->patch_info)
2064 cfg->patch_info = patch_info->next;
2069 for (tmp = cfg->patch_info; tmp->next != patch_info;
2072 tmp->next = patch_info->next;
2077 cfg->code_len = (char *)code - (char *)cfg->native_code;
2079 g_assert (cfg->code_len < cfg->code_size);
2083 /*========================= End of Function ========================*/
2085 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2086 offset = ((char *)code - \
2087 (char *)cfg->native_code); \
2088 if (Tins->flags & MONO_INST_BRLABEL) \
2090 if (Tins->inst_i0->inst_c0) \
2092 CFG_DEBUG(3) g_print("inst_c0: %0lX, data: %p]\n", \
2093 Tins->inst_i0->inst_c0, \
2094 cfg->native_code + Tins->inst_i0->inst_c0); \
2095 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2099 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n", \
2100 offset, Tins->inst_i0); \
2101 mono_add_patch_info (cfg, offset, \
2102 MONO_PATCH_INFO_LABEL, Tins->inst_i0); \
2103 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2108 if (Tins->inst_true_bb->native_offset) \
2110 long br_offset = (char *)cfg->native_code + \
2111 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2112 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2113 Tins->inst_target_bb->native_offset, \
2114 cfg->native_code + \
2115 Tins->inst_true_bb->native_offset); \
2116 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2120 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2121 offset, Tins->inst_target_bb); \
2122 mono_add_patch_info (cfg, offset, \
2123 MONO_PATCH_INFO_BB, \
2124 Tins->inst_true_bb); \
2125 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2130 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2133 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2138 mono_add_patch_info (cfg, \
2140 (char *)cfg->native_code), \
2141 MONO_PATCH_INFO_EXC, EXC_NAME); \
2142 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2146 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2151 /*------------------------------------------------------------------*/
2153 /* Name - mono_arch_output_basic_block */
2155 /* Function - Perform the "real" work of emitting instructions */
2156 /* that will do the work of in the basic block. */
2158 /*------------------------------------------------------------------*/
2161 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2166 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2167 guint last_offset = 0;
2170 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2172 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2173 bb->block_num, bb, bb->native_offset);
2175 cpos = bb->max_offset;
2177 offset = ((char *)code) - ((char *)cfg->native_code);
2179 mono_debug_open_block (cfg, bb, offset);
2181 MONO_BB_FOR_EACH_INS (bb, ins) {
2182 offset = ((char *)code) - ((char *)cfg->native_code);
2184 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2186 if (offset > (cfg->code_size - max_len - 16))
2188 cfg->code_size *= 2;
2189 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2190 code = (unsigned int *)(cfg->native_code + offset);
2191 mono_jit_stats.code_reallocs++;
2194 mono_debug_record_line_number (cfg, ins, offset);
2196 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2197 mono_inst_name(ins->opcode));
2199 switch (ins->opcode)
2202 // Shift 64 bit value right
2203 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2204 ins->dreg, ins->sreg1, ins->sreg2);
2205 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2209 // Shift 64 bit value right
2210 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2211 ins->dreg, ins->sreg1, ins->sreg2);
2212 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2216 // Shift 64 bit value right by constant
2217 g_assert(alpha_is_imm(ins->inst_imm));
2218 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2219 ins->dreg, ins->sreg1, ins->inst_imm);
2220 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2224 // Shift 32 bit value left
2225 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2226 ins->dreg, ins->sreg1, ins->sreg2);
2227 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2228 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2232 // Shift 32 bit value left by constant
2233 g_assert(alpha_is_imm(ins->inst_imm));
2234 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2235 ins->dreg, ins->sreg1, ins->inst_imm);
2236 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2237 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2241 g_assert(alpha_is_imm(ins->inst_imm));
2242 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2243 ins->dreg, ins->sreg1, ins->inst_imm);
2244 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2248 g_assert(alpha_is_imm(ins->inst_imm));
2249 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2250 ins->dreg, ins->sreg1, ins->inst_imm);
2251 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2256 // Shift 32 bit value left
2257 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2258 ins->dreg, ins->sreg1, ins->sreg2);
2259 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2263 // Shift 64 bit value left
2264 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2265 ins->dreg, ins->sreg1, ins->sreg2);
2266 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2271 // Shift 32 bit value right
2272 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2273 ins->dreg, ins->sreg1, ins->sreg2);
2274 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2275 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2279 // Shift 32 bit value rigth by constant
2280 g_assert(alpha_is_imm(ins->inst_imm));
2281 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2282 ins->dreg, ins->sreg1, ins->inst_imm);
2283 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2284 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2288 // Shift 32 bit unsigned value right
2289 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2290 ins->dreg, ins->sreg1, ins->sreg2);
2291 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2292 alpha_srl(code, alpha_at /*ins->dreg*/, ins->sreg2, ins->dreg);
2295 case OP_ISHR_UN_IMM:
2296 // Shift 32 bit unassigned value rigth by constant
2297 g_assert(alpha_is_imm(ins->inst_imm));
2298 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2299 ins->dreg, ins->sreg1, ins->inst_imm);
2300 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2301 alpha_srl_(code, alpha_at /*ins->dreg*/, ins->inst_imm, ins->dreg);
2304 case OP_LSHR_UN_IMM:
2305 // Shift 64 bit unassigned value rigth by constant
2306 g_assert(alpha_is_imm(ins->inst_imm));
2307 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2308 ins->dreg, ins->sreg1, ins->inst_imm);
2309 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2313 // Sum two 64 bits regs
2314 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2315 ins->dreg, ins->sreg1, ins->sreg2);
2316 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2320 // Subtract two 64 bit regs
2321 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2322 ins->dreg, ins->sreg1, ins->sreg2);
2323 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2327 // Add imm value to 64 bits int
2328 g_assert(alpha_is_imm(ins->inst_imm));
2329 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2330 ins->dreg, ins->sreg1, ins->inst_imm);
2331 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2335 // Add two 32 bit ints
2336 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2337 ins->dreg, ins->sreg1, ins->sreg2);
2338 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2342 // Add two 32 bit ints with overflow detection
2343 // Use AT to hold flag of signed overflow
2344 // Use t12(PV) to hold unsigned overflow
2345 // Use RA to hold intermediate result
2346 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2347 ins->dreg, ins->sreg1, ins->sreg2);
2348 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2349 alpha_ble(code, ins->sreg2, 2);
2351 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2352 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2353 alpha_br(code, alpha_zero, 1);
2355 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2356 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2358 /* res <u sreg1 => unsigned overflow */
2359 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2361 alpha_mov1(code, alpha_ra, ins->dreg);
2365 // Add two 64 bit ints with overflow detection
2366 // Use AT to hold flag of signed overflow
2367 // Use t12(PV) to hold unsigned overflow
2368 // Use RA to hold intermediate result
2369 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2370 ins->dreg, ins->sreg1, ins->sreg2);
2371 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2372 alpha_ble(code, ins->sreg2, 2);
2374 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2375 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2376 alpha_br(code, alpha_zero, 1);
2378 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2379 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2381 /* res <u sreg1 => unsigned overflow */
2382 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2384 alpha_mov1(code, alpha_ra, ins->dreg);
2388 // Add imm value to 32 bits int
2389 g_assert(alpha_is_imm(ins->inst_imm));
2390 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2391 ins->dreg, ins->sreg1, ins->inst_imm);
2392 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2396 // Substract to 32 bit ints
2397 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2398 ins->dreg, ins->sreg1, ins->sreg2);
2399 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2403 // Sub imm value from 32 bits int
2404 g_assert(alpha_is_imm(ins->inst_imm));
2405 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2406 ins->dreg, ins->sreg1, ins->inst_imm);
2407 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2411 // Sub to 32 bit ints with overflow detection
2412 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2413 ins->dreg, ins->sreg1, ins->sreg2);
2414 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2415 alpha_ble(code, ins->sreg2, 2);
2417 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2418 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2419 alpha_br(code, alpha_zero, 1);
2421 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2422 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2424 /* sreg1 <u sreg2 => unsigned overflow */
2425 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2427 alpha_mov1(code, alpha_ra, ins->dreg);
2431 // Sub to 64 bit ints with overflow detection
2432 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2433 ins->dreg, ins->sreg1, ins->sreg2);
2435 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2436 alpha_ble(code, ins->sreg2, 2);
2438 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2439 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2440 alpha_br(code, alpha_zero, 1);
2442 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2443 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2445 /* sreg1 <u sreg2 => unsigned overflow */
2446 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2448 alpha_mov1(code, alpha_ra, ins->dreg);
2453 // AND to 32 bit ints
2454 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2455 ins->dreg, ins->sreg1, ins->sreg2);
2456 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2461 // AND imm value with 32 bit int
2462 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2463 ins->dreg, ins->sreg1, ins->inst_imm);
2465 g_assert(alpha_is_imm(ins->inst_imm));
2466 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2472 // OR two 32/64 bit ints
2473 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2474 ins->dreg, ins->sreg1, ins->sreg2);
2475 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2479 // OR imm value with 32 bit int
2480 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2481 ins->dreg, ins->sreg1, ins->inst_imm);
2483 g_assert(alpha_is_imm(ins->inst_imm));
2484 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2490 // XOR two 32/64 bit ints
2491 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2492 ins->dreg, ins->sreg1, ins->sreg2);
2493 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2497 // XOR imm value with 32 bit int
2498 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2499 ins->dreg, ins->sreg1, ins->inst_imm);
2501 g_assert(alpha_is_imm(ins->inst_imm));
2502 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2508 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2509 ins->dreg, ins->sreg1);
2510 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2515 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2516 ins->dreg, ins->sreg1);
2517 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2522 // NOT 32/64 bit reg
2523 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2524 ins->dreg, ins->sreg1);
2525 alpha_not(code, ins->sreg1, ins->dreg);
2533 case OP_IMUL_OVF_UN:
2536 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",
2537 ins->dreg, ins->sreg1, ins->sreg2);
2541 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2542 ins->dreg, ins->sreg1, ins->sreg2);
2543 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2547 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2548 ins->dreg, ins->sreg1, ins->inst_imm);
2552 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2554 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2558 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2559 ins->dreg, ins->sreg1);
2560 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2561 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2565 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2566 ins->dreg, ins->sreg1);
2567 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2568 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2572 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2573 ins->dreg, ins->sreg1);
2574 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2575 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2579 // Actually ICONST is 32 bits long
2580 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2581 ins->dreg, ins->inst_c0);
2584 if (ins->inst_c0 == 0)
2586 alpha_clr(code, ins->dreg);
2590 // if -32768 < const <= 32767
2591 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2593 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2594 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2595 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2599 int lo = (char *)code - (char *)cfg->native_code;
2600 AlphaGotData ge_data;
2602 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2603 ge_data.data.l = ins->inst_c0;
2605 add_got_entry(cfg, GT_LONG, ge_data,
2606 lo, MONO_PATCH_INFO_NONE, 0);
2607 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2609 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2610 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2618 // To load 64 bit values we will have to use ldah/lda combination
2619 // and temporary register. As temporary register use r28
2620 // Divide 64 bit value in two parts and load upper 32 bits into
2621 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2622 // dreg from temp reg
2623 // the 32 bit value could be loaded with ldah/lda
2624 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2625 ins->dreg, ins->inst_c0);
2628 if (ins->inst_c0 == 0)
2630 alpha_clr(code, ins->dreg);
2634 // if -32768 < const <= 32767
2635 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2636 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2639 AlphaGotData ge_data;
2641 lo = (char *)code - (char *)cfg->native_code;
2643 ge_data.data.l = ins->inst_c0;
2645 add_got_entry(cfg, GT_LONG, ge_data,
2646 lo, MONO_PATCH_INFO_NONE, 0);
2647 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2654 double d = *(double *)ins->inst_p0;
2655 AlphaGotData ge_data;
2657 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2661 add_got_entry(cfg, GT_DOUBLE, ge_data,
2662 (char *)code - (char *)cfg->native_code,
2663 MONO_PATCH_INFO_NONE, 0);
2664 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2671 float d = *(float *)ins->inst_p0;
2672 AlphaGotData ge_data;
2674 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2678 add_got_entry(cfg, GT_FLOAT, ge_data,
2679 (char *)code - (char *)cfg->native_code,
2680 MONO_PATCH_INFO_NONE, 0);
2681 alpha_lds(code, ins->dreg, alpha_gp, 0);
2686 case OP_LOADU4_MEMBASE:
2687 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2688 ins->dreg, ins->inst_basereg, ins->inst_offset);
2690 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2691 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2694 case OP_LOADU1_MEMBASE:
2695 // Load unassigned byte from REGOFFSET
2696 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2697 ins->dreg, ins->inst_basereg, ins->inst_offset);
2699 alpha_ldbu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2702 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2704 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2705 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2709 case OP_LOADU2_MEMBASE:
2710 // Load unassigned word from REGOFFSET
2711 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2712 ins->dreg, ins->inst_basereg, ins->inst_offset);
2715 alpha_ldwu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2718 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2720 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2721 (ins->inst_offset+1));
2722 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2723 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2724 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2725 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2729 case OP_LOAD_MEMBASE:
2730 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2731 ins->dreg, ins->inst_basereg, ins->inst_offset);
2732 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2735 case OP_LOADI8_MEMBASE:
2736 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2737 ins->dreg, ins->inst_basereg, ins->inst_offset);
2738 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2741 case OP_LOADI4_MEMBASE:
2742 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2743 ins->dreg, ins->inst_basereg, ins->inst_offset);
2744 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2747 case OP_LOADI1_MEMBASE:
2748 // Load sign-extended byte from REGOFFSET
2749 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2750 ins->dreg, ins->inst_basereg, ins->inst_offset);
2753 alpha_ldbu(code, ins->dreg, ins->inst_basereg,
2755 alpha_sextb(code, ins->dreg, ins->dreg);
2759 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2761 alpha_lda(code, alpha_at, ins->inst_basereg,
2762 (ins->inst_offset+1));
2763 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2764 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2768 case OP_LOADI2_MEMBASE:
2769 // Load sign-extended word from REGOFFSET
2770 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2771 ins->dreg, ins->inst_basereg, ins->inst_offset);
2774 alpha_ldwu(code, ins->dreg, ins->inst_basereg,
2776 alpha_sextw(code, ins->dreg, ins->dreg);
2780 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2782 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2783 (ins->inst_offset+1));
2784 alpha_lda(code, alpha_at, ins->inst_basereg,
2785 (ins->inst_offset+2));
2786 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2787 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2788 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2789 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2793 case OP_STOREI1_MEMBASE_IMM:
2794 // Store signed byte at REGOFFSET
2795 // Valid only for storing 0
2796 // storei1_membase_reg will do the rest
2798 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2799 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2800 g_assert(ins->inst_imm == 0);
2803 alpha_stb(code, alpha_zero, ins->inst_destbasereg,
2806 g_assert_not_reached();
2810 case OP_STOREI1_MEMBASE_REG:
2811 // Store byte at REGOFFSET
2812 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2813 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2816 alpha_stb(code, ins->sreg1, ins->inst_destbasereg,
2821 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2823 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2825 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2826 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2827 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2828 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2833 case OP_STOREI2_MEMBASE_IMM:
2834 // Store signed word at REGOFFSET
2835 // Now work only for storing 0
2836 // For now storei2_membase_reg will do the work
2838 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2839 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2841 g_assert(ins->inst_imm == 0);
2844 alpha_stw(code, alpha_zero, ins->inst_destbasereg,
2847 g_assert_not_reached();
2851 case OP_STOREI2_MEMBASE_REG:
2852 // Store signed word from reg to REGOFFSET
2853 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2854 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2858 alpha_stw(code, ins->sreg1, ins->inst_destbasereg,
2863 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2865 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2866 (ins->inst_offset+1));
2867 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2869 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2870 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2871 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2872 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2873 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2874 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2875 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2876 (ins->inst_offset+1));
2877 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2883 case OP_STOREI4_MEMBASE_IMM:
2884 // We will get here only with ins->inst_imm = 0
2885 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2886 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2888 g_assert(ins->inst_imm == 0);
2890 alpha_stl(code, alpha_zero,
2891 ins->inst_destbasereg, ins->inst_offset);
2894 case OP_STORER4_MEMBASE_REG:
2895 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2896 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2897 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2900 case OP_STORER8_MEMBASE_REG:
2901 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2902 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2903 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2907 case OP_LOADR4_MEMBASE:
2908 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2909 ins->dreg, ins->inst_basereg, ins->inst_offset);
2910 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2913 case OP_LOADR8_MEMBASE:
2914 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2915 ins->dreg, ins->inst_basereg, ins->inst_offset);
2916 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2920 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2921 ins->sreg1, ins->dreg);
2922 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
2926 // Later check different rounding and exc modes
2927 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2928 ins->sreg1, ins->sreg2, ins->dreg);
2929 alpha_addt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2934 // Later check different rounding and exc modes
2935 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2936 ins->sreg1, ins->sreg2, ins->dreg);
2937 alpha_subt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2942 // Later check different rounding and exc modes
2943 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2944 ins->sreg1, ins->sreg2, ins->dreg);
2945 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
2949 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2950 ins->sreg1, ins->dreg);
2951 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
2954 case OP_ALPHA_TRAPB:
2955 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2960 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2961 ins->sreg1, ins->dreg);
2962 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
2965 case OP_STORE_MEMBASE_IMM:
2966 case OP_STOREI8_MEMBASE_IMM:
2967 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2968 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2969 g_assert(ins->inst_imm == 0);
2971 alpha_stq(code, alpha_zero,
2972 ins->inst_destbasereg, ins->inst_offset);
2975 case OP_STORE_MEMBASE_REG:
2976 case OP_STOREI8_MEMBASE_REG:
2977 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2978 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2979 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2982 case OP_STOREI4_MEMBASE_REG:
2983 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2984 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2985 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2988 case OP_ICOMPARE_IMM:
2989 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2990 ins->sreg1, ins->dreg, ins->inst_imm);
2992 g_assert_not_reached();
2996 case OP_COMPARE_IMM:
2997 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2998 ins->sreg1, ins->dreg, ins->inst_imm);
3000 g_assert_not_reached();
3004 case OP_COMPARE: // compare two 32 bit regs
3005 case OP_LCOMPARE: // compare two 64 bit regs
3006 case OP_FCOMPARE: // compare two floats
3007 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3008 ins->sreg1, ins->sreg2, ins->dreg);
3010 g_assert_not_reached();
3014 case OP_ALPHA_CMPT_UN:
3015 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3016 ins->sreg1, ins->sreg2, ins->dreg);
3017 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3020 case OP_ALPHA_CMPT_UN_SU:
3021 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3022 ins->sreg1, ins->sreg2, ins->dreg);
3023 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3026 case OP_ALPHA_CMPT_EQ:
3027 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3028 ins->sreg1, ins->sreg2, ins->dreg);
3029 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
3032 case OP_ALPHA_CMPT_EQ_SU:
3033 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3034 ins->sreg1, ins->sreg2, ins->dreg);
3035 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
3039 case OP_ALPHA_CMPT_LT:
3040 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3041 ins->sreg1, ins->sreg2, ins->dreg);
3042 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3045 case OP_ALPHA_CMPT_LT_SU:
3046 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3047 ins->sreg1, ins->sreg2, ins->dreg);
3048 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3051 case OP_ALPHA_CMPT_LE:
3052 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3053 ins->sreg1, ins->sreg2, ins->dreg);
3054 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3057 case OP_ALPHA_CMPT_LE_SU:
3058 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3059 ins->sreg1, ins->sreg2, ins->dreg);
3060 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3063 case OP_ALPHA_CMP_EQ:
3064 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3065 ins->sreg1, ins->sreg2, ins->dreg);
3066 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3069 case OP_ALPHA_CMP_IMM_EQ:
3070 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3071 ins->sreg1, ins->inst_imm, ins->dreg);
3072 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3075 case OP_ALPHA_CMP_IMM_ULE:
3076 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%d\n",
3077 ins->sreg1, ins->inst_imm, ins->dreg);
3078 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3081 case OP_ALPHA_CMP_ULT:
3082 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3083 ins->sreg1, ins->sreg2, ins->dreg);
3084 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3087 case OP_ALPHA_CMP_IMM_ULT:
3088 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3089 ins->sreg1, ins->inst_imm, ins->dreg);
3090 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3093 case OP_ALPHA_CMP_LE:
3094 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3095 ins->sreg1, ins->sreg2, ins->dreg);
3096 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3099 case OP_ALPHA_CMP_ULE:
3100 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3101 ins->sreg1, ins->sreg2, ins->dreg);
3102 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3106 case OP_ALPHA_CMP_IMM_LE:
3107 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%d\n",
3108 ins->sreg1, ins->inst_imm, ins->dreg);
3109 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3112 case OP_ALPHA_CMP_LT:
3113 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3114 ins->sreg1, ins->sreg2, ins->dreg);
3115 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3118 case OP_ALPHA_CMP_IMM_LT:
3119 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3120 ins->sreg1, ins->inst_imm, ins->dreg);
3121 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3124 case OP_COND_EXC_GT:
3125 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3126 (char *)ins->inst_p1);
3128 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3131 case OP_COND_EXC_GT_UN:
3132 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3133 (char *)ins->inst_p1);
3135 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3138 case OP_COND_EXC_LT:
3139 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3140 (char *)ins->inst_p1);
3142 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3145 case OP_COND_EXC_LT_UN:
3146 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3147 (char *)ins->inst_p1);
3149 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3153 case OP_COND_EXC_LE_UN:
3154 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3155 (char *)ins->inst_p1);
3156 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3159 case OP_COND_EXC_NE_UN:
3160 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3161 (char *)ins->inst_p1);
3162 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3165 case OP_COND_EXC_EQ:
3166 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3167 (char *)ins->inst_p1);
3168 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3171 case OP_COND_EXC_IOV:
3172 case OP_COND_EXC_OV:
3173 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3176 case OP_COND_EXC_IC:
3178 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3181 case CEE_CONV_OVF_U4:
3182 // Convert unsigned 32 bit value to 64 bit reg
3184 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3185 ins->sreg1, ins->dreg);
3186 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3187 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3188 alpha_mov1(code, ins->sreg1, ins->dreg);
3191 case CEE_CONV_OVF_I4_UN:
3192 // Convert unsigned 32 bit value to 64 bit reg
3194 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3195 ins->sreg1, ins->dreg);
3196 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3198 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3199 alpha_mov1(code, ins->sreg1, ins->dreg);
3203 // Move I1 (byte) to dreg(64 bits) and sign extend it
3205 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3206 ins->sreg1, ins->dreg);
3208 alpha_sextb(code, ins->sreg1, ins->dreg);
3211 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3212 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3213 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3218 // Move I2 (word) to dreg(64 bits) and sign extend it
3219 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3220 ins->sreg1, ins->dreg);
3222 alpha_sextw(code, ins->sreg1, ins->dreg);
3225 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3226 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3227 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3232 // Move I4 (long) to dreg(64 bits) and sign extend it
3233 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3234 ins->sreg1, ins->dreg);
3235 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3240 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3241 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3242 ins->sreg1, ins->dreg);
3243 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3244 alpha_mov1(code, ins->sreg1, ins->dreg);
3248 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3249 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3250 ins->sreg1, ins->dreg);
3251 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3255 // Move U2 (word) to dreg(64 bits) don't sign extend it
3256 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3257 ins->sreg1, ins->dreg);
3258 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3262 // Move U4 (long) to dreg(64 bits) don't sign extend it
3263 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3264 ins->sreg1, ins->dreg);
3265 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3270 // Move U4 (long) to dreg(64 bits) don't sign extend it
3271 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3272 ins->sreg1, ins->dreg);
3273 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3276 case OP_FCONV_TO_I4:
3277 case OP_FCONV_TO_I8:
3278 // Move float to 32 bit reg
3279 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3280 ins->sreg1, ins->dreg);
3281 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3282 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3283 alpha_lda(code, alpha_sp, alpha_sp, -8);
3284 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3285 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3286 alpha_lda(code, alpha_sp, alpha_sp, 8);
3289 case OP_FCONV_TO_I2:
3290 // Move float to 16 bit reg
3291 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3292 ins->sreg1, ins->dreg);
3293 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3294 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3295 alpha_lda(code, alpha_sp, alpha_sp, -8);
3296 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3297 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3298 alpha_lda(code, alpha_sp, alpha_sp, 8);
3299 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3300 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3303 case OP_FCONV_TO_U2:
3304 // Move float to 16 bit reg as unsigned
3305 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3306 ins->sreg1, ins->dreg);
3307 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3308 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3309 alpha_lda(code, alpha_sp, alpha_sp, -8);
3310 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3311 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3312 alpha_lda(code, alpha_sp, alpha_sp, 8);
3313 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3316 case OP_FCONV_TO_U1:
3317 // Move float to 8 bit reg as unsigned
3318 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] 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_and_(code, ins->dreg, 0xff, ins->dreg);
3329 case OP_FCONV_TO_I1:
3330 // Move float to 8 bit reg
3331 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3332 ins->sreg1, ins->dreg);
3333 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3334 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3335 alpha_lda(code, alpha_sp, alpha_sp, -8);
3336 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3337 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3338 alpha_lda(code, alpha_sp, alpha_sp, 8);
3339 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3340 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3344 case OP_LCONV_TO_R4:
3345 // Move 32/64 bit int into float
3346 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3347 ins->sreg1, ins->dreg);
3348 alpha_lda(code, alpha_sp, alpha_sp, -8);
3349 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3350 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3351 alpha_lda(code, alpha_sp, alpha_sp, 8);
3352 alpha_cvtqs(code, ins->dreg, ins->dreg);
3357 case OP_LCONV_TO_R8:
3358 // Move 32/64 bit int into double
3359 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3360 ins->sreg1, ins->dreg);
3361 alpha_lda(code, alpha_sp, alpha_sp, -8);
3362 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3363 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3364 alpha_lda(code, alpha_sp, alpha_sp, 8);
3365 alpha_cvtqt(code, ins->dreg, ins->dreg);
3369 case OP_FCONV_TO_R4:
3370 // Convert 64 bit float to 32 bit float (T -> S)
3371 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3372 ins->sreg1, ins->dreg);
3373 alpha_cvtts_su(code, ins->sreg1, ins->dreg);
3378 // Allocate sreg1 bytes on stack, round bytes by 8,
3379 // modify SP, set dreg to end of current stack frame
3380 // top of stack is used for call params
3381 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3382 ins->sreg1, ins->dreg);
3384 alpha_addq_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3385 alpha_bic_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3386 if (ins->flags & MONO_INST_INIT)
3387 alpha_mov1(code, ins->sreg1, ins->sreg2);
3389 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3390 if (cfg->arch.params_stack_size > 0)
3392 alpha_lda(code, ins->dreg, alpha_zero,
3393 (cfg->arch.params_stack_size));
3394 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3397 alpha_mov1(code, alpha_sp, ins->dreg);
3399 if (ins->flags & MONO_INST_INIT)
3401 // TODO: Optimize it later
3402 alpha_lda(code, ins->sreg2, ins->sreg2,
3403 -(MONO_ARCH_LOCALLOC_ALIGNMENT));
3404 alpha_blt(code, ins->sreg2, 3);
3405 alpha_addq(code, ins->sreg2, ins->dreg, alpha_at);
3406 alpha_stq(code, alpha_zero, alpha_at, 0);
3407 alpha_br(code, alpha_zero, -5);
3413 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3414 ins->sreg1, ins->dreg);
3415 alpha_mov1(code, ins->sreg1, ins->dreg);
3422 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3424 alpha_clr(code, ins->dreg);
3425 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3432 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3434 alpha_clr(code, ins->dreg);
3435 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3440 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3442 alpha_clr(code, ins->dreg);
3443 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3447 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3449 alpha_clr(code, ins->dreg);
3450 alpha_fbeq(code, alpha_at, 1);
3451 alpha_lda(code, ins->dreg, alpha_zero, 1);
3454 alpha_cvttq_c(code, alpha_at, alpha_at);
3455 alpha_lda(code, alpha_sp, alpha_sp, -8);
3456 alpha_stt(code, alpha_at, alpha_sp, 0);
3457 alpha_ldq(code, alpha_at, alpha_sp, 0);
3458 alpha_lda(code, alpha_sp, alpha_sp, 8);
3460 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3465 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3467 alpha_clr(code, ins->dreg);
3468 alpha_fbne(code, alpha_at, 1);
3469 alpha_lda(code, ins->dreg, alpha_zero, 1);
3472 alpha_cvttq_c(code, alpha_at, alpha_at);
3473 alpha_lda(code, alpha_sp, alpha_sp, -8);
3474 alpha_stt(code, alpha_at, alpha_sp, 0);
3475 alpha_ldq(code, alpha_at, alpha_sp, 0);
3476 alpha_lda(code, alpha_sp, alpha_sp, 8);
3478 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3484 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3486 alpha_clr(code, ins->dreg);
3487 alpha_fbeq(code, alpha_at, 1);
3488 alpha_lda(code, ins->dreg, alpha_zero, 1);
3492 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3495 alpha_clr(code, ins->dreg);
3496 alpha_fbne(code, (alpha_at+1), 1);
3497 alpha_fbeq(code, alpha_at, 1);
3498 alpha_lda(code, ins->dreg, alpha_zero, 1);
3503 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3504 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3508 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3509 alpha_fbeq(code, (alpha_at+1), 1);
3510 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3511 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3515 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3516 alpha_fbeq(code, (alpha_at+1), 1);
3517 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3518 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3522 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge] [");
3523 alpha_fbne(code, (alpha_at+1), 1);
3524 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3528 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3529 alpha_fbeq(code, (alpha_at+1), 1);
3530 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3531 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3535 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble] [");
3536 alpha_fbne(code, (alpha_at+1), 1);
3537 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3541 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3542 alpha_fbeq(code, (alpha_at+1), 1);
3543 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3544 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3548 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt] [");
3549 alpha_fbne(code, (alpha_at+1), 1);
3550 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3554 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3555 alpha_fbeq(code, (alpha_at+1), 1);
3556 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3557 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3561 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt] [");
3562 alpha_fbne(code, (alpha_at+1), 1);
3563 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3567 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3568 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3572 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3573 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3577 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3578 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3582 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3583 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3587 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3588 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3592 if (ins->flags & MONO_INST_BRLABEL)
3594 if (ins->inst_i0->inst_c0)
3596 CFG_DEBUG(4) g_print("inst_c0: %0lX, data: %p]\n",
3597 ins->inst_i0->inst_c0,
3598 cfg->native_code + ins->inst_i0->inst_c0);
3599 alpha_br(code, alpha_zero, 0);
3603 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n",
3604 offset, ins->inst_i0);
3605 mono_add_patch_info (cfg, offset,
3606 MONO_PATCH_INFO_LABEL, ins->inst_i0);
3608 alpha_br(code, alpha_zero, 0);
3613 if (ins->inst_target_bb->native_offset)
3615 // Somehow native offset is offset from
3616 // start of the code. So convert it to
3618 long br_offset = (char *)cfg->native_code +
3619 ins->inst_target_bb->native_offset - 4 - (char *)code;
3621 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3622 ins->inst_target_bb->native_offset,
3624 ins->inst_target_bb->native_offset);
3625 alpha_br(code, alpha_zero, br_offset/4);
3629 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3630 offset, ins->inst_target_bb);
3632 mono_add_patch_info (cfg, offset,
3634 ins->inst_target_bb);
3635 alpha_br(code, alpha_zero, 0);
3642 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3645 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3653 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3654 call = (MonoCallInst*)ins;
3656 if (ins->flags & MONO_INST_HAS_METHOD)
3658 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3659 code = emit_call (cfg, code,
3660 MONO_PATCH_INFO_METHOD, call->method);
3664 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3665 code = emit_call (cfg, code,
3666 MONO_PATCH_INFO_ABS, call->fptr);
3669 //code = emit_move_return_value (cfg, ins, code);
3676 case OP_VOIDCALL_REG:
3681 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3682 call = (MonoCallInst*)ins;
3684 alpha_mov1(code, ins->sreg1, alpha_pv);
3686 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3688 offset = (char *)code - (char *)cfg->native_code;
3691 ALPHA_LOAD_GP(offset)
3692 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3693 alpha_lda(code, alpha_gp, alpha_gp, 0);
3697 case OP_FCALL_MEMBASE:
3698 case OP_CALL_MEMBASE:
3699 case OP_LCALL_MEMBASE:
3700 case OP_VCALL_MEMBASE:
3704 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3705 ins->inst_basereg, ins->inst_offset);
3706 call = (MonoCallInst*)ins;
3708 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3709 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3711 offset = (char *)code - (char *)cfg->native_code;
3714 ALPHA_LOAD_GP(offset)
3715 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3716 alpha_lda(code, alpha_gp, alpha_gp, 0);
3720 case OP_VOIDCALL_MEMBASE:
3724 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3725 ins->inst_basereg, ins->inst_offset);
3726 call = (MonoCallInst*)ins;
3728 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3729 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3731 offset = (char *)code - (char *)cfg->native_code;
3734 ALPHA_LOAD_GP(offset)
3735 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3736 alpha_lda(code, alpha_gp, alpha_gp, 0);
3740 case OP_START_HANDLER:
3742 // TODO - find out when we called by call_handler or resume_context
3743 // of by call_filter. There should be difference. For now just
3744 // handle - call_handler
3746 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3747 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3749 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3750 ins->inst_left->inst_offset);
3756 // Keep in sync with start_handler
3757 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3758 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3760 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3761 ins->inst_left->inst_offset);
3763 alpha_ret(code, alpha_ra, 1);
3769 // Keep in sync with start_handler
3770 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3771 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3773 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3774 ins->inst_left->inst_offset);
3776 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3777 alpha_mov1(code, ins->sreg1, alpha_r0);
3779 alpha_ret(code, alpha_ra, 1);
3783 case OP_CALL_HANDLER:
3787 offset = (char *)code - (char *)cfg->native_code;
3789 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3790 offset, ins->inst_target_bb);
3792 mono_add_patch_info (cfg, offset,
3794 ins->inst_target_bb);
3795 alpha_bsr(code, alpha_ra, 0);
3800 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3802 alpha_mov1(code, ins->sreg1, alpha_a0);
3803 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3804 (gpointer)"mono_arch_throw_exception");
3808 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3810 alpha_mov1(code, ins->sreg1, alpha_a0);
3811 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3812 (gpointer)"mono_arch_rethrow_exception");
3818 * Note: this 'frame destruction' logic is useful for tail calls,
3819 too. Keep in sync with the code in emit_epilog.
3822 AlphaGotData ge_data;
3824 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3826 /* FIXME: no tracing support... */
3827 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3828 code = mono_arch_instrument_epilog (cfg,
3829 mono_profiler_method_leave, code, FALSE);
3830 g_assert (!cfg->method->save_lmf);
3832 alpha_mov1( code, alpha_fp, alpha_sp );
3834 code = emit_load_volatile_arguments (cfg, code);
3836 offset = cfg->arch.params_stack_size;
3838 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3839 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3840 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3842 ge_data.data.p = ins->inst_p0;
3843 add_got_entry(cfg, GT_PTR, ge_data,
3844 (char *)code - (char *)cfg->native_code,
3845 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3846 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3848 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3853 mono_add_patch_info (cfg, offset,
3854 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3857 case OP_MEMORY_BARRIER:
3858 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3863 // Float register contains a value which we need to check
3865 double ni = -1.0 / 0.0;
3866 double pi = 1.0 / 0.0;
3867 AlphaGotData ge_data;
3869 CFG_DEBUG(4) g_print("ALPHA_TODO: [chfinite] sreg1=%d\n", ins->sreg1);
3870 alpha_cmptun_su(code, ins->sreg1, ins->sreg1, alpha_at);
3872 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3874 // Negative infinity
3875 ge_data.data.d = ni;
3876 add_got_entry(cfg, GT_DOUBLE, ge_data,
3877 (char *)code - (char *)cfg->native_code,
3878 MONO_PATCH_INFO_NONE, 0);
3879 alpha_ldt(code, alpha_at, alpha_gp, 0);
3881 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3884 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3886 // Positive infinity
3887 ge_data.data.d = pi;
3888 add_got_entry(cfg, GT_DOUBLE, ge_data,
3889 (char *)code - (char *)cfg->native_code,
3890 MONO_PATCH_INFO_NONE, 0);
3891 alpha_ldt(code, alpha_at, alpha_gp, 0);
3893 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3896 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3900 CFG_DEBUG(4) g_print("ALPHA_TODO: [fdiv] dest=%d, sreg1=%d, sreg2=%d\n",
3901 ins->dreg, ins->sreg1, ins->sreg2);
3902 alpha_divt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
3907 g_warning ("unknown opcode %s in %s()\n",
3908 mono_inst_name (ins->opcode), __FUNCTION__);
3910 // g_assert_not_reached ();
3914 if ( (((char *)code) -
3915 ((char *)cfg->native_code) -
3918 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3919 mono_inst_name (ins->opcode), max_len,
3920 ((char *)code) - ((char *)cfg->native_code) - offset );
3921 //g_assert_not_reached ();
3926 last_offset = offset;
3929 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3932 /*========================= End of Function ========================*/
3937 /*------------------------------------------------------------------*/
3939 /* Name - mono_arch_cpu_optimizazions */
3941 /* Function - Returns the optimizations supported on this CPU */
3943 /*------------------------------------------------------------------*/
3946 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3950 if (getenv("MONO_ALPHA_DEBUG"))
3951 mini_alpha_verbose_level = 1;
3953 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3955 /*----------------------------------------------------------*/
3956 /* no alpha-specific optimizations yet */
3957 /*----------------------------------------------------------*/
3958 *exclude_mask = MONO_OPT_LINEARS;
3959 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3963 /*========================= End of Function ========================*/
3965 /*------------------------------------------------------------------*/
3967 /* Name - mono_arch_flush_icache */
3969 /* Function - Flush the CPU icache. */
3971 /*------------------------------------------------------------------*/
3974 mono_arch_flush_icache (guint8 *code, gint size)
3976 //ALPHA_DEBUG("mono_arch_flush_icache");
3978 /* flush instruction cache to see trampoline code */
3979 asm volatile("imb":::"memory");
3982 /*========================= End of Function ========================*/
3984 /*------------------------------------------------------------------*/
3986 /* Name - mono_arch_regname */
3988 /* Function - Returns the name of the register specified by */
3989 /* the input parameter. */
3991 /*------------------------------------------------------------------*/
3994 mono_arch_regname (int reg) {
3995 static const char * rnames[] = {
3996 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
3997 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
3998 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
3999 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
4000 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
4001 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
4002 "alpha_r30", "alpha_r31"
4005 if (reg >= 0 && reg < 32)
4006 return rnames [reg];
4010 /*========================= End of Function ========================*/
4012 /*------------------------------------------------------------------*/
4014 /* Name - mono_arch_fregname */
4016 /* Function - Returns the name of the register specified by */
4017 /* the input parameter. */
4019 /*------------------------------------------------------------------*/
4022 mono_arch_fregname (int reg) {
4023 static const char * rnames[] = {
4024 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4025 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4026 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4027 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4028 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4029 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4030 "alpha_f30", "alpha_f31"
4033 if (reg >= 0 && reg < 32)
4034 return rnames [reg];
4039 /*========================= End of Function ========================*/
4041 /*------------------------------------------------------------------*/
4043 /* Name - mono_arch_patch_code */
4045 /* Function - Process the patch data created during the */
4046 /* instruction build process. This resolves jumps, */
4047 /* calls, variables etc. */
4049 /*------------------------------------------------------------------*/
4052 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
4053 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4055 MonoJumpInfo *patch_info;
4056 gboolean compile_aot = !run_cctors;
4058 ALPHA_DEBUG("mono_arch_patch_code");
4060 for (patch_info = ji; patch_info; patch_info = patch_info->next)
4062 unsigned char *ip = patch_info->ip.i + code;
4063 const unsigned char *target;
4065 target = mono_resolve_patch_target (method, domain,
4066 code, patch_info, run_cctors);
4070 switch (patch_info->type)
4073 case MONO_PATCH_INFO_BB:
4074 case MONO_PATCH_INFO_LABEL:
4077 /* No need to patch these */
4082 switch (patch_info->type)
4084 case MONO_PATCH_INFO_NONE:
4087 case MONO_PATCH_INFO_GOT_OFFSET:
4089 unsigned int *ip2 = (unsigned int *)ip;
4090 unsigned int inst = *ip2;
4091 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
4093 g_assert(!(off & 0xFFFF8000));
4101 case MONO_PATCH_INFO_CLASS_INIT:
4103 /* Might already been changed to a nop */
4104 unsigned int* ip2 = (unsigned int *)ip;
4105 unsigned long t_addr = (unsigned long)target;
4107 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
4108 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
4110 // amd64_call_code (ip2, 0);
4114 // case MONO_PATCH_INFO_METHOD_REL:
4115 case MONO_PATCH_INFO_R8:
4116 case MONO_PATCH_INFO_R4:
4117 g_assert_not_reached ();
4119 case MONO_PATCH_INFO_BB:
4122 case MONO_PATCH_INFO_METHOD:
4123 case MONO_PATCH_INFO_METHODCONST:
4124 case MONO_PATCH_INFO_INTERNAL_METHOD:
4125 case MONO_PATCH_INFO_METHOD_JUMP:
4127 volatile unsigned int *p = (unsigned int *)ip;
4128 unsigned long t_addr;
4135 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4137 if (target != ((void *)t_addr))
4139 t_addr = (unsigned long)target;
4140 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4141 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4146 case MONO_PATCH_INFO_ABS:
4148 volatile unsigned int *p = (unsigned int *)ip;
4149 unsigned long t_addr;
4155 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4160 case MONO_PATCH_INFO_SWITCH:
4162 unsigned int *pcode = (unsigned int *)ip;
4163 unsigned long t_addr;
4165 t_addr = (unsigned long)target;
4167 if (((unsigned long)ip) % 8)
4173 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4174 alpha_nop(pcode); // TODO optimize later
4175 alpha_bsr(pcode, alpha_at, 2);
4177 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4179 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4182 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4192 volatile unsigned int *p = (unsigned int *)ip;
4193 unsigned int alpha_ins = *p;
4194 unsigned int opcode;
4197 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4199 if (opcode >= 0x30 && opcode <= 0x3f)
4201 // This is branch with offset instruction
4202 br_offset = (target - ip - 4);
4204 g_assert(!(br_offset & 3));
4206 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4214 /*========================= End of Function ========================*/
4215 /*------------------------------------------------------------------*/
4217 /* Name - mono_arch_emit_this_vret_args */
4221 /*------------------------------------------------------------------*/
4224 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4225 int this_reg, int this_type, int vt_reg)
4227 MonoCallInst *call = (MonoCallInst*)inst;
4228 CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, inst->signature, FALSE);
4230 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4236 if (cinfo->ret.storage == ArgValuetypeInReg)
4239 * The valuetype is in RAX:RDX after the call, need to be copied to
4240 * the stack. Push the address here, so the call instruction can
4243 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4244 //vtarg->sreg1 = vt_reg;
4245 //mono_bblock_add_inst (cfg->cbb, vtarg);
4248 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4253 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4254 vtarg->sreg1 = vt_reg;
4255 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4256 mono_bblock_add_inst (cfg->cbb, vtarg);
4258 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4259 cinfo->ret.reg, FALSE);
4263 /* add the this argument */
4267 MONO_INST_NEW (cfg, this, OP_MOVE);
4268 this->type = this_type;
4269 this->sreg1 = this_reg;
4270 this->dreg = mono_regstate_next_int (cfg->rs);
4271 mono_bblock_add_inst (cfg->cbb, this);
4273 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4274 cinfo->args [0].reg, FALSE);
4280 /*========================= End of Function ========================*/
4282 /*------------------------------------------------------------------*/
4284 /* Name - mono_arch_is_inst_imm */
4286 /* Function - Determine if operand qualifies as an immediate */
4287 /* value. For Alpha this is a value 0 - 255 */
4289 /* Returns - True|False - is [not] immediate value. */
4291 /*------------------------------------------------------------------*/
4294 mono_arch_is_inst_imm (gint64 imm)
4296 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4298 return (imm & ~(0x0FFL)) ? 0 : 1;
4301 /*------------------------------------------------------------------*/
4303 /* Name - mono_arch_setup_jit_tls_data */
4305 /* Function - Setup the JIT's Thread Level Specific Data. */
4307 /*------------------------------------------------------------------*/
4310 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4312 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4314 if (!tls_offset_inited) {
4315 tls_offset_inited = TRUE;
4318 if (!lmf_addr_key_inited) {
4319 lmf_addr_key_inited = TRUE;
4320 pthread_key_create (&lmf_addr_key, NULL);
4323 pthread_setspecific (lmf_addr_key, &tls->lmf);
4326 /*------------------------------------------------------------------*/
4328 /* Name - mono_arch_cpu_init */
4330 /* Function - Perform CPU specific initialization to execute */
4333 /*------------------------------------------------------------------*/
4336 mono_arch_cpu_init (void)
4338 unsigned long amask, implver;
4339 register long v0 __asm__("$0") = -1;
4341 ALPHA_DEBUG("mono_arch_cpu_init");
4343 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
4345 __asm__ (".long 0x47e03d80" : "=r"(v0));
4351 //printf("amask: %x, implver: %x", amask, implver);
4355 * Initialize architecture specific code.
4358 mono_arch_init (void)
4363 * Cleanup architecture specific code.
4366 mono_arch_cleanup (void)
4373 * Obtain information about a call according to the calling convention.
4375 * For x86 ELF, see the "System V Application Binary Interface Intel386
4376 * Architecture Processor Supplment, Fourth Edition" document for more
4378 * For x86 win32, see ???.
4381 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
4383 guint32 i, gr, fr, *pgr, *pfr;
4385 int n = sig->hasthis + sig->param_count;
4386 guint32 stack_size = 0;
4389 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4404 ret_type = mono_type_get_underlying_type (sig->ret);
4405 switch (ret_type->type) {
4406 case MONO_TYPE_BOOLEAN:
4411 case MONO_TYPE_CHAR:
4417 case MONO_TYPE_FNPTR:
4418 case MONO_TYPE_CLASS:
4419 case MONO_TYPE_OBJECT:
4420 case MONO_TYPE_SZARRAY:
4421 case MONO_TYPE_ARRAY:
4422 case MONO_TYPE_STRING:
4423 cinfo->ret.storage = ArgInIReg;
4424 cinfo->ret.reg = alpha_r0;
4428 cinfo->ret.storage = ArgInIReg;
4429 cinfo->ret.reg = alpha_r0;
4432 cinfo->ret.storage = ArgInFloatReg;
4433 cinfo->ret.reg = alpha_f0;
4436 cinfo->ret.storage = ArgInDoubleReg;
4437 cinfo->ret.reg = alpha_f0;
4439 case MONO_TYPE_GENERICINST:
4440 if (!mono_type_generic_inst_is_valuetype (sig->ret))
4442 cinfo->ret.storage = ArgInIReg;
4443 cinfo->ret.reg = alpha_r0;
4447 case MONO_TYPE_VALUETYPE:
4449 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4451 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE,
4452 &tmp_gr, &tmp_fr, &tmp_stacksize);
4454 if (cinfo->ret.storage == ArgOnStack)
4455 /* The caller passes the address where the value
4457 add_general (pgr, &stack_size, &cinfo->ret);
4460 case MONO_TYPE_TYPEDBYREF:
4461 /* Same as a valuetype with size 24 */
4462 add_general (pgr, &stack_size, &cinfo->ret);
4465 case MONO_TYPE_VOID:
4468 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4474 add_general (pgr, &stack_size, cinfo->args + 0);
4476 if (!sig->pinvoke &&
4477 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4480 fr = FLOAT_PARAM_REGS;
4482 /* Emit the signature cookie just before the implicit arguments
4484 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4487 for (i = 0; i < sig->param_count; ++i)
4489 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4492 if (!sig->pinvoke &&
4493 (sig->call_convention == MONO_CALL_VARARG) &&
4494 (i == sig->sentinelpos))
4496 /* We allways pass the sig cookie on the stack for simpl
4499 * Prevent implicit arguments + the sig cookie from being passed
4503 fr = FLOAT_PARAM_REGS;
4505 /* Emit the signature cookie just before the implicit arguments */
4506 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4509 if (sig->params [i]->byref) {
4510 add_general (pgr, &stack_size, ainfo);
4514 ptype = mono_type_get_underlying_type (sig->params [i]);
4516 switch (ptype->type) {
4517 case MONO_TYPE_BOOLEAN:
4520 add_general (pgr, &stack_size, ainfo);
4524 case MONO_TYPE_CHAR:
4525 add_general (pgr, &stack_size, ainfo);
4529 add_general (pgr, &stack_size, ainfo);
4534 case MONO_TYPE_FNPTR:
4535 case MONO_TYPE_CLASS:
4536 case MONO_TYPE_OBJECT:
4537 case MONO_TYPE_STRING:
4538 case MONO_TYPE_SZARRAY:
4539 case MONO_TYPE_ARRAY:
4540 add_general (pgr, &stack_size, ainfo);
4542 case MONO_TYPE_GENERICINST:
4543 if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
4545 add_general (pgr, &stack_size, ainfo);
4549 case MONO_TYPE_VALUETYPE:
4551 /* We allways pass valuetypes on the stack */
4552 add_valuetype (gsctx, sig, ainfo, sig->params [i],
4553 FALSE, pgr, pfr, &stack_size);
4555 case MONO_TYPE_TYPEDBYREF:
4556 stack_size += sizeof (MonoTypedRef);
4557 ainfo->storage = ArgOnStack;
4561 add_general (pgr, &stack_size, ainfo);
4564 add_float (pfr, &stack_size, ainfo, FALSE);
4567 add_float (pfr, &stack_size, ainfo, TRUE);
4570 g_assert_not_reached ();
4574 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4575 (n > 0) && (sig->sentinelpos == sig->param_count))
4578 fr = FLOAT_PARAM_REGS;
4580 /* Emit the signature cookie just before the implicit arguments
4582 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4585 cinfo->stack_usage = stack_size;
4586 cinfo->reg_usage = gr;
4587 cinfo->freg_usage = fr;
4592 static const char *CvtMonoType(MonoTypeEnum t)
4597 return "MONO_TYPE_END";
4598 case MONO_TYPE_VOID:
4599 return "MONO_TYPE_VOID";
4600 case MONO_TYPE_BOOLEAN:
4601 return "MONO_TYPE_BOOLEAN";
4602 case MONO_TYPE_CHAR:
4603 return "MONO_TYPE_CHAR";
4605 return "MONO_TYPE_I1";
4607 return "MONO_TYPE_U1";
4609 return "MONO_TYPE_I2";
4611 return "MONO_TYPE_U2";
4613 return "MONO_TYPE_I4";
4615 return "MONO_TYPE_U4";
4617 return "MONO_TYPE_I8";
4619 return "MONO_TYPE_U8";
4621 return "MONO_TYPE_R4";
4623 return "MONO_TYPE_R8";
4624 case MONO_TYPE_STRING:
4625 return "MONO_TYPE_STRING";
4627 return "MONO_TYPE_PTR";
4628 case MONO_TYPE_BYREF:
4629 return "MONO_TYPE_BYREF";
4630 case MONO_TYPE_VALUETYPE:
4631 return "MONO_TYPE_VALUETYPE";
4632 case MONO_TYPE_CLASS:
4633 return "MONO_TYPE_CLASS";
4635 return "MONO_TYPE_VAR";
4636 case MONO_TYPE_ARRAY:
4637 return "MONO_TYPE_ARRAY";
4638 case MONO_TYPE_GENERICINST:
4639 return "MONO_TYPE_GENERICINST";
4640 case MONO_TYPE_TYPEDBYREF:
4641 return "MONO_TYPE_TYPEDBYREF";
4643 return "MONO_TYPE_I";
4645 return "MONO_TYPE_U";
4646 case MONO_TYPE_FNPTR:
4647 return "MONO_TYPE_FNPTR";
4648 case MONO_TYPE_OBJECT:
4649 return "MONO_TYPE_OBJECT";
4650 case MONO_TYPE_SZARRAY:
4651 return "MONO_TYPE_SZARRAY";
4652 case MONO_TYPE_MVAR:
4653 return "MONO_TYPE_MVAR";
4654 case MONO_TYPE_CMOD_REQD:
4655 return "MONO_TYPE_CMOD_REQD";
4656 case MONO_TYPE_CMOD_OPT:
4657 return "MONO_TYPE_CMOD_OPT";
4658 case MONO_TYPE_INTERNAL:
4659 return "MONO_TYPE_INTERNAL";
4660 case MONO_TYPE_MODIFIER:
4661 return "MONO_TYPE_MODIFIER";
4662 case MONO_TYPE_SENTINEL:
4663 return "MONO_TYPE_SENTINEL";
4664 case MONO_TYPE_PINNED:
4665 return "MONO_TYPE_PINNED";
4673 /*------------------------------------------------------------------*/
4675 /* Name - mono_arch_call_opcode */
4677 /* Function - Take the arguments and generate the arch-specific */
4678 /* instructions to properly call the function. This */
4679 /* includes pushing, moving argments to the correct */
4682 * This method is called during converting method to IR
4683 * We need to generate IR ints to follow calling convention
4684 * cfg - points to currently compiled unit
4686 * call - points to structure that describes what we are going to
4687 * call (at least number of parameters required for the call)
4690 * On return we need to pass back modified call structure
4692 /*------------------------------------------------------------------*/
4695 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4696 MonoCallInst *call, int is_virtual)
4699 MonoMethodSignature *sig;
4704 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4706 sig = call->signature;
4707 n = sig->param_count + sig->hasthis;
4709 // Collect info about method we age going to call
4710 cinfo = get_call_info (cfg->generic_sharing_context, sig, sig->pinvoke);
4712 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4713 sig->pinvoke ? "PInvoke" : "Managed",
4714 sig->param_count, sig->hasthis,
4715 CvtMonoType(sig->ret->type), sig->ret->type);
4717 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4718 cfg->arch.params_stack_size = cinfo->stack_usage;
4720 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4721 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4723 for (i = 0; i < n; ++i)
4725 ArgInfo *ainfo = cinfo->args + i;
4727 /* Emit the signature cookie just before the implicit arguments
4729 if (!sig->pinvoke &&
4730 (sig->call_convention == MONO_CALL_VARARG) &&
4733 MonoMethodSignature *tmp_sig;
4736 /* FIXME: Add support for signature tokens to AOT */
4737 cfg->disable_aot = TRUE;
4738 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4741 * mono_ArgIterator_Setup assumes the signature cookie is
4742 * passed first and all the arguments which were before it are
4743 * passed on the stack after the signature. So compensate by
4744 * passing a different signature.
4746 tmp_sig = mono_metadata_signature_dup (call->signature);
4747 tmp_sig->param_count -= call->signature->sentinelpos;
4748 tmp_sig->sentinelpos = 0;
4749 memcpy (tmp_sig->params,
4750 call->signature->params + call->signature->sentinelpos,
4751 tmp_sig->param_count * sizeof (MonoType*));
4753 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4754 sig_arg->inst_p0 = tmp_sig;
4756 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4757 arg->inst_left = sig_arg;
4758 arg->type = STACK_PTR;
4759 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4762 if (is_virtual && i == 0) {
4763 /* the argument will be attached to the call instrucion
4765 in = call->args [i];
4769 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4770 in = call->args [i];
4771 arg->cil_code = in->cil_code;
4772 arg->inst_left = in;
4773 arg->type = in->type;
4774 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4776 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4778 if (sig->hasthis && (i == 0))
4779 arg_type = &mono_defaults.object_class->byval_arg;
4781 arg_type = sig->params [i - sig->hasthis];
4783 if ((i >= sig->hasthis) &&
4784 (MONO_TYPE_ISSTRUCT(arg_type)))
4789 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4790 size = sizeof (MonoTypedRef);
4791 align = sizeof (gpointer);
4795 size = mono_type_native_stack_size (&in->klass->byval_arg,
4798 size = mini_type_stack_size (cfg->generic_sharing_context, &in->klass->byval_arg, &align);
4800 if (ainfo->storage == ArgAggregate)
4802 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4805 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4807 vtaddr = mono_compile_create_var (cfg,
4808 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4811 * Part of the structure is passed in registers.
4813 for (j = 0; j < ainfo->nregs; ++j)
4815 int offset, load_op, dest_reg, arg_storage;
4817 slot = ainfo->reg + j;
4818 load_op = CEE_LDIND_I;
4820 dest_reg = ainfo->reg + j;
4821 arg_storage = ArgInIReg;
4823 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4824 load->ssa_op = MONO_SSA_LOAD;
4825 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4827 NEW_ICONST (cfg, offset_ins, offset);
4828 MONO_INST_NEW (cfg, load2, CEE_ADD);
4829 load2->inst_left = load;
4830 load2->inst_right = offset_ins;
4832 MONO_INST_NEW (cfg, load, load_op);
4833 load->inst_left = load2;
4838 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4840 add_outarg_reg (cfg, call, set_reg, arg_storage,
4842 if (&set_reg->node != call->out_args.next)
4844 MONO_INST_LIST_ADD (&set_reg->node, &call->out_args);
4849 * Part of the structure is passed on the stack.
4851 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4855 slot = ainfo->reg + j;
4857 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4858 load->ssa_op = MONO_SSA_LOAD;
4859 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4861 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4862 MONO_INST_NEW (cfg, load2, CEE_ADD);
4863 load2->inst_left = load;
4864 load2->inst_right = offset_ins;
4866 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4867 load->inst_left = load2;
4872 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4874 outarg->inst_left = load;
4875 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4876 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4878 if (&outarg->node != call->out_args.next)
4880 MONO_INST_LIST_ADD (&outarg->node, &call->out_args);
4884 /* Trees can't be shared so make a copy*/
4885 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4886 arg->cil_code = in->cil_code;
4887 arg->ssa_op = MONO_SSA_STORE;
4888 arg->inst_left = vtaddr;
4889 arg->inst_right = in;
4890 arg->type = in->type;
4891 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4895 MonoInst *stack_addr;
4897 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4899 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4900 stack_addr->inst_basereg = alpha_sp;
4901 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4902 stack_addr->inst_offset = ainfo->offset;
4903 //stack_addr->inst_offset = 16 + ainfo->offset;
4904 stack_addr->inst_imm = size;
4906 arg->opcode = OP_OUTARG_VT;
4907 arg->inst_right = stack_addr;
4911 arg->opcode = OP_OUTARG_VT;
4912 arg->klass = in->klass;
4913 arg->backend.is_pinvoke = sig->pinvoke;
4914 arg->inst_imm = size; */
4918 CFG_DEBUG(3) g_print("simple\n");
4920 switch (ainfo->storage)
4923 add_outarg_reg (cfg, call, arg, ainfo->storage,
4927 arg->opcode = OP_OUTARG;
4928 //arg->dreg = -((n - i) * 8);
4929 arg->dreg = ainfo->offset;
4930 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4932 if (!sig->params[i-sig->hasthis]->byref) {
4933 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4934 arg->opcode = OP_OUTARG_R4;
4936 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4937 arg->opcode = OP_OUTARG_R8;
4941 case ArgInDoubleReg:
4942 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4945 g_assert_not_reached ();
4951 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4953 if (cinfo->ret.storage == ArgValuetypeInReg) {
4954 MonoInst *zero_inst;
4956 * After the call, the struct is in registers, but needs to be saved
4957 to the memory pointed
4958 * to by vt_arg in this_vret_args. This means that vt_ar
4959 g needs to be saved somewhere
4960 * before calling the function. So we add a dummy instru
4961 ction to represent pushing the
4962 * struct return address to the stack. The return addres
4963 s will be saved to this stack slot
4964 * by the code emitted in this_vret_args.
4966 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4967 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
4968 zero_inst->inst_p0 = 0;
4969 arg->inst_left = zero_inst;
4970 arg->type = STACK_PTR;
4971 MONO_INST_LIST_ADD (&arg->node, &call->out_args);
4974 /* if the function returns a struct, the called method a
4975 lready does a ret $0x4 */
4976 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4977 ; //cinfo->stack_usage -= 4;
4980 // stack_usage shows how much stack we would need to do the call
4981 // (for example for params that we pass on stack
4982 call->stack_usage = cinfo->stack_usage;
4984 // Save all used regs to do the call in compile unit structure
4985 cfg->used_int_regs |= call->used_iregs;
4992 /*========================= End of Function ========================*/
4994 /*------------------------------------------------------------------*/
4996 /* Name - mono_arch_register_lowlevel_calls */
4998 /* Function - Register routines to help with --trace operation. */
5000 /*------------------------------------------------------------------*/
5003 mono_arch_register_lowlevel_calls (void)
5005 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
5007 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
5011 /*========================= End of Function ========================*/
5013 /*------------------------------------------------------------------*/
5015 /* Name - mono_arch_global_int_regs */
5017 /* Function - Return a list of usable integer registers. */
5019 /*------------------------------------------------------------------*/
5022 mono_arch_get_global_int_regs (MonoCompile *cfg)
5026 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5028 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5029 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5030 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5031 regs = g_list_prepend (regs, (gpointer)alpha_r12);
5032 regs = g_list_prepend (regs, (gpointer)alpha_r13);
5033 regs = g_list_prepend (regs, (gpointer)alpha_r14);
5038 /*========================= End of Function ========================*/
5040 /*------------------------------------------------------------------*/
5042 /* Name - mono_arch_get_allocatable_int_vars */
5046 /*------------------------------------------------------------------*/
5049 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
5053 MonoMethodSignature *sig;
5054 MonoMethodHeader *header;
5057 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5059 header = mono_method_get_header (cfg->method);
5061 sig = mono_method_signature (cfg->method);
5063 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5065 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5067 MonoInst *ins = cfg->args [i];
5069 ArgInfo *ainfo = &cinfo->args [i];
5072 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5075 // if (ainfo->storage == ArgInIReg) {
5076 // /* The input registers are non-volatile */
5077 // ins->opcode = OP_REGVAR;
5078 //ins->dreg = 32 + ainfo->reg;
5082 for (i = 0; i < cfg->num_varinfo; i++)
5084 MonoInst *ins = cfg->varinfo [i];
5085 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
5088 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
5092 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
5093 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
5096 if (mono_is_regsize_var (ins->inst_vtype))
5098 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
5099 g_assert (i == vmv->idx);
5100 vars = g_list_prepend (vars, vmv);
5104 vars = mono_varlist_sort (cfg, vars, 0);
5109 /*========================= End of Function ========================*/
5111 /*------------------------------------------------------------------*/
5113 /* Name - mono_arch_get_domain_intrinsic */
5119 /*------------------------------------------------------------------*/
5122 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5126 if (appdomain_tls_offset == -1)
5129 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5130 ins->inst_offset = appdomain_tls_offset;
5134 /*========================= End of Function ========================*/
5136 /*------------------------------------------------------------------*/
5138 /* Name - mono_arch_get_thread_intrinsic */
5144 /*------------------------------------------------------------------*/
5147 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5151 if (thread_tls_offset == -1)
5154 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5155 ins->inst_offset = thread_tls_offset;
5159 /*========================= End of Function ========================*/
5161 /*------------------------------------------------------------------*/
5163 /* Name - mono_arch_get_inst_for_method */
5165 /* Function - Check for opcodes we can handle directly in */
5168 /*------------------------------------------------------------------*/
5171 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5172 MonoMethodSignature *fsig, MonoInst **args)
5174 MonoInst *ins = NULL;
5176 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5178 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5183 /*========================= End of Function ========================*/
5185 /*------------------------------------------------------------------*/
5187 /* Name - mono_arch_create_class_init_trampoline */
5189 /* Function - Creates a trampoline function to run a type init- */
5190 /* ializer. If the trampoline is called, it calls */
5191 /* mono_runtime_class_init with the given vtable, */
5192 /* then patches the caller code so it does not get */
5193 /* called any more. */
5195 /* Parameter - vtable - The type to initialize */
5197 /* Returns - A pointer to the newly created code */
5199 /*------------------------------------------------------------------*/
5202 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5204 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5211 /*------------------------------------------------------------------*/
5213 /* Name - mono_arch_instrument_prolog */
5215 /* Function - Create an "instrumented" prolog. */
5217 /*------------------------------------------------------------------*/
5220 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5221 gboolean enable_arguments)
5223 unsigned int *code = p;
5226 CallInfo *cinfo = NULL;
5227 MonoMethodSignature *sig;
5229 int i, n, stack_area = 0;
5230 AlphaGotData ge_data;
5232 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5234 /* Keep this in sync with mono_arch_get_argument_info */
5235 if (enable_arguments)
5237 /* Allocate a new area on the stack and save arguments there */
5238 sig = mono_method_signature (cfg->method);
5240 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5242 n = sig->param_count + sig->hasthis;
5244 stack_area = ALIGN_TO (n * 8, 8);
5246 // Correct stack by calculated value
5248 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5250 for (i = 0; i < n; ++i)
5252 inst = cfg->args [i];
5254 if (inst->opcode == OP_REGVAR)
5256 switch(cinfo->args[i].storage)
5258 case ArgInDoubleReg:
5259 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5262 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5265 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5270 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5271 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5276 offset = (char *)code - (char *)cfg->native_code;
5278 ge_data.data.p = cfg->method;
5280 add_got_entry(cfg, GT_PTR, ge_data,
5281 (char *)code - (char *)cfg->native_code,
5282 MONO_PATCH_INFO_METHODCONST, cfg->method);
5283 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5285 alpha_mov1(code, alpha_sp, alpha_a1);
5287 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5289 if (enable_arguments)
5291 // Correct stack back by calculated value
5293 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5301 /*========================= End of Function ========================*/
5311 /*------------------------------------------------------------------*/
5313 /* Name - mono_arch_instrument_epilog */
5315 /* Function - Create an epilog that will handle the returned */
5316 /* values used in instrumentation. */
5318 /*------------------------------------------------------------------*/
5321 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p,
5322 gboolean enable_arguments)
5324 unsigned int *code = p;
5325 int save_mode = SAVE_NONE;
5327 MonoMethod *method = cfg->method;
5328 AlphaGotData ge_data;
5329 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5331 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5335 case MONO_TYPE_VOID:
5336 /* special case string .ctor icall */
5337 if (strcmp (".ctor", method->name) &&
5338 method->klass == mono_defaults.string_class)
5339 save_mode = SAVE_R0;
5341 save_mode = SAVE_NONE;
5345 save_mode = SAVE_R0;
5349 save_mode = SAVE_XMM;
5351 case MONO_TYPE_VALUETYPE:
5352 save_mode = SAVE_STRUCT;
5355 save_mode = SAVE_R0;
5359 /* Save the result and copy it into the proper argument register */
5363 alpha_lda(code, alpha_sp, alpha_sp, -8);
5364 alpha_stq(code, alpha_r0, alpha_sp, 0);
5366 if (enable_arguments)
5367 alpha_mov1(code, alpha_r0, alpha_a1);
5372 if (enable_arguments)
5373 alpha_lda(code, alpha_a1, alpha_zero, 0);
5377 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5378 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5380 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5382 * The result is already in the proper argument register so no copying
5389 g_assert_not_reached ();
5392 offset = (char *)code - (char *)cfg->native_code;
5394 ge_data.data.p = cfg->method;
5396 add_got_entry(cfg, GT_PTR, ge_data,
5397 (char *)code - (char *)cfg->native_code,
5398 MONO_PATCH_INFO_METHODCONST, cfg->method);
5400 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5402 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5404 /* Restore result */
5408 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5409 alpha_lda(code, alpha_sp, alpha_sp, 8);
5415 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5416 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5417 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5422 g_assert_not_reached ();
5428 /*========================= End of Function ========================*/
5430 /*------------------------------------------------------------------*/
5432 /* Name - mono_arch_allocate_vars */
5434 /* Function - Set var information according to the calling */
5435 /* convention for Alpha. The local var stuff should */
5436 /* most likely be split in another method. */
5438 /* Parameter - @m - Compile unit. */
5440 * This method is called right before working with BBs. Conversion to
5441 * IR was done and some analises what registers would be used.
5442 * Collect info about registers we used - if we want to use a register
5443 * we need to allocate space for it and save on the stack in method
5446 * Alpha calling convertion:
5447 * FP -> Stack top <- SP
5448 * 0: Stack params to call others
5450 * RA <- arch.params_stack_size
5453 * [LMF info] <- arch.lmf_offset
5455 * [possible return values allocated on stack]
5459 * . caller saved regs <- arch.reg_save_area_offset
5460 * . a0 <- arch.args_save_area_offset
5466 * ------------------------
5467 * . a6 - passed args on stack
5470 /*------------------------------------------------------------------*/
5473 mono_arch_allocate_vars (MonoCompile *cfg)
5475 MonoMethodSignature *sig;
5476 MonoMethodHeader *header;
5478 int i, offset = 0, a_off = 0;
5479 guint32 locals_stack_size, locals_stack_align = 0;
5483 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5485 header = mono_method_get_header (cfg->method);
5487 sig = mono_method_signature (cfg->method);
5489 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5491 /* if (cfg->arch.omit_fp) {
5492 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5493 cfg->frame_reg = AMD64_RSP;
5498 /* Locals are allocated forwards from FP. After
5499 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5500 * (starting from offset 16).
5501 * FIXME: Check there Arg6...Argn are supposed to be
5503 cfg->frame_reg = alpha_fp;
5504 // offset = MONO_ALPHA_VARS_OFFSET;
5507 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5508 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5509 offset += cfg->arch.params_stack_size;
5511 offset += 16; // Size to save RA & FP
5513 if (cfg->method->save_lmf)
5515 /* Reserve stack space for saving LMF + argument regs */
5516 guint32 size = sizeof (MonoLMF);
5518 //if (lmf_tls_offset == -1)
5519 // /* Need to save argument regs too */
5520 // size += (AMD64_NREG * 8) + (8 * 8);
5522 cfg->arch.lmf_offset = offset;
5525 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5526 cfg->method->name, cfg->arch.lmf_offset, size);
5529 if (sig->ret->type != MONO_TYPE_VOID)
5531 switch (cinfo->ret.storage)
5535 case ArgInDoubleReg:
5536 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5537 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5538 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5540 /* The register is volatile */
5541 cfg->ret->opcode = OP_REGOFFSET;
5542 cfg->ret->inst_basereg = cfg->frame_reg;
5544 /*if (cfg->arch.omit_fp) {
5545 cfg->ret->inst_offset = offset;
5549 cfg->ret->inst_offset = offset;
5550 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5556 cfg->ret->opcode = OP_REGVAR;
5557 cfg->ret->inst_c0 = cinfo->ret.reg;
5560 case ArgValuetypeInReg:
5561 /* Allocate a local to hold the result, the epilog will
5562 copy it to the correct place */
5563 // g_assert (!cfg->arch.omit_fp);
5565 cfg->ret->opcode = OP_REGOFFSET;
5566 cfg->ret->inst_basereg = cfg->frame_reg;
5567 cfg->ret->inst_offset = offset;
5570 g_assert_not_reached ();
5572 cfg->ret->dreg = cfg->ret->inst_c0;
5575 /* Allocate locals */
5576 offsets = mono_allocate_stack_slots_full (cfg,
5577 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5579 &locals_stack_align);
5581 //g_assert((locals_stack_size % 8) == 0);
5582 if (locals_stack_size % 8)
5584 locals_stack_size += 8 - (locals_stack_size % 8);
5587 /* if (locals_stack_align)
5589 offset += (locals_stack_align - 1);
5590 offset &= ~(locals_stack_align - 1);
5594 cfg->arch.localloc_offset = offset;
5596 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5597 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5598 locals_stack_size, locals_stack_size);
5600 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5602 if (offsets [i] != -1) {
5603 MonoInst *inst = cfg->varinfo [i];
5604 inst->opcode = OP_REGOFFSET;
5605 inst->inst_basereg = cfg->frame_reg;
5606 //if (cfg->arch.omit_fp)
5607 // inst->inst_offset = (offset + offsets [i]);
5609 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5611 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5612 CFG_DEBUG(3) mono_print_tree_nl (inst);
5616 // TODO check how offsets[i] are calculated
5617 // it seems they are points to the end on data. Like 8, but it actually - 0
5619 offset += locals_stack_size; //+8;
5621 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5622 // g_assert (!cfg->arch.omit_fp);
5623 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5624 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5627 // Save offset for caller saved regs
5628 cfg->arch.reg_save_area_offset = offset;
5630 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5632 // Reserve space for caller saved registers
5633 for (i = 0; i < MONO_MAX_IREGS; ++i)
5634 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5635 (cfg->used_int_regs & (1 << i)))
5637 offset += sizeof (gpointer);
5640 // Save offset to args regs
5641 cfg->arch.args_save_area_offset = offset;
5643 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5645 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5647 ArgInfo *ainfo = &cinfo->args [i];
5649 switch(ainfo->storage)
5653 case ArgInDoubleReg:
5654 offset += sizeof (gpointer);
5657 offset += ainfo->nregs * sizeof (gpointer);
5664 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5667 // Reserve space for method params
5668 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5670 inst = cfg->args [i];
5672 if (inst->opcode != OP_REGVAR)
5674 ArgInfo *ainfo = &cinfo->args [i];
5675 gboolean inreg = TRUE;
5678 if (sig->hasthis && (i == 0))
5679 arg_type = &mono_defaults.object_class->byval_arg;
5681 arg_type = sig->params [i - sig->hasthis];
5683 /* FIXME: Allocate volatile arguments to registers */
5684 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5688 * Under AMD64, all registers used to pass arguments to functions
5689 * are volatile across calls. For Alpha too.
5690 * FIXME: Optimize this.
5694 if (inreg && (ainfo->storage == ArgInIReg)
5695 //&& cfg->used_int_regs & (1 << ainfo->reg)
5699 if (//(ainfo->storage == ArgInIReg) ||
5700 (ainfo->storage == ArgInFloatReg) ||
5701 (ainfo->storage == ArgInDoubleReg) ||
5702 (ainfo->storage == ArgValuetypeInReg))
5705 inst->opcode = OP_REGOFFSET;
5707 switch (ainfo->storage)
5711 case ArgInDoubleReg:
5712 inst->opcode = OP_REGVAR;
5713 inst->dreg = ainfo->reg;
5716 // g_assert (!cfg->arch.omit_fp);
5717 inst->opcode = OP_REGOFFSET;
5718 inst->inst_basereg = cfg->frame_reg;
5720 // "offset" here will point to the end of
5721 // array of saved ret,locals, args
5722 // Ideally it would point to "a7"
5723 inst->inst_offset = ainfo->offset + offset;
5725 case ArgValuetypeInReg:
5735 if (!inreg && (ainfo->storage != ArgOnStack))
5737 inst->opcode = OP_REGOFFSET;
5738 inst->inst_basereg = cfg->frame_reg;
5740 /* These arguments are saved to the stack in the prolog */
5741 /*if (cfg->arch.omit_fp) {
5742 inst->inst_offset = offset;
5743 offset += (ainfo->storage == ArgValuetypeInReg) ?
5744 2 * sizeof (gpointer) : sizeof (gpointer);
5747 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5748 // 2 * sizeof (gpointer) : sizeof (gpointer);
5750 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5751 switch(ainfo->storage)
5754 a_off += ainfo->nslots * 8;
5757 a_off += sizeof (gpointer);
5759 // (/*(ainfo->reg - 16)*/ i * 8);
5765 cfg->stack_offset = offset;
5770 /*========================= End of Function ========================*/
5772 /*------------------------------------------------------------------*/
5774 /* Name - mono_arch_print_tree */
5776 /* Function - Print platform-specific opcode details. */
5778 /* Returns - 1 - opcode details have been printed */
5779 /* 0 - opcode details have not been printed */
5781 /*------------------------------------------------------------------*/
5784 mono_arch_print_tree (MonoInst *tree, int arity)
5788 ALPHA_DEBUG("mono_arch_print_tree");
5790 switch (tree->opcode) {
5797 /*========================= End of Function ========================*/
5801 ** mono_arch_get_vcall_slot_addr
5802 ** is called by mono_magic_trampoline to determine that the JIT compiled
5803 ** method is called via vtable slot. We need to analyze call sequence
5804 ** and determine that. In case it is true - we need to return address
5807 ** code - points to the next instruction after call
5808 ** reg - points to saved regs before the call (this is done
5809 ** by mono_magic_trampoline function
5813 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
5815 unsigned int *pc = (unsigned int *)code;
5817 int start_index = -2;
5819 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5822 // Check if we have parameters on stack
5823 if ((pc[-2] & 0xFFFF0000) == 0x23DE0000) // lda sp,-n(sp)
5826 // Check for (call_membase):
5827 // -4: mov v0,a0 - load this ???
5828 // -3: ldq v0,0(v0) - load vtable
5829 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5830 if ((pc[start_index-1] & 0xFC00FFFF) == 0xA4000000 &&
5831 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5834 disp = pc[start_index] & 0xFFFF;
5835 reg = (pc[start_index-1] >> AXP_REG1_SHIFT) & AXP_REG_MASK;
5836 //reg = 0; // For now
5838 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5840 return (gpointer)(((guint64)(regs [reg])) + disp);
5843 // Check for interface call
5846 // -3: ldq v0,-n(v0)
5847 // -2: ldq t12,0(v0)
5848 if ((pc[start_index-2] & 0xFC00FFFF) == 0xA4000000 &&
5849 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5850 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5853 disp = pc[start_index] & 0xFFFF;;
5856 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5858 return (gpointer)(((guint64)(regs [reg])) + disp);
5866 mono_arch_get_patch_offset (guint8 *code)