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 /*------------------------------------------------------------------*/
22 #define NOT_IMPLEMENTED(x) \
23 g_error ("FIXME: %s is not yet implemented.", x);
25 #define ALPHA_DEBUG(x) \
26 if (mini_alpha_verbose_level) \
27 g_debug ("ALPHA_DEBUG: %s is called.", x);
29 #define ALPHA_PRINT if (mini_alpha_verbose_level)
31 #define NEW_INS(cfg,dest,op) do { \
32 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
33 (dest)->opcode = (op); \
34 insert_after_ins (bb, last_ins, (dest)); \
37 #define NEW_ICONST(cfg,dest,val) do { \
38 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
39 (dest)->opcode = OP_ICONST; \
40 (dest)->inst_c0 = (val); \
41 (dest)->type = STACK_I4; \
46 #define DEBUG(a) if (cfg->verbose_level > 1) a
48 #define CFG_DEBUG(LVL) if (cfg->verbose_level > LVL)
50 //#define ALPHA_IS_CALLEE_SAVED_REG(reg) (MONO_ARCH_CALLEE_SAVED_REGS & (1 << (reg)))
51 #define ALPHA_ARGS_REGS ((regmask_t)0x03F0000)
52 #define ARGS_OFFSET 16
54 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
55 #define alpha_is_imm(X) ((X >= 0 && X <= 255))
56 #define ALPHA_LOAD_GP(IP) { AlphaGotData ge_data; add_got_entry(cfg, GT_LD_GTADDR, ge_data, IP, MONO_PATCH_INFO_NONE, 0); }
58 /*========================= End of Defines =========================*/
60 /*------------------------------------------------------------------*/
62 /*------------------------------------------------------------------*/
67 #include <mono/metadata/appdomain.h>
68 #include <mono/metadata/debug-helpers.h>
69 #include <mono/metadata/profiler-private.h>
70 #include <mono/utils/mono-math.h>
73 #include "mini-alpha.h"
75 #include "cpu-alpha.h"
77 /*========================= End of Includes ========================*/
79 /*------------------------------------------------------------------*/
80 /* G l o b a l V a r i a b l e s */
81 /*------------------------------------------------------------------*/
82 static int indent_level = 0;
84 int mini_alpha_verbose_level = 0;
85 static int bwx_supported = 0;
87 static gboolean tls_offset_inited = FALSE;
89 static int appdomain_tls_offset = -1,
91 thread_tls_offset = -1;
93 pthread_key_t lmf_addr_key;
95 gboolean lmf_addr_key_inited = FALSE;
97 /*====================== End of Global Variables ===================*/
99 static void mono_arch_break(void);
100 gpointer mono_arch_get_lmf_addr (void);
107 ArgValuetypeInReg, // ??
118 /* Only if storage == ArgAggregate */
120 //AggregateType atype; // So far use only AggregateNormal
126 // guint32 struct_ret; /// ???
130 gboolean need_stack_align;
137 static CallInfo* get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke);
138 static unsigned int *emit_call(MonoCompile *cfg, unsigned int *code,
139 guint32 patch_type, gconstpointer data);
142 static int param_regs [] =
149 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
152 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
154 ainfo->offset = *stack_size;
156 if (*gr >= PARAM_REGS)
158 ainfo->storage = ArgOnStack;
159 (*stack_size) += sizeof (gpointer);
163 ainfo->storage = ArgInIReg;
164 ainfo->reg = param_regs [*gr];
169 #define FLOAT_PARAM_REGS 6
170 static int fparam_regs [] = { alpha_fa0, alpha_fa1, alpha_fa2, alpha_fa3,
171 alpha_fa4, alpha_fa5 };
174 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo,
177 ainfo->offset = *stack_size;
179 if (*gr >= FLOAT_PARAM_REGS)
181 ainfo->storage = ArgOnStack;
182 (*stack_size) += sizeof (gpointer);
186 /* A double register */
188 ainfo->storage = ArgInDoubleReg;
190 ainfo->storage = ArgInFloatReg;
192 ainfo->reg = fparam_regs [*gr];
198 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
200 guint32 *gr, guint32 *fr, guint32 *stack_size)
204 MonoMarshalType *info;
205 gboolean is_hfa = TRUE;
206 guint32 hfa_type = 0;
208 klass = mono_class_from_mono_type (type);
209 if (type->type == MONO_TYPE_TYPEDBYREF)
210 size = 3 * sizeof (gpointer);
211 else if (sig->pinvoke)
212 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
214 size = mono_type_stack_size (&klass->byval_arg, NULL);
216 if (!sig->pinvoke || (size == 0) || is_return) {
217 /* Allways pass in memory */
218 ainfo->offset = *stack_size;
219 *stack_size += ALIGN_TO (size, 8);
220 ainfo->storage = ArgOnStack;
225 info = mono_marshal_load_type_info (klass);
228 ainfo->storage = ArgAggregate;
229 //ainfo->atype = AggregateNormal;
232 /* This also handles returning of TypedByRef used by some icalls */
235 ainfo->reg = IA64_R8;
236 ainfo->nregs = (size + 7) / 8;
237 ainfo->nslots = ainfo->nregs;
244 ainfo->reg = param_regs [*gr];
245 ainfo->offset = *stack_size;
246 ainfo->nslots = (size + 7) / 8;
248 if (((*gr) + ainfo->nslots) <= 6) {
249 /* Fits entirely in registers */
250 ainfo->nregs = ainfo->nslots;
251 (*gr) += ainfo->nregs;
255 ainfo->nregs = 6 - (*gr);
257 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
261 // This function is called from mono_arch_call_opcode and
262 // should determine which registers will be used to do the call
263 // For Alpha we could calculate number of parameter used for each
264 // call and allocate space in stack only for whose "a0-a5" registers
265 // that will be used in calls
267 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
268 ArgStorage storage, int reg, MonoInst *tree)
273 arg->opcode = OP_OUTARG_REG;
274 arg->inst_left = tree;
275 arg->inst_right = (MonoInst*)call;
276 arg->backend.reg3 = reg;
277 call->used_iregs |= 1 << reg;
280 arg->opcode = OP_OUTARG_FREG;
281 arg->inst_left = tree;
282 arg->inst_right = (MonoInst*)call;
283 arg->backend.reg3 = reg;
284 call->used_fregs |= 1 << reg;
287 arg->opcode = OP_OUTARG_FREG;
288 arg->inst_left = tree;
289 arg->inst_right = (MonoInst*)call;
290 arg->backend.reg3 = reg;
291 call->used_fregs |= 1 << reg;
294 g_assert_not_reached ();
299 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
304 bb->code = to_insert;
305 to_insert->next = ins;
309 to_insert->next = ins->next;
310 ins->next = to_insert;
314 static void add_got_entry(MonoCompile *cfg, AlphaGotType ge_type,
315 AlphaGotData ge_data,
316 int ip, MonoJumpInfoType type, gconstpointer target)
318 AlphaGotEntry *AGE = mono_mempool_alloc (cfg->mempool,
319 sizeof (AlphaGotEntry));
326 AGE->value.data.i = ge_data.data.i;
329 AGE->value.data.l = ge_data.data.l;
332 AGE->value.data.p = ge_data.data.p;
335 AGE->value.data.f = ge_data.data.f;
338 AGE->value.data.d = ge_data.data.d;
341 AGE->value.data.l = ip;
347 if (type != MONO_PATCH_INFO_NONE)
349 mono_add_patch_info(cfg, ip, type, target);
350 AGE->patch_info = cfg->patch_info;
355 if (AGE->type != GT_LD_GTADDR)
357 mono_add_patch_info(cfg, ip, MONO_PATCH_INFO_GOT_OFFSET, 0);
358 AGE->got_patch_info = cfg->patch_info;
361 AGE->next = cfg->arch.got_data;
363 cfg->arch.got_data = AGE;
366 /*------------------------------------------------------------------*/
368 /* Name - mono_arch_create_vars */
375 * cfg - pointer to compile unit
378 * This method is called right before starting converting compiled
379 * method to IR. I guess we could find out how many arguments we
380 * should expect, what type and what return value would be.
381 * After that we could correct "cfg" structure, or "arch" part of
385 /*------------------------------------------------------------------*/
388 mono_arch_create_vars (MonoCompile *cfg)
390 MonoMethodSignature *sig;
393 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
395 sig = mono_method_signature (cfg->method);
397 cinfo = get_call_info (sig, FALSE);
399 if (cinfo->ret.storage == ArgValuetypeInReg)
400 cfg->ret_var_is_local = TRUE;
406 /*------------------------------------------------------------------*/
408 /* Name - mono_arch_get_lmf_addr */
414 /*------------------------------------------------------------------*/
417 mono_arch_get_lmf_addr (void)
419 ALPHA_DEBUG("mono_arch_get_lmf_addr");
421 return pthread_getspecific (lmf_addr_key);
424 /*========================= End of Function ========================*/
426 /*------------------------------------------------------------------*/
428 /* Name - mono_arch_free_jit_tls_data */
430 /* Function - Free tls data. */
432 /*------------------------------------------------------------------*/
435 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
437 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
440 /*========================= End of Function ========================*/
443 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
445 MonoInst *ins, *last_ins = NULL;
448 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE pass\n");
460 * OP_MOVE reg, reg except special case (mov at, at)
462 if (ins->dreg == ins->sreg1 &&
463 ins->dreg != alpha_at)
466 last_ins->next = ins->next;
478 if (last_ins && last_ins->opcode == OP_MOVE &&
479 ins->sreg1 == last_ins->dreg &&
480 last_ins->dreg != alpha_at &&
481 ins->dreg == last_ins->sreg1)
483 last_ins->next = ins->next;
492 /* remove unnecessary multiplication with 1 */
493 if (ins->inst_imm == 1)
495 if (ins->dreg != ins->sreg1)
497 ins->opcode = OP_MOVE;
501 last_ins->next = ins->next;
509 case OP_LOADI8_MEMBASE:
510 case OP_LOAD_MEMBASE:
512 * Note: if reg1 = reg2 the load op is removed
514 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
515 * OP_LOADI8_MEMBASE offset(basereg), reg2
517 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
521 (last_ins->opcode == OP_STOREI8_MEMBASE_REG ||
522 last_ins->opcode == OP_STORE_MEMBASE_REG) &&
523 ins->inst_basereg == last_ins->inst_destbasereg &&
524 ins->inst_offset == last_ins->inst_offset)
526 if (ins->dreg == last_ins->sreg1)
528 last_ins->next = ins->next;
535 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
536 ins->opcode = OP_MOVE;
537 ins->sreg1 = last_ins->sreg1;
543 case OP_LOAD_MEMBASE:
544 case OP_LOADI4_MEMBASE:
546 * Note: if reg1 = reg2 the load op is removed
548 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
549 * OP_LOAD_MEMBASE offset(basereg), reg2
551 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
554 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
555 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
556 ins->inst_basereg == last_ins->inst_destbasereg &&
557 ins->inst_offset == last_ins->inst_offset)
559 if (ins->dreg == last_ins->sreg1)
561 last_ins->next = ins->next;
568 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
569 ins->opcode = OP_MOVE;
570 ins->sreg1 = last_ins->sreg1;
574 * Note: reg1 must be different from the basereg in the second load
575 * Note: if reg1 = reg2 is equal then second load is removed
577 * OP_LOAD_MEMBASE offset(basereg), reg1
578 * OP_LOAD_MEMBASE offset(basereg), reg2
580 * OP_LOAD_MEMBASE offset(basereg), reg1
584 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
585 || last_ins->opcode == OP_LOAD_MEMBASE) &&
586 ins->inst_basereg != last_ins->dreg &&
587 ins->inst_basereg == last_ins->inst_basereg &&
588 ins->inst_offset == last_ins->inst_offset)
590 if (ins->dreg == last_ins->dreg)
592 last_ins->next = ins->next;
599 ins->opcode = OP_MOVE;
600 ins->sreg1 = last_ins->dreg;
603 //g_assert_not_reached ();
613 bb->last_ins = last_ins;
618 // Convert to opposite branch opcode
619 static guint16 cvt_branch_opcode(guint16 opcode)
624 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
629 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
633 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
637 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
641 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
645 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
649 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
653 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
657 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
661 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
665 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
669 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
673 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
677 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
681 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
685 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
689 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
693 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
697 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
701 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
705 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
709 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
713 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
717 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
721 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
728 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
733 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
735 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
741 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
752 return OP_ALPHA_CMP_EQ;
754 return OP_ALPHA_CMP_ULE;
756 return OP_ALPHA_CMP_LE;
758 return OP_ALPHA_CMP_LT;
760 return OP_ALPHA_CMP_ULT;
765 case OP_ICOMPARE_IMM:
771 return OP_ALPHA_CMP_IMM_EQ;
773 return OP_ALPHA_CMP_IMM_ULE;
775 return OP_ALPHA_CMP_IMM_LE;
777 return OP_ALPHA_CMP_IMM_LT;
779 return OP_ALPHA_CMP_IMM_ULT;
784 g_assert_not_reached();
789 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
791 // Instead of compare+b<cond>,
792 // Alpha has compare<cond>+br<cond>
793 // we need to convert
794 // Handle floating compare here too
800 // Convert cmp + beq -> cmpeq + bne
801 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
802 next->opcode = cvt_branch_opcode(next->opcode);
807 // cmp + ibne_un -> cmpeq + beq
808 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
809 next->opcode = cvt_branch_opcode(next->opcode);
814 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
815 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
816 next->opcode = cvt_branch_opcode(next->opcode);
821 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
822 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
823 next->opcode = cvt_branch_opcode(next->opcode);
828 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
829 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
830 next->opcode = cvt_branch_opcode(next->opcode);
835 // lcmp + blt.un -> cmpult + bne
836 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
837 next->opcode = cvt_branch_opcode(next->opcode);
842 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
843 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
844 next->opcode = cvt_branch_opcode(next->opcode);
849 //lcmp + bge.un -> cmpult + beq
850 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
851 next->opcode = cvt_branch_opcode(next->opcode);
856 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
857 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
858 next->opcode = cvt_branch_opcode(next->opcode);
863 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
864 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
865 next->opcode = cvt_branch_opcode(next->opcode);
871 // cmp + cgt_un -> cmpule + beq
872 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
877 // cmp + iceq -> cmpeq + bne
878 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
883 // cmp + int_cgt -> cmple + beq
884 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
889 // cmp + int_clt -> cmplt + bne
890 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
895 // cmp + int_clt_un -> cmpult + bne
896 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
900 // The conditional exceptions will be handled in
901 // output_basic_blocks. Here we just determine correct
904 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
907 case OP_COND_EXC_GT_UN:
908 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
912 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
915 case OP_COND_EXC_LT_UN:
916 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
919 case OP_COND_EXC_LE_UN:
920 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
923 case OP_COND_EXC_NE_UN:
924 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
928 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
933 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
934 mono_inst_name(next->opcode), next->opcode);
936 // g_assert_not_reached();
944 * mono_arch_lowering_pass:
946 * Converts complex opcodes into simpler ones so that each IR instruction
947 * corresponds to one machine instruction.
950 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
952 MonoInst *ins, *temp, *last_ins = NULL;
957 if (bb->max_ireg > cfg->rs->next_vireg)
958 cfg->rs->next_vireg = bb->max_ireg;
959 if (bb->max_freg > cfg->rs->next_vfreg)
960 cfg->rs->next_vfreg = bb->max_freg;
963 * FIXME: Need to add more instructions, but the current machine
964 * description can't model some parts of the composite instructions like
977 NEW_INS (cfg, temp, OP_I8CONST);
978 temp->inst_c0 = ins->inst_imm;
979 temp->dreg = mono_regstate_next_int (cfg->rs);
984 ins->opcode = CEE_MUL;
987 ins->opcode = OP_LDIV;
990 ins->opcode = OP_LREM;
993 ins->opcode = OP_IDIV;
996 ins->opcode = OP_IREM;
1000 ins->sreg2 = temp->dreg;
1008 // Instead of compare+b<cond>/fcompare+b<cond>,
1009 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
1010 // we need to convert
1013 cvt_cmp_branch(ins, next);
1017 case OP_COMPARE_IMM:
1018 if (!alpha_is_imm (ins->inst_imm))
1020 NEW_INS (cfg, temp, OP_I8CONST);
1021 temp->inst_c0 = ins->inst_imm;
1022 temp->dreg = mono_regstate_next_int (cfg->rs);
1023 ins->opcode = OP_COMPARE;
1024 ins->sreg2 = temp->dreg;
1026 // We should try to reevaluate new IR opcode
1032 cvt_cmp_branch(ins, next);
1036 case OP_ICOMPARE_IMM:
1037 if (!alpha_is_imm (ins->inst_imm))
1039 NEW_INS (cfg, temp, OP_ICONST);
1040 temp->inst_c0 = ins->inst_imm;
1041 temp->dreg = mono_regstate_next_int (cfg->rs);
1042 ins->opcode = OP_ICOMPARE;
1043 ins->sreg2 = temp->dreg;
1045 // We should try to reevaluate new IR opcode
1051 cvt_cmp_branch(ins, next);
1055 case OP_STORE_MEMBASE_IMM:
1056 case OP_STOREI8_MEMBASE_IMM:
1057 if (ins->inst_imm != 0)
1059 NEW_INS (cfg, temp, OP_I8CONST);
1060 temp->inst_c0 = ins->inst_imm;
1061 temp->dreg = mono_regstate_next_int (cfg->rs);
1062 ins->opcode = OP_STOREI8_MEMBASE_REG;
1063 ins->sreg1 = temp->dreg;
1067 case OP_STOREI4_MEMBASE_IMM:
1068 if (ins->inst_imm != 0)
1071 NEW_INS (cfg, temp, OP_ICONST);
1072 temp->inst_c0 = ins->inst_imm;
1073 temp->dreg = mono_regstate_next_int (cfg->rs);
1074 ins->opcode = OP_STOREI4_MEMBASE_REG;
1075 ins->sreg1 = temp->dreg;
1079 case OP_STOREI1_MEMBASE_IMM:
1080 if (ins->inst_imm != 0 || !bwx_supported)
1083 NEW_INS (cfg, temp, OP_ICONST);
1084 temp->inst_c0 = ins->inst_imm;
1085 temp->dreg = mono_regstate_next_int (cfg->rs);
1086 ins->opcode = OP_STOREI1_MEMBASE_REG;
1087 ins->sreg1 = temp->dreg;
1091 case OP_STOREI2_MEMBASE_IMM:
1092 if (ins->inst_imm != 0 || !bwx_supported)
1095 NEW_INS (cfg, temp, OP_ICONST);
1096 temp->inst_c0 = ins->inst_imm;
1097 temp->dreg = mono_regstate_next_int (cfg->rs);
1098 ins->opcode = OP_STOREI2_MEMBASE_REG;
1099 ins->sreg1 = temp->dreg;
1110 case OP_ISHR_UN_IMM:
1111 if (!alpha_is_imm(ins->inst_imm))
1114 NEW_INS (cfg, temp, OP_ICONST);
1115 temp->inst_c0 = ins->inst_imm;
1116 temp->dreg = mono_regstate_next_int (cfg->rs);
1121 ins->opcode = OP_IADD;
1124 ins->opcode = OP_ISUB;
1127 ins->opcode = OP_IAND;
1130 ins->opcode = OP_IOR;
1133 ins->opcode = OP_IXOR;
1136 ins->opcode = OP_ISHL;
1139 ins->opcode = OP_ISHR;
1141 case OP_ISHR_UN_IMM:
1142 ins->opcode = OP_ISHR_UN;
1148 ins->sreg2 = temp->dreg;
1154 if (!alpha_is_imm(ins->inst_imm))
1157 NEW_INS (cfg, temp, OP_ICONST);
1158 temp->inst_c0 = ins->inst_imm;
1159 temp->dreg = mono_regstate_next_int (cfg->rs);
1164 ins->opcode = CEE_ADD;
1167 ins->opcode = CEE_SUB;
1170 ins->opcode = CEE_AND;
1173 ins->opcode = CEE_SHL;
1179 ins->sreg2 = temp->dreg;
1183 if (!alpha_is_imm(ins->inst_imm))
1186 NEW_INS(cfg, temp, OP_ICONST);
1187 temp->inst_c0 = ins->inst_imm;
1188 temp->dreg = mono_regstate_next_int(cfg->rs);
1189 ins->sreg2 = temp->dreg;
1190 ins->opcode = OP_LSHR;
1194 if (!alpha_is_imm(ins->inst_imm))
1197 NEW_INS(cfg, temp, OP_ICONST);
1198 temp->inst_c0 = ins->inst_imm;
1199 temp->dreg = mono_regstate_next_int(cfg->rs);
1200 ins->sreg2 = temp->dreg;
1201 ins->opcode = OP_LSHL;
1213 bb->last_ins = last_ins;
1215 bb->max_ireg = cfg->rs->next_vireg;
1216 bb->max_freg = cfg->rs->next_vfreg;
1219 /*------------------------------------------------------------------*/
1221 /* Name - mono_arch_local_regalloc. */
1223 /* Function - We first scan the list of instructions and we */
1224 /* save the liveness information of each register */
1225 /* (when the register is first used, when its value */
1226 /* is set etc.). We also reverse the list of instr- */
1227 /* uctions (in the InstList list) because assigning */
1228 /* registers backwards allows for more tricks to be */
1231 /*------------------------------------------------------------------*/
1234 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1236 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_local_regalloc");
1241 mono_arch_lowering_pass (cfg, bb);
1243 mono_local_regalloc(cfg, bb);
1246 /*========================= End of Function ========================*/
1248 #define AXP_GENERAL_REGS 6
1249 #define AXP_MIN_STACK_SIZE 24
1251 /* A typical Alpha stack frame looks like this */
1253 fun: // called from outside the module.
1254 ldgp gp,0(pv) // load the global pointer
1255 fun..ng: // called from inside the module.
1256 lda sp, -SIZE( sp ) // grow the stack downwards.
1258 stq ra, 0(sp) // save the return address.
1260 stq s0, 8(sp) // callee-saved registers.
1261 stq s1, 16(sp) // ...
1263 // Move the arguments to the argument registers...
1265 mov addr, pv // Load the callee address
1266 jsr ra, (pv) // call the method.
1267 ldgp gp, 0(ra) // restore gp
1269 // return value is in v0
1271 ldq ra, 0(sp) // free stack frame
1272 ldq s0, 8(sp) // restore callee-saved registers.
1274 ldq sp, 32(sp) // restore stack pointer
1276 ret zero, (ra), 1 // return.
1279 // our call must look like this.
1285 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1286 stq ra, SIZE-48(sp) // store ra
1287 stq fp, SIZE-40(sp) // store fp (frame pointer)
1288 stq a0, SIZE-32(sp) // store args. a0 = func
1289 stq a1, SIZE-24(sp) // a1 = retval
1290 stq a2, SIZE-16(sp) // a2 = this
1291 stq a3, SIZE-8(sp) // a3 = args
1292 mov sp, fp // set frame pointer
1312 jsr ra, (pv) // call func
1313 ldgp gp, 0(ra) // restore gp.
1314 mov v0, t1 // move return value into t1
1317 ldq t0, SIZE-24(fp) // load retval into t2
1318 stl t1, 0(t0) // store value.
1329 * emit_load_volatile_arguments:
1331 * Load volatile arguments from the stack to the original input registers.
1332 * Required before a tail call.
1334 static unsigned int*
1335 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1337 MonoMethod *method = cfg->method;
1338 MonoMethodSignature *sig;
1343 /* FIXME: Generate intermediate code instead */
1345 sig = mono_method_signature (method);
1347 cinfo = get_call_info (sig, FALSE);
1349 if (sig->ret->type != MONO_TYPE_VOID) {
1350 if ((cinfo->ret.storage == ArgInIReg) &&
1351 (cfg->ret->opcode != OP_REGVAR))
1353 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1354 cfg->ret->inst_offset);
1358 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1360 ArgInfo *ainfo = &cinfo->args [i];
1361 MonoInst *inst = cfg->varinfo [i];
1363 switch(ainfo->storage)
1366 // We need to save all used a0-a5 params
1367 //for (i=0; i<PARAM_REGS; i++)
1369 // if (i < cinfo->reg_usage)
1371 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1372 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1374 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1375 ainfo->reg, inst->inst_offset/*offset*/);
1379 case ArgInDoubleReg:
1381 // We need to save all used af0-af5 params
1382 //for (i=0; i<PARAM_REGS; i++)
1384 // if (i < cinfo->freg_usage)
1386 switch(cinfo->args[i].storage)
1389 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1390 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1392 case ArgInDoubleReg:
1393 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1394 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1400 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1401 ainfo->reg, /*offset*/inst->inst_offset);
1410 /*------------------------------------------------------------------*/
1412 /* Name - mono_arch_emit_prolog */
1414 /* Function - Create the instruction sequence for a function */
1417 * How to handle consts and method addreses:
1418 * For method we will allocate array of qword after method epiloge.
1419 * These qword will hold readonly info to method to properly to run.
1420 * For example: qword constants, method addreses
1421 * GP will point to start of data. Offsets to the data will be equal
1422 * to "address" of data - start of GP. (GP = 0 during method jiting).
1423 * GP is easily calculated from passed PV (method start address).
1424 * The patch will update GP loadings.
1425 * The GOT section should be more than 32Kb.
1426 * The patch code should put proper offset since the real position of
1427 * qword array will be known after the function epiloge.
1429 /*------------------------------------------------------------------*/
1432 mono_arch_emit_prolog (MonoCompile *cfg)
1434 MonoMethod *method = cfg->method;
1435 MonoMethodSignature *sig = mono_method_signature (method);
1436 //int alloc_size, code_size, max_offset, quad;
1439 int i, stack_size, offset;
1440 gint32 lmf_offset = cfg->arch.lmf_offset;
1442 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1444 // FIXME: Use just one field to hold calculated stack size
1445 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1446 cfg->arch.got_data = 0;
1448 cfg->code_size = 512;
1450 code = (unsigned int *)g_malloc(cfg->code_size);
1451 cfg->native_code = (void *)code;
1453 // Emit method prolog
1454 // Calculate GP from passed PV, allocate stack
1456 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1457 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1458 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1460 offset = cfg->arch.params_stack_size;
1462 /* store call convention parameters on stack */
1463 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1464 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1466 /* set the frame pointer */
1467 alpha_mov1( code, alpha_sp, alpha_fp );
1470 if (method->save_lmf)
1473 alpha_stq(code, alpha_pv, alpha_fp,
1474 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1476 alpha_stq(code, alpha_sp, alpha_fp,
1477 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1479 alpha_stq(code, alpha_fp, alpha_fp,
1480 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1482 alpha_stq(code, alpha_gp, alpha_fp,
1483 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1486 alpha_stq(code, alpha_pv, alpha_fp,
1487 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1490 /* Save (global) regs */
1491 offset = cfg->arch.reg_save_area_offset;
1493 for (i = 0; i < MONO_MAX_IREGS; ++i)
1494 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1495 (cfg->used_int_regs & (1 << i)) &&
1496 !( ALPHA_ARGS_REGS & (1 << i)) )
1498 alpha_stq(code, i, alpha_fp, offset);
1499 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1504 offset = cfg->arch.args_save_area_offset;
1506 cinfo = get_call_info (sig, FALSE);
1508 if (sig->ret->type != MONO_TYPE_VOID)
1510 if ((cinfo->ret.storage == ArgInIReg) &&
1511 (cfg->ret->opcode != OP_REGVAR))
1513 /* Save volatile arguments to the stack */
1514 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1515 cfg->ret->inst_offset);
1519 /* Keep this in sync with emit_load_volatile_arguments */
1520 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1522 ArgInfo *ainfo = &cinfo->args [i];
1523 MonoInst *inst = cfg->varinfo [i];
1526 switch(ainfo->storage)
1529 // We need to save all used a0-a5 params
1531 if (inst->opcode == OP_REGVAR)
1533 alpha_mov1(code, ainfo->reg, inst->dreg);
1534 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1535 ainfo->reg, inst->dreg);
1539 alpha_stq(code, ainfo->reg, inst->inst_basereg,
1542 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1543 ainfo->reg, inst->inst_offset);
1551 for(j=0; j<ainfo->nregs; j++)
1553 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1554 ainfo->reg + j, inst->inst_offset + (8*j));
1555 alpha_stq(code, (ainfo->reg+j), inst->inst_basereg,
1556 (inst->inst_offset + (8*j)));
1561 case ArgInDoubleReg:
1563 // We need to save all used af0-af5 params
1565 switch(cinfo->args[i].storage)
1568 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1569 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1571 case ArgInDoubleReg:
1572 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1573 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1579 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1580 ainfo->reg, /*offset*/inst->inst_offset);
1587 offset = cfg->arch.reg_save_area_offset;
1590 for (i = 0; i < MONO_MAX_IREGS; ++i)
1591 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1592 (cfg->used_int_regs & (1 << i)) &&
1593 !( ALPHA_ARGS_REGS & (1 << i)) )
1595 alpha_stq(code, i, alpha_fp, offset);
1596 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1601 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1603 if (method->save_lmf)
1606 * The call might clobber argument registers, but they are already
1607 * saved to the stack/global regs.
1610 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1611 (gpointer)"mono_get_lmf_addr");
1614 alpha_stq(code, alpha_r0, alpha_fp,
1615 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1616 // Load "previous_lmf" member of MonoLMF struct
1617 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1619 // Save it to MonoLMF struct
1620 alpha_stq(code, alpha_r1, alpha_fp,
1621 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1624 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1625 alpha_stq(code, alpha_r1, alpha_r0, 0);
1630 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1631 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1634 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1636 g_assert (cfg->code_len < cfg->code_size);
1638 return (gint8 *)code;
1641 /*========================= End of Function ========================*/
1643 /*------------------------------------------------------------------*/
1645 /* Name - mono_arch_flush_register_windows */
1651 /*------------------------------------------------------------------*/
1654 mono_arch_flush_register_windows (void)
1656 ALPHA_DEBUG("mono_arch_flush_register_windows");
1658 /*========================= End of Function ========================*/
1660 /*------------------------------------------------------------------*/
1662 /* Name - mono_arch_regalloc_cost */
1664 /* Function - Determine the cost, in the number of memory */
1665 /* references, of the action of allocating the var- */
1666 /* iable VMV into a register during global register */
1669 /* Returns - Cost */
1671 /*------------------------------------------------------------------*/
1674 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1676 MonoInst *ins = cfg->varinfo [vmv->idx];
1679 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1681 if (cfg->method->save_lmf)
1682 /* The register is already saved */
1683 /* substract 1 for the invisible store in the prolog */
1684 return (ins->opcode == OP_ARG) ? 1 : 0;
1687 return (ins->opcode == OP_ARG) ? 2 : 1;
1690 /*========================= End of Function ========================*/
1694 ** This method emits call sequience
1697 static unsigned int *
1698 emit_call(MonoCompile *cfg, unsigned int *code,
1699 guint32 patch_type, gconstpointer data)
1702 AlphaGotData ge_data;
1704 offset = (char *)code - (char *)cfg->native_code;
1706 ge_data.data.p = (void *)data;
1707 add_got_entry(cfg, GT_PTR, ge_data,
1708 offset, patch_type, data);
1710 // Load call address into PV
1711 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1714 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1716 offset = (char *)code - (char *)cfg->native_code;
1719 ALPHA_LOAD_GP(offset)
1720 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1721 alpha_lda(code, alpha_gp, alpha_gp, 0);
1726 /*------------------------------------------------------------------*/
1728 /* Name - arch_get_argument_info */
1730 /* Function - Gathers information on parameters such as size, */
1731 /* alignment, and padding. arg_info should be large */
1732 /* enough to hold param_count + 1 entries. */
1734 /* Parameters - @csig - Method signature */
1735 /* @param_count - No. of parameters to consider */
1736 /* @arg_info - An array to store the result info */
1738 /* Returns - Size of the activation frame */
1740 /*------------------------------------------------------------------*/
1743 mono_arch_get_argument_info (MonoMethodSignature *csig,
1745 MonoJitArgumentInfo *arg_info)
1748 CallInfo *cinfo = get_call_info (csig, FALSE);
1749 guint32 args_size = cinfo->stack_usage;
1751 ALPHA_DEBUG("mono_arch_get_argument_info");
1753 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1756 arg_info [0].offset = 0;
1759 for (k = 0; k < param_count; k++)
1761 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1765 // The size is checked only for valuetype in trace.c
1766 arg_info [k + 1].size = 8;
1774 /*------------------------------------------------------------------*/
1776 /* Name - mono_arch_emit_epilog */
1778 /* Function - Emit the instructions for a function epilog. */
1780 /*------------------------------------------------------------------*/
1783 mono_arch_emit_epilog (MonoCompile *cfg)
1785 MonoMethod *method = cfg->method;
1788 int max_epilog_size = 128;
1789 int stack_size = cfg->arch.stack_size;
1791 gint32 lmf_offset = cfg->arch.lmf_offset;
1793 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1795 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1797 cfg->code_size *= 2;
1798 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1799 mono_jit_stats.code_reallocs++;
1802 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1804 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1805 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1808 if (method->save_lmf)
1810 /* Restore previous lmf */
1811 alpha_ldq(code, alpha_at, alpha_fp,
1812 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1813 alpha_ldq(code, alpha_ra, alpha_fp,
1814 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1815 alpha_stq(code, alpha_at, alpha_ra, 0);
1819 alpha_mov1( code, alpha_fp, alpha_sp );
1821 // Restore saved regs
1822 offset = cfg->arch.reg_save_area_offset;
1824 for (i = 0; i < MONO_MAX_IREGS; ++i)
1825 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1826 (cfg->used_int_regs & (1 << i)) &&
1827 !( ALPHA_ARGS_REGS & (1 << i)) )
1829 alpha_ldq(code, i, alpha_sp, offset);
1830 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1835 /* restore fp, ra, sp */
1836 offset = cfg->arch.params_stack_size;
1838 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1839 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1840 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1843 alpha_ret( code, alpha_ra, 1 );
1845 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1847 g_assert (cfg->code_len < cfg->code_size);
1850 /*========================= End of Function ========================*/
1852 /*------------------------------------------------------------------*/
1854 /* Name - mono_arch_emit_exceptions */
1856 /* Function - Emit the blocks to handle exception conditions. */
1858 /*------------------------------------------------------------------*/
1861 mono_arch_emit_exceptions (MonoCompile *cfg)
1863 MonoJumpInfo *patch_info;
1865 unsigned int *code, *got_start;
1866 unsigned long *corlib_exc_adr;
1867 MonoClass *exc_classes [16];
1868 guint8 *exc_throw_start [16], *exc_throw_end [16];
1869 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1870 AlphaGotEntry *got_data;
1872 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1874 /* Compute needed space */
1875 for (patch_info = cfg->patch_info; patch_info;
1876 patch_info = patch_info->next)
1878 if (patch_info->type == MONO_PATCH_INFO_EXC)
1880 if (patch_info->type == MONO_PATCH_INFO_R8)
1881 code_size += 8 + 7; /* sizeof (double) + alignment */
1882 if (patch_info->type == MONO_PATCH_INFO_R4)
1883 code_size += 4 + 7; /* sizeof (float) + alignment */
1886 // Reserve space for GOT entries
1887 for (got_data = cfg->arch.got_data; got_data;
1888 got_data = got_data->next)
1890 // Reserve space for 8 byte const (for now)
1891 if (got_data->type != GT_LD_GTADDR)
1895 while (cfg->code_len + code_size > (cfg->code_size - 16))
1897 cfg->code_size *= 2;
1898 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1899 mono_jit_stats.code_reallocs++;
1902 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1904 // Set code alignment
1905 if (((unsigned long)code) % 8)
1910 /* Add code to store conts and modify patch into to store offset in got */
1911 for (got_data = cfg->arch.got_data; got_data;
1912 got_data = got_data->next)
1914 unsigned long data = got_data->value.data.l;
1915 MonoJumpInfo *got_ref = got_data->got_patch_info;
1917 // Modify loading of GP
1918 if (got_data->type == GT_LD_GTADDR)
1920 short high_off, low_off;
1921 unsigned int *ldgp_code =
1922 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1923 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1925 high_off = got_off / 0x10000;
1926 low_off = got_off % 0x10000;
1930 // Set offset from current point to GOT array
1931 // modify the following code sequence
1932 // ldah gp, 0(pv) or ldah gp, 0(ra)
1934 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1936 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1941 patch_info = got_data->patch_info;
1943 // Check code alignment
1944 if (((unsigned long)code) % 8)
1947 got_ref->data.offset = ((char *)code - (char *)got_start);
1950 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1952 *code = (unsigned int)(data & 0xFFFFFFFF);
1954 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1959 corlib_exc_adr = (unsigned long *)code;
1961 /* add code to raise exceptions */
1963 for (patch_info = cfg->patch_info; patch_info;
1964 patch_info = patch_info->next)
1966 switch (patch_info->type)
1968 case MONO_PATCH_INFO_EXC:
1970 MonoClass *exc_class;
1971 unsigned int *buf, *buf2;
1976 // Add patch info to call mono_arch_throw_corlib_exception
1977 // method to raise corlib exception
1978 // Will be added at the begining of the patch info list
1979 mono_add_patch_info(cfg,
1980 ((char *)code - (char *)cfg->native_code),
1981 MONO_PATCH_INFO_INTERNAL_METHOD,
1982 "mono_arch_throw_corlib_exception");
1984 // Skip longword before starting the code
1989 exc_class = mono_class_from_name (mono_defaults.corlib,
1990 "System", patch_info->data.name);
1992 g_assert (exc_class);
1993 throw_ip = patch_info->ip.i;
1995 //x86_breakpoint (code);
1996 /* Find a throw sequence for the same exception class */
1997 for (i = 0; i < nthrows; ++i)
1998 if (exc_classes [i] == exc_class)
2005 // Patch original branch (patch info) to jump here
2006 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
2007 patch_info->data.target =
2008 (char *)code - (char *)cfg->native_code;
2010 alpha_lda(code, alpha_a1, alpha_zero,
2011 -((short)((((char *)exc_throw_end[i] -
2012 (char *)cfg->native_code)) - throw_ip) - 4) );
2014 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
2016 alpha_bsr(code, alpha_zero, br_offset);
2022 // Save exception token type as first 32bit word for new
2023 // exception handling jump code
2024 *code = exc_class->type_token;
2027 // Patch original branch (patch info) to jump here
2028 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
2029 patch_info->data.target =
2030 (char *)code - (char *)cfg->native_code;
2033 alpha_lda(code, alpha_a1, alpha_zero, 0);
2037 exc_classes [nthrows] = exc_class;
2038 exc_throw_start [nthrows] = code;
2041 // Load exception token
2042 alpha_ldl(code, alpha_a0, alpha_gp,
2043 ((char *)buf - (char *)got_start /*cfg->native_code*/));
2044 // Load corlib exception raiser code address
2045 alpha_ldq(code, alpha_pv, alpha_gp,
2046 ((char *)corlib_exc_adr -
2047 (char *)got_start /*cfg->native_code*/));
2049 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
2050 //patch_info->data.name = "mono_arch_throw_corlib_exception";
2051 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
2052 //patch_info->type = MONO_PATCH_INFO_NONE;
2053 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
2055 if (cfg->compile_aot)
2057 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
2058 //amd64_call_reg (code, GP_SCRATCH_REG);
2060 /* The callee is in memory allocated using
2062 alpha_jsr(code, alpha_ra, alpha_pv, 0);
2065 alpha_lda(buf2, alpha_a1, alpha_zero,
2066 -((short)(((char *)code - (char *)cfg->native_code) -
2071 exc_throw_end [nthrows] = code;
2083 /* Handle relocations with RIP relative addressing */
2084 for (patch_info = cfg->patch_info; patch_info;
2085 patch_info = patch_info->next)
2087 gboolean remove = FALSE;
2089 switch (patch_info->type)
2091 case MONO_PATCH_INFO_R8:
2095 code = (guint8*)ALIGN_TO (code, 8);
2097 pos = cfg->native_code + patch_info->ip.i;
2099 *(double*)code = *(double*)patch_info->data.target;
2102 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2104 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2110 case MONO_PATCH_INFO_R4:
2114 code = (guint8*)ALIGN_TO (code, 8);
2116 pos = cfg->native_code + patch_info->ip.i;
2118 *(float*)code = *(float*)patch_info->data.target;
2121 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2123 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2135 if (patch_info == cfg->patch_info)
2136 cfg->patch_info = patch_info->next;
2141 for (tmp = cfg->patch_info; tmp->next != patch_info;
2144 tmp->next = patch_info->next;
2149 cfg->code_len = (char *)code - (char *)cfg->native_code;
2151 g_assert (cfg->code_len < cfg->code_size);
2155 /*========================= End of Function ========================*/
2157 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2158 offset = ((char *)code - \
2159 (char *)cfg->native_code); \
2160 if (Tins->flags & MONO_INST_BRLABEL) \
2162 if (Tins->inst_i0->inst_c0) \
2164 CFG_DEBUG(3) g_print("inst_c0: %0lX, data: %p]\n", \
2165 Tins->inst_i0->inst_c0, \
2166 cfg->native_code + Tins->inst_i0->inst_c0); \
2167 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2171 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n", \
2172 offset, Tins->inst_i0); \
2173 mono_add_patch_info (cfg, offset, \
2174 MONO_PATCH_INFO_LABEL, Tins->inst_i0); \
2175 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2180 if (Tins->inst_true_bb->native_offset) \
2182 long br_offset = (char *)cfg->native_code + \
2183 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2184 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2185 Tins->inst_target_bb->native_offset, \
2186 cfg->native_code + \
2187 Tins->inst_true_bb->native_offset); \
2188 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2192 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2193 offset, Tins->inst_target_bb); \
2194 mono_add_patch_info (cfg, offset, \
2195 MONO_PATCH_INFO_BB, \
2196 Tins->inst_true_bb); \
2197 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2202 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2205 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2210 mono_add_patch_info (cfg, \
2212 (char *)cfg->native_code), \
2213 MONO_PATCH_INFO_EXC, EXC_NAME); \
2214 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2218 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2223 /*------------------------------------------------------------------*/
2225 /* Name - mono_arch_output_basic_block */
2227 /* Function - Perform the "real" work of emitting instructions */
2228 /* that will do the work of in the basic block. */
2230 /*------------------------------------------------------------------*/
2233 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2238 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2239 MonoInst *last_ins = NULL;
2240 guint last_offset = 0;
2243 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2245 if (cfg->opt & MONO_OPT_PEEPHOLE)
2246 peephole_pass (cfg, bb);
2248 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2249 bb->block_num, bb, bb->native_offset);
2251 cpos = bb->max_offset;
2253 offset = ((char *)code) - ((char *)cfg->native_code);
2255 mono_debug_open_block (cfg, bb, offset);
2260 offset = ((char *)code) - ((char *)cfg->native_code);
2262 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2264 if (offset > (cfg->code_size - max_len - 16))
2266 cfg->code_size *= 2;
2267 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2268 code = (unsigned int *)(cfg->native_code + offset);
2269 mono_jit_stats.code_reallocs++;
2272 mono_debug_record_line_number (cfg, ins, offset);
2274 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2275 mono_inst_name(ins->opcode));
2277 switch (ins->opcode)
2280 // Shift 64 bit value right
2281 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2282 ins->dreg, ins->sreg1, ins->sreg2);
2283 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2287 // Shift 64 bit value right
2288 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2289 ins->dreg, ins->sreg1, ins->sreg2);
2290 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2294 // Shift 64 bit value right by constant
2295 g_assert(alpha_is_imm(ins->inst_imm));
2296 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2297 ins->dreg, ins->sreg1, ins->inst_imm);
2298 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2302 // Shift 32 bit value left
2303 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2304 ins->dreg, ins->sreg1, ins->sreg2);
2305 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2309 // Shift 32 bit value left by constant
2310 g_assert(alpha_is_imm(ins->inst_imm));
2311 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2312 ins->dreg, ins->sreg1, ins->inst_imm);
2313 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2317 g_assert(alpha_is_imm(ins->inst_imm));
2318 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2319 ins->dreg, ins->sreg1, ins->inst_imm);
2320 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2324 g_assert(alpha_is_imm(ins->inst_imm));
2325 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2326 ins->dreg, ins->sreg1, ins->inst_imm);
2327 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2332 // Shift 32 bit value left
2333 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2334 ins->dreg, ins->sreg1, ins->sreg2);
2335 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2339 // Shift 64 bit value left
2340 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2341 ins->dreg, ins->sreg1, ins->sreg2);
2342 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2347 // Shift 32 bit value right
2348 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2349 ins->dreg, ins->sreg1, ins->sreg2);
2350 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2351 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2355 // Shift 32 bit value rigth by constant
2356 g_assert(alpha_is_imm(ins->inst_imm));
2357 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2358 ins->dreg, ins->sreg1, ins->inst_imm);
2359 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2360 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2364 // Shift 32 bit unsigned value right
2365 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2366 ins->dreg, ins->sreg1, ins->sreg2);
2367 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2368 alpha_srl(code, alpha_at /*ins->dreg*/, ins->sreg2, ins->dreg);
2371 case OP_ISHR_UN_IMM:
2372 // Shift 32 bit unassigned value rigth by constant
2373 g_assert(alpha_is_imm(ins->inst_imm));
2374 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2375 ins->dreg, ins->sreg1, ins->inst_imm);
2376 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2377 alpha_srl_(code, alpha_at /*ins->dreg*/, ins->inst_imm, ins->dreg);
2380 case OP_LSHR_UN_IMM:
2381 // Shift 64 bit unassigned value rigth by constant
2382 g_assert(alpha_is_imm(ins->inst_imm));
2383 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2384 ins->dreg, ins->sreg1, ins->inst_imm);
2385 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2389 // Sum two 64 bits regs
2390 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2391 ins->dreg, ins->sreg1, ins->sreg2);
2392 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2396 // Subtract two 64 bit regs
2397 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2398 ins->dreg, ins->sreg1, ins->sreg2);
2399 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2403 // Add imm value to 64 bits int
2404 g_assert(alpha_is_imm(ins->inst_imm));
2405 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2406 ins->dreg, ins->sreg1, ins->inst_imm);
2407 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2411 // Add two 32 bit ints
2412 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2413 ins->dreg, ins->sreg1, ins->sreg2);
2414 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2418 // Add two 32 bit ints with overflow detection
2419 // Use AT to hold flag of signed overflow
2420 // Use t12(PV) to hold unsigned overflow
2421 // Use RA to hold intermediate result
2422 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2423 ins->dreg, ins->sreg1, ins->sreg2);
2424 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2425 alpha_ble(code, ins->sreg2, 2);
2427 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2428 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2429 alpha_br(code, alpha_zero, 1);
2431 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2432 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2434 /* res <u sreg1 => unsigned overflow */
2435 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2437 alpha_mov1(code, alpha_ra, ins->dreg);
2441 // Add two 64 bit ints with overflow detection
2442 // Use AT to hold flag of signed overflow
2443 // Use t12(PV) to hold unsigned overflow
2444 // Use RA to hold intermediate result
2445 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2446 ins->dreg, ins->sreg1, ins->sreg2);
2447 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2448 alpha_ble(code, ins->sreg2, 2);
2450 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2451 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2452 alpha_br(code, alpha_zero, 1);
2454 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2455 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2457 /* res <u sreg1 => unsigned overflow */
2458 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2460 alpha_mov1(code, alpha_ra, ins->dreg);
2464 // Add imm value to 32 bits int
2465 g_assert(alpha_is_imm(ins->inst_imm));
2466 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2467 ins->dreg, ins->sreg1, ins->inst_imm);
2468 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2472 // Substract to 32 bit ints
2473 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2474 ins->dreg, ins->sreg1, ins->sreg2);
2475 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2479 // Sub imm value from 32 bits int
2480 g_assert(alpha_is_imm(ins->inst_imm));
2481 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2482 ins->dreg, ins->sreg1, ins->inst_imm);
2483 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2487 // Sub to 32 bit ints with overflow detection
2488 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2489 ins->dreg, ins->sreg1, ins->sreg2);
2490 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2491 alpha_ble(code, ins->sreg2, 2);
2493 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2494 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2495 alpha_br(code, alpha_zero, 1);
2497 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2498 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2500 /* sreg1 <u sreg2 => unsigned overflow */
2501 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2503 alpha_mov1(code, alpha_ra, ins->dreg);
2507 // Sub to 64 bit ints with overflow detection
2508 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2509 ins->dreg, ins->sreg1, ins->sreg2);
2511 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2512 alpha_ble(code, ins->sreg2, 2);
2514 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2515 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2516 alpha_br(code, alpha_zero, 1);
2518 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2519 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2521 /* sreg1 <u sreg2 => unsigned overflow */
2522 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2524 alpha_mov1(code, alpha_ra, ins->dreg);
2529 // AND to 32 bit ints
2530 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2531 ins->dreg, ins->sreg1, ins->sreg2);
2532 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2537 // AND imm value with 32 bit int
2538 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2539 ins->dreg, ins->sreg1, ins->inst_imm);
2541 g_assert(alpha_is_imm(ins->inst_imm));
2542 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2548 // OR two 32/64 bit ints
2549 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2550 ins->dreg, ins->sreg1, ins->sreg2);
2551 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2555 // OR imm value with 32 bit int
2556 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2557 ins->dreg, ins->sreg1, ins->inst_imm);
2559 g_assert(alpha_is_imm(ins->inst_imm));
2560 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2566 // XOR two 32/64 bit ints
2567 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2568 ins->dreg, ins->sreg1, ins->sreg2);
2569 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2573 // XOR imm value with 32 bit int
2574 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2575 ins->dreg, ins->sreg1, ins->inst_imm);
2577 g_assert(alpha_is_imm(ins->inst_imm));
2578 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2584 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2585 ins->dreg, ins->sreg1);
2586 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2591 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2592 ins->dreg, ins->sreg1);
2593 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2598 // NOT 32/64 bit reg
2599 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2600 ins->dreg, ins->sreg1);
2601 alpha_not(code, ins->sreg1, ins->dreg);
2609 case OP_IMUL_OVF_UN:
2612 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",
2613 ins->dreg, ins->sreg1, ins->sreg2);
2617 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2618 ins->dreg, ins->sreg1, ins->sreg2);
2619 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2623 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2624 ins->dreg, ins->sreg1, ins->inst_imm);
2628 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2630 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2634 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2635 ins->dreg, ins->sreg1);
2636 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2637 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2641 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2642 ins->dreg, ins->sreg1);
2643 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2644 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2648 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2649 ins->dreg, ins->sreg1);
2650 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2651 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2655 // Actually ICONST is 32 bits long
2656 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2657 ins->dreg, ins->inst_c0);
2660 if (ins->inst_c0 == 0)
2662 alpha_clr(code, ins->dreg);
2666 // if -32768 < const <= 32767
2667 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2669 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2670 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2671 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2675 int lo = (char *)code - (char *)cfg->native_code;
2676 AlphaGotData ge_data;
2678 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2679 ge_data.data.l = ins->inst_c0;
2681 add_got_entry(cfg, GT_LONG, ge_data,
2682 lo, MONO_PATCH_INFO_NONE, 0);
2683 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2685 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2686 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2694 // To load 64 bit values we will have to use ldah/lda combination
2695 // and temporary register. As temporary register use r28
2696 // Divide 64 bit value in two parts and load upper 32 bits into
2697 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2698 // dreg from temp reg
2699 // the 32 bit value could be loaded with ldah/lda
2700 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2701 ins->dreg, ins->inst_c0);
2704 if (ins->inst_c0 == 0)
2706 alpha_clr(code, ins->dreg);
2710 // if -32768 < const <= 32767
2711 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2712 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2715 AlphaGotData ge_data;
2717 lo = (char *)code - (char *)cfg->native_code;
2719 ge_data.data.l = ins->inst_c0;
2721 add_got_entry(cfg, GT_LONG, ge_data,
2722 lo, MONO_PATCH_INFO_NONE, 0);
2723 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2730 double d = *(double *)ins->inst_p0;
2731 AlphaGotData ge_data;
2733 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2737 add_got_entry(cfg, GT_DOUBLE, ge_data,
2738 (char *)code - (char *)cfg->native_code,
2739 MONO_PATCH_INFO_NONE, 0);
2740 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2747 float d = *(float *)ins->inst_p0;
2748 AlphaGotData ge_data;
2750 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2754 add_got_entry(cfg, GT_FLOAT, ge_data,
2755 (char *)code - (char *)cfg->native_code,
2756 MONO_PATCH_INFO_NONE, 0);
2757 alpha_lds(code, ins->dreg, alpha_gp, 0);
2762 case OP_LOADU4_MEMBASE:
2763 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2764 ins->dreg, ins->inst_basereg, ins->inst_offset);
2766 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2767 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2770 case OP_LOADU1_MEMBASE:
2771 // Load unassigned byte from REGOFFSET
2772 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2773 ins->dreg, ins->inst_basereg, ins->inst_offset);
2775 alpha_ldbu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2778 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2780 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2781 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2785 case OP_LOADU2_MEMBASE:
2786 // Load unassigned word from REGOFFSET
2787 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2788 ins->dreg, ins->inst_basereg, ins->inst_offset);
2791 alpha_ldwu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2794 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2796 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2797 (ins->inst_offset+1));
2798 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2799 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2800 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2801 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2805 case OP_LOAD_MEMBASE:
2806 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2807 ins->dreg, ins->inst_basereg, ins->inst_offset);
2808 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2811 case OP_LOADI8_MEMBASE:
2812 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2813 ins->dreg, ins->inst_basereg, ins->inst_offset);
2814 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2817 case OP_LOADI4_MEMBASE:
2818 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2819 ins->dreg, ins->inst_basereg, ins->inst_offset);
2820 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2823 case OP_LOADI1_MEMBASE:
2824 // Load sign-extended byte from REGOFFSET
2825 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2826 ins->dreg, ins->inst_basereg, ins->inst_offset);
2829 alpha_ldbu(code, ins->dreg, ins->inst_basereg,
2831 alpha_sextb(code, ins->dreg, ins->dreg);
2835 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2837 alpha_lda(code, alpha_at, ins->inst_basereg,
2838 (ins->inst_offset+1));
2839 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2840 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2844 case OP_LOADI2_MEMBASE:
2845 // Load sign-extended word from REGOFFSET
2846 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2847 ins->dreg, ins->inst_basereg, ins->inst_offset);
2850 alpha_ldwu(code, ins->dreg, ins->inst_basereg,
2852 alpha_sextw(code, ins->dreg, ins->dreg);
2856 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2858 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2859 (ins->inst_offset+1));
2860 alpha_lda(code, alpha_at, ins->inst_basereg,
2861 (ins->inst_offset+2));
2862 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2863 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2864 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2865 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2869 case OP_STOREI1_MEMBASE_IMM:
2870 // Store signed byte at REGOFFSET
2871 // Valid only for storing 0
2872 // storei1_membase_reg will do the rest
2874 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2875 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2876 g_assert(ins->inst_imm == 0);
2879 alpha_stb(code, alpha_zero, ins->inst_destbasereg,
2882 g_assert_not_reached();
2886 case OP_STOREI1_MEMBASE_REG:
2887 // Store byte at REGOFFSET
2888 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2889 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2892 alpha_stb(code, ins->sreg1, ins->inst_destbasereg,
2897 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2899 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2901 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2902 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2903 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2904 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2909 case OP_STOREI2_MEMBASE_IMM:
2910 // Store signed word at REGOFFSET
2911 // Now work only for storing 0
2912 // For now storei2_membase_reg will do the work
2914 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2915 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2917 g_assert(ins->inst_imm == 0);
2920 alpha_stw(code, alpha_zero, ins->inst_destbasereg,
2923 g_assert_not_reached();
2927 case OP_STOREI2_MEMBASE_REG:
2928 // Store signed word from reg to REGOFFSET
2929 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2930 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2934 alpha_stw(code, ins->sreg1, ins->inst_destbasereg,
2939 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2941 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2942 (ins->inst_offset+1));
2943 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2945 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2946 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2947 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2948 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2949 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2950 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2951 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2952 (ins->inst_offset+1));
2953 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2959 case OP_STOREI4_MEMBASE_IMM:
2960 // We will get here only with ins->inst_imm = 0
2961 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2962 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2964 g_assert(ins->inst_imm == 0);
2966 alpha_stl(code, alpha_zero,
2967 ins->inst_destbasereg, ins->inst_offset);
2970 case OP_STORER4_MEMBASE_REG:
2971 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2972 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2973 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2976 case OP_STORER8_MEMBASE_REG:
2977 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2978 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2979 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2983 case OP_LOADR4_MEMBASE:
2984 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2985 ins->dreg, ins->inst_basereg, ins->inst_offset);
2986 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2989 case OP_LOADR8_MEMBASE:
2990 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2991 ins->dreg, ins->inst_basereg, ins->inst_offset);
2992 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2996 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2997 ins->sreg1, ins->dreg);
2998 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
3002 // Later check different rounding and exc modes
3003 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
3004 ins->sreg1, ins->sreg2, ins->dreg);
3005 alpha_addt(code, ins->sreg1, ins->sreg2, ins->dreg);
3009 // Later check different rounding and exc modes
3010 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
3011 ins->sreg1, ins->sreg2, ins->dreg);
3012 alpha_subt(code, ins->sreg1, ins->sreg2, ins->dreg);
3016 // Later check different rounding and exc modes
3017 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
3018 ins->sreg1, ins->sreg2, ins->dreg);
3019 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
3023 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
3024 ins->sreg1, ins->dreg);
3025 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
3028 case OP_ALPHA_TRAPB:
3029 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
3034 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
3035 ins->sreg1, ins->dreg);
3036 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
3039 case OP_STORE_MEMBASE_IMM:
3040 case OP_STOREI8_MEMBASE_IMM:
3041 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
3042 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
3043 g_assert(ins->inst_imm == 0);
3045 alpha_stq(code, alpha_zero,
3046 ins->inst_destbasereg, ins->inst_offset);
3049 case OP_STORE_MEMBASE_REG:
3050 case OP_STOREI8_MEMBASE_REG:
3051 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3052 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3053 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3056 case OP_STOREI4_MEMBASE_REG:
3057 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3058 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3059 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3062 case OP_ICOMPARE_IMM:
3063 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3064 ins->sreg1, ins->dreg, ins->inst_imm);
3066 g_assert_not_reached();
3070 case OP_COMPARE_IMM:
3071 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3072 ins->sreg1, ins->dreg, ins->inst_imm);
3074 g_assert_not_reached();
3078 case OP_COMPARE: // compare two 32 bit regs
3079 case OP_LCOMPARE: // compare two 64 bit regs
3080 case OP_FCOMPARE: // compare two floats
3081 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3082 ins->sreg1, ins->sreg2, ins->dreg);
3084 g_assert_not_reached();
3088 case OP_ALPHA_CMPT_UN:
3089 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3090 ins->sreg1, ins->sreg2, ins->dreg);
3091 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3094 case OP_ALPHA_CMPT_UN_SU:
3095 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3096 ins->sreg1, ins->sreg2, ins->dreg);
3097 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3100 case OP_ALPHA_CMPT_EQ:
3101 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3102 ins->sreg1, ins->sreg2, ins->dreg);
3103 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
3106 case OP_ALPHA_CMPT_EQ_SU:
3107 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3108 ins->sreg1, ins->sreg2, ins->dreg);
3109 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
3113 case OP_ALPHA_CMPT_LT:
3114 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3115 ins->sreg1, ins->sreg2, ins->dreg);
3116 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3119 case OP_ALPHA_CMPT_LT_SU:
3120 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3121 ins->sreg1, ins->sreg2, ins->dreg);
3122 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3125 case OP_ALPHA_CMPT_LE:
3126 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3127 ins->sreg1, ins->sreg2, ins->dreg);
3128 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3131 case OP_ALPHA_CMPT_LE_SU:
3132 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3133 ins->sreg1, ins->sreg2, ins->dreg);
3134 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3137 case OP_ALPHA_CMP_EQ:
3138 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3139 ins->sreg1, ins->sreg2, ins->dreg);
3140 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3143 case OP_ALPHA_CMP_IMM_EQ:
3144 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3145 ins->sreg1, ins->inst_imm, ins->dreg);
3146 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3149 case OP_ALPHA_CMP_IMM_ULE:
3150 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%\d\n",
3151 ins->sreg1, ins->inst_imm, ins->dreg);
3152 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3155 case OP_ALPHA_CMP_ULT:
3156 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3157 ins->sreg1, ins->sreg2, ins->dreg);
3158 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3161 case OP_ALPHA_CMP_IMM_ULT:
3162 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3163 ins->sreg1, ins->inst_imm, ins->dreg);
3164 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3167 case OP_ALPHA_CMP_LE:
3168 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3169 ins->sreg1, ins->sreg2, ins->dreg);
3170 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3173 case OP_ALPHA_CMP_ULE:
3174 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3175 ins->sreg1, ins->sreg2, ins->dreg);
3176 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3180 case OP_ALPHA_CMP_IMM_LE:
3181 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%\d\n",
3182 ins->sreg1, ins->inst_imm, ins->dreg);
3183 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3186 case OP_ALPHA_CMP_LT:
3187 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3188 ins->sreg1, ins->sreg2, ins->dreg);
3189 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3192 case OP_ALPHA_CMP_IMM_LT:
3193 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3194 ins->sreg1, ins->inst_imm, ins->dreg);
3195 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3198 case OP_COND_EXC_GT:
3199 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3200 (char *)ins->inst_p1);
3202 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3205 case OP_COND_EXC_GT_UN:
3206 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3207 (char *)ins->inst_p1);
3209 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3212 case OP_COND_EXC_LT:
3213 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3214 (char *)ins->inst_p1);
3216 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3219 case OP_COND_EXC_LT_UN:
3220 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3221 (char *)ins->inst_p1);
3223 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3227 case OP_COND_EXC_LE_UN:
3228 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3229 (char *)ins->inst_p1);
3230 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3233 case OP_COND_EXC_NE_UN:
3234 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3235 (char *)ins->inst_p1);
3236 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3239 case OP_COND_EXC_EQ:
3240 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3241 (char *)ins->inst_p1);
3242 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3245 case OP_COND_EXC_IOV:
3246 case OP_COND_EXC_OV:
3247 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3250 case OP_COND_EXC_IC:
3252 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3255 case CEE_CONV_OVF_U4:
3256 // Convert unsigned 32 bit value to 64 bit reg
3258 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3259 ins->sreg1, ins->dreg);
3260 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3261 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3262 alpha_mov1(code, ins->sreg1, ins->dreg);
3265 case CEE_CONV_OVF_I4_UN:
3266 // Convert unsigned 32 bit value to 64 bit reg
3268 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3269 ins->sreg1, ins->dreg);
3270 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3272 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3273 alpha_mov1(code, ins->sreg1, ins->dreg);
3277 // Move I1 (byte) to dreg(64 bits) and sign extend it
3279 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3280 ins->sreg1, ins->dreg);
3282 alpha_sextb(code, ins->sreg1, ins->dreg);
3285 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3286 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3287 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3292 // Move I2 (word) to dreg(64 bits) and sign extend it
3293 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3294 ins->sreg1, ins->dreg);
3296 alpha_sextw(code, ins->sreg1, ins->dreg);
3299 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3300 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3301 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3306 // Move I4 (long) to dreg(64 bits) and sign extend it
3307 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3308 ins->sreg1, ins->dreg);
3309 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3314 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3315 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3316 ins->sreg1, ins->dreg);
3317 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3318 alpha_mov1(code, ins->sreg1, ins->dreg);
3322 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3323 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3324 ins->sreg1, ins->dreg);
3325 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3329 // Move U2 (word) to dreg(64 bits) don't sign extend it
3330 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3331 ins->sreg1, ins->dreg);
3332 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3336 // Move U4 (long) to dreg(64 bits) don't sign extend it
3337 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3338 ins->sreg1, ins->dreg);
3339 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3344 // Move U4 (long) to dreg(64 bits) don't sign extend it
3345 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3346 ins->sreg1, ins->dreg);
3347 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3350 case OP_FCONV_TO_I4:
3351 case OP_FCONV_TO_I8:
3352 // Move float to 32 bit reg
3353 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3354 ins->sreg1, ins->dreg);
3355 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3356 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3357 alpha_lda(code, alpha_sp, alpha_sp, -8);
3358 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3359 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3360 alpha_lda(code, alpha_sp, alpha_sp, 8);
3363 case OP_FCONV_TO_I2:
3364 // Move float to 16 bit reg
3365 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3366 ins->sreg1, ins->dreg);
3367 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3368 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3369 alpha_lda(code, alpha_sp, alpha_sp, -8);
3370 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3371 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3372 alpha_lda(code, alpha_sp, alpha_sp, 8);
3373 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3374 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3377 case OP_FCONV_TO_U2:
3378 // Move float to 16 bit reg as unsigned
3379 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3380 ins->sreg1, ins->dreg);
3381 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3382 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3383 alpha_lda(code, alpha_sp, alpha_sp, -8);
3384 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3385 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3386 alpha_lda(code, alpha_sp, alpha_sp, 8);
3387 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3390 case OP_FCONV_TO_U1:
3391 // Move float to 8 bit reg as unsigned
3392 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3393 ins->sreg1, ins->dreg);
3394 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3395 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3396 alpha_lda(code, alpha_sp, alpha_sp, -8);
3397 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3398 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3399 alpha_lda(code, alpha_sp, alpha_sp, 8);
3400 alpha_and_(code, ins->dreg, 0xff, ins->dreg);
3403 case OP_FCONV_TO_I1:
3404 // Move float to 8 bit reg
3405 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3406 ins->sreg1, ins->dreg);
3407 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3408 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3409 alpha_lda(code, alpha_sp, alpha_sp, -8);
3410 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3411 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3412 alpha_lda(code, alpha_sp, alpha_sp, 8);
3413 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3414 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3418 case OP_LCONV_TO_R4:
3419 // Move 32/64 bit int into float
3420 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3421 ins->sreg1, ins->dreg);
3422 alpha_lda(code, alpha_sp, alpha_sp, -8);
3423 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3424 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3425 alpha_lda(code, alpha_sp, alpha_sp, 8);
3426 alpha_cvtqs(code, ins->dreg, ins->dreg);
3430 case OP_LCONV_TO_R8:
3431 // Move 32/64 bit int into double
3432 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3433 ins->sreg1, ins->dreg);
3434 alpha_lda(code, alpha_sp, alpha_sp, -8);
3435 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3436 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3437 alpha_lda(code, alpha_sp, alpha_sp, 8);
3438 alpha_cvtqt(code, ins->dreg, ins->dreg);
3441 case OP_FCONV_TO_R4:
3442 // Convert 64 bit float to 32 bit float (T -> S)
3443 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3444 ins->sreg1, ins->dreg);
3445 alpha_cvtts(code, ins->sreg1, ins->dreg);
3449 // Allocate sreg1 bytes on stack, round bytes by 8,
3450 // modify SP, set dreg to end of current stack frame
3451 // top of stack is used for call params
3452 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3453 ins->sreg1, ins->dreg);
3454 alpha_addq_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3455 alpha_and_(code, ins->sreg1, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3456 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3457 alpha_lda(code, ins->dreg, alpha_zero, (cfg->arch.params_stack_size));
3458 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3462 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3463 ins->sreg1, ins->dreg);
3464 alpha_mov1(code, ins->sreg1, ins->dreg);
3471 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3473 alpha_clr(code, ins->dreg);
3474 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3481 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3483 alpha_clr(code, ins->dreg);
3484 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3489 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3491 alpha_clr(code, ins->dreg);
3492 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3496 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3498 alpha_clr(code, ins->dreg);
3499 alpha_fbeq(code, alpha_at, 1);
3500 alpha_lda(code, ins->dreg, alpha_zero, 1);
3503 alpha_cvttq_c(code, alpha_at, alpha_at);
3504 alpha_lda(code, alpha_sp, alpha_sp, -8);
3505 alpha_stt(code, alpha_at, alpha_sp, 0);
3506 alpha_ldq(code, alpha_at, alpha_sp, 0);
3507 alpha_lda(code, alpha_sp, alpha_sp, 8);
3509 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3514 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3516 alpha_clr(code, ins->dreg);
3517 alpha_fbne(code, alpha_at, 1);
3518 alpha_lda(code, ins->dreg, alpha_zero, 1);
3521 alpha_cvttq_c(code, alpha_at, alpha_at);
3522 alpha_lda(code, alpha_sp, alpha_sp, -8);
3523 alpha_stt(code, alpha_at, alpha_sp, 0);
3524 alpha_ldq(code, alpha_at, alpha_sp, 0);
3525 alpha_lda(code, alpha_sp, alpha_sp, 8);
3527 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3533 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3535 alpha_clr(code, ins->dreg);
3536 alpha_fbeq(code, alpha_at, 1);
3537 alpha_lda(code, ins->dreg, alpha_zero, 1);
3541 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3544 alpha_clr(code, ins->dreg);
3545 alpha_fbne(code, (alpha_at+1), 1);
3546 alpha_fbeq(code, alpha_at, 1);
3547 alpha_lda(code, ins->dreg, alpha_zero, 1);
3552 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3553 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3557 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3558 alpha_fbeq(code, (alpha_at+1), 1);
3559 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3560 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3564 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3565 alpha_fbeq(code, (alpha_at+1), 1);
3566 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3567 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3571 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3572 alpha_fbeq(code, (alpha_at+1), 1);
3573 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3574 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3578 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3579 alpha_fbeq(code, (alpha_at+1), 1);
3580 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3581 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3585 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3586 alpha_fbeq(code, (alpha_at+1), 1);
3587 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3588 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3592 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3593 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3597 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3598 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3602 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3603 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3607 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3608 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3612 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3613 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3617 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br] target: %p, next: %p, curr: %p, last: %p [",
3618 ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3620 if (ins->flags & MONO_INST_BRLABEL)
3622 if (ins->inst_i0->inst_c0)
3624 CFG_DEBUG(4) g_print("inst_c0: %0lX, data: %p]\n",
3625 ins->inst_i0->inst_c0,
3626 cfg->native_code + ins->inst_i0->inst_c0);
3627 alpha_br(code, alpha_zero, 0);
3631 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n",
3632 offset, ins->inst_i0);
3633 mono_add_patch_info (cfg, offset,
3634 MONO_PATCH_INFO_LABEL, ins->inst_i0);
3636 alpha_br(code, alpha_zero, 0);
3641 if (ins->inst_target_bb->native_offset)
3643 // Somehow native offset is offset from
3644 // start of the code. So convert it to
3646 long br_offset = (char *)cfg->native_code +
3647 ins->inst_target_bb->native_offset - 4 - (char *)code;
3649 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3650 ins->inst_target_bb->native_offset,
3652 ins->inst_target_bb->native_offset);
3653 alpha_br(code, alpha_zero, br_offset/4);
3657 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3658 offset, ins->inst_target_bb);
3660 mono_add_patch_info (cfg, offset,
3662 ins->inst_target_bb);
3663 alpha_br(code, alpha_zero, 0);
3670 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3673 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3681 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3682 call = (MonoCallInst*)ins;
3684 if (ins->flags & MONO_INST_HAS_METHOD)
3686 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3687 code = emit_call (cfg, code,
3688 MONO_PATCH_INFO_METHOD, call->method);
3692 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3693 code = emit_call (cfg, code,
3694 MONO_PATCH_INFO_ABS, call->fptr);
3697 //code = emit_move_return_value (cfg, ins, code);
3704 case OP_VOIDCALL_REG:
3709 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3710 call = (MonoCallInst*)ins;
3712 alpha_mov1(code, ins->sreg1, alpha_pv);
3714 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3716 offset = (char *)code - (char *)cfg->native_code;
3719 ALPHA_LOAD_GP(offset)
3720 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3721 alpha_lda(code, alpha_gp, alpha_gp, 0);
3725 case OP_FCALL_MEMBASE:
3726 case OP_CALL_MEMBASE:
3727 case OP_LCALL_MEMBASE:
3728 case OP_VCALL_MEMBASE:
3732 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3733 ins->inst_basereg, ins->inst_offset);
3734 call = (MonoCallInst*)ins;
3736 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3737 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3739 offset = (char *)code - (char *)cfg->native_code;
3742 ALPHA_LOAD_GP(offset)
3743 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3744 alpha_lda(code, alpha_gp, alpha_gp, 0);
3748 case OP_VOIDCALL_MEMBASE:
3752 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3753 ins->inst_basereg, ins->inst_offset);
3754 call = (MonoCallInst*)ins;
3756 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3757 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3759 offset = (char *)code - (char *)cfg->native_code;
3762 ALPHA_LOAD_GP(offset)
3763 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3764 alpha_lda(code, alpha_gp, alpha_gp, 0);
3768 case OP_START_HANDLER:
3770 // TODO - find out when we called by call_handler or resume_context
3771 // of by call_filter. There should be difference. For now just
3772 // handle - call_handler
3774 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3775 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3777 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3778 ins->inst_left->inst_offset);
3782 case CEE_ENDFINALLY:
3784 // Keep in sync with start_handler
3785 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3786 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3788 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3789 ins->inst_left->inst_offset);
3791 alpha_ret(code, alpha_ra, 1);
3797 // Keep in sync with start_handler
3798 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3799 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3801 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3802 ins->inst_left->inst_offset);
3804 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3805 alpha_mov1(code, ins->sreg1, alpha_r0);
3807 alpha_ret(code, alpha_ra, 1);
3811 case OP_CALL_HANDLER:
3815 offset = (char *)code - (char *)cfg->native_code;
3817 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3818 offset, ins->inst_target_bb);
3820 mono_add_patch_info (cfg, offset,
3822 ins->inst_target_bb);
3823 alpha_bsr(code, alpha_ra, 0);
3828 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ret]\n");
3830 alpha_ret(code, alpha_ra, 1);
3834 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3836 alpha_mov1(code, ins->sreg1, alpha_a0);
3837 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3838 (gpointer)"mono_arch_throw_exception");
3842 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3844 alpha_mov1(code, ins->sreg1, alpha_a0);
3845 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3846 (gpointer)"mono_arch_rethrow_exception");
3852 * Note: this 'frame destruction' logic is useful for tail calls,
3853 too. Keep in sync with the code in emit_epilog.
3856 AlphaGotData ge_data;
3858 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3860 /* FIXME: no tracing support... */
3861 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3862 code = mono_arch_instrument_epilog (cfg,
3863 mono_profiler_method_leave, code, FALSE);
3864 g_assert (!cfg->method->save_lmf);
3866 alpha_mov1( code, alpha_fp, alpha_sp );
3868 code = emit_load_volatile_arguments (cfg, code);
3870 offset = cfg->arch.params_stack_size;
3872 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3873 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3874 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3876 ge_data.data.p = ins->inst_p0;
3877 add_got_entry(cfg, GT_PTR, ge_data,
3878 (char *)code - (char *)cfg->native_code,
3879 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3880 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3882 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3887 mono_add_patch_info (cfg, offset,
3888 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3891 case OP_MEMORY_BARRIER:
3892 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3897 g_warning ("unknown opcode %s in %s()\n",
3898 mono_inst_name (ins->opcode), __FUNCTION__);
3900 // g_assert_not_reached ();
3904 if ( (((char *)code) -
3905 ((char *)cfg->native_code) -
3908 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3909 mono_inst_name (ins->opcode), max_len,
3910 ((char *)code) - ((char *)cfg->native_code) - offset );
3911 //g_assert_not_reached ();
3917 last_offset = offset;
3922 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3925 /*========================= End of Function ========================*/
3930 /*------------------------------------------------------------------*/
3932 /* Name - mono_arch_cpu_optimizazions */
3934 /* Function - Returns the optimizations supported on this CPU */
3936 /*------------------------------------------------------------------*/
3939 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3943 if (getenv("MONO_ALPHA_DEBUG"))
3944 mini_alpha_verbose_level = 1;
3946 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3948 /*----------------------------------------------------------*/
3949 /* no alpha-specific optimizations yet */
3950 /*----------------------------------------------------------*/
3951 *exclude_mask = MONO_OPT_LINEARS;
3952 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3956 /*========================= End of Function ========================*/
3958 /*------------------------------------------------------------------*/
3960 /* Name - mono_arch_flush_icache */
3962 /* Function - Flush the CPU icache. */
3964 /*------------------------------------------------------------------*/
3967 mono_arch_flush_icache (guint8 *code, gint size)
3969 //ALPHA_DEBUG("mono_arch_flush_icache");
3971 /* flush instruction cache to see trampoline code */
3972 asm volatile("imb":::"memory");
3975 /*========================= End of Function ========================*/
3977 /*------------------------------------------------------------------*/
3979 /* Name - mono_arch_regname */
3981 /* Function - Returns the name of the register specified by */
3982 /* the input parameter. */
3984 /*------------------------------------------------------------------*/
3987 mono_arch_regname (int reg) {
3988 static const char * rnames[] = {
3989 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
3990 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
3991 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
3992 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
3993 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
3994 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
3995 "alpha_r30", "alpha_r31"
3998 if (reg >= 0 && reg < 32)
3999 return rnames [reg];
4003 /*========================= End of Function ========================*/
4005 /*------------------------------------------------------------------*/
4007 /* Name - mono_arch_fregname */
4009 /* Function - Returns the name of the register specified by */
4010 /* the input parameter. */
4012 /*------------------------------------------------------------------*/
4015 mono_arch_fregname (int reg) {
4016 static const char * rnames[] = {
4017 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4018 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4019 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4020 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4021 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4022 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4023 "alpha_f30", "alpha_f31"
4026 if (reg >= 0 && reg < 32)
4027 return rnames [reg];
4032 /*========================= End of Function ========================*/
4034 /*------------------------------------------------------------------*/
4036 /* Name - mono_arch_patch_code */
4038 /* Function - Process the patch data created during the */
4039 /* instruction build process. This resolves jumps, */
4040 /* calls, variables etc. */
4042 /*------------------------------------------------------------------*/
4045 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
4046 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4048 MonoJumpInfo *patch_info;
4049 gboolean compile_aot = !run_cctors;
4051 ALPHA_DEBUG("mono_arch_patch_code");
4053 for (patch_info = ji; patch_info; patch_info = patch_info->next)
4055 unsigned char *ip = patch_info->ip.i + code;
4056 const unsigned char *target;
4058 target = mono_resolve_patch_target (method, domain,
4059 code, patch_info, run_cctors);
4063 switch (patch_info->type)
4066 case MONO_PATCH_INFO_BB:
4067 case MONO_PATCH_INFO_LABEL:
4070 /* No need to patch these */
4075 switch (patch_info->type)
4077 case MONO_PATCH_INFO_NONE:
4080 case MONO_PATCH_INFO_GOT_OFFSET:
4082 unsigned int *ip2 = (unsigned int *)ip;
4083 unsigned int inst = *ip2;
4084 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
4086 g_assert(!(off & 0xFFFF8000));
4094 case MONO_PATCH_INFO_CLASS_INIT:
4096 /* Might already been changed to a nop */
4097 unsigned int* ip2 = (unsigned int *)ip;
4098 unsigned long t_addr = (unsigned long)target;
4100 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
4101 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
4102 NOT_IMPLEMENTED("mono_arch_patch_code: MONO_PATCH_INFO_CLASS_INIT");
4103 // amd64_call_code (ip2, 0);
4107 // case MONO_PATCH_INFO_METHOD_REL:
4108 case MONO_PATCH_INFO_R8:
4109 case MONO_PATCH_INFO_R4:
4110 g_assert_not_reached ();
4112 case MONO_PATCH_INFO_BB:
4115 case MONO_PATCH_INFO_METHOD:
4116 case MONO_PATCH_INFO_METHODCONST:
4117 case MONO_PATCH_INFO_INTERNAL_METHOD:
4118 case MONO_PATCH_INFO_METHOD_JUMP:
4120 volatile unsigned int *p = (unsigned int *)ip;
4121 unsigned long t_addr;
4128 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4130 if (target != ((void *)t_addr))
4132 t_addr = (unsigned long)target;
4133 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4134 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4139 case MONO_PATCH_INFO_ABS:
4141 volatile unsigned int *p = (unsigned int *)ip;
4142 unsigned long t_addr;
4148 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4153 case MONO_PATCH_INFO_SWITCH:
4155 unsigned int *pcode = (unsigned int *)ip;
4156 unsigned long t_addr;
4158 t_addr = (unsigned long)target;
4160 if (((unsigned long)ip) % 8)
4166 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4167 alpha_nop(pcode); // TODO optimize later
4168 alpha_bsr(pcode, alpha_at, 2);
4170 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4172 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4175 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4185 volatile unsigned int *p = (unsigned int *)ip;
4186 unsigned int alpha_ins = *p;
4187 unsigned int opcode;
4190 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4192 if (opcode >= 0x30 && opcode <= 0x3f)
4194 // This is branch with offset instruction
4195 br_offset = (target - ip - 4);
4197 g_assert(!(br_offset & 3));
4199 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4207 /*========================= End of Function ========================*/
4208 /*------------------------------------------------------------------*/
4210 /* Name - mono_arch_emit_this_vret_args */
4214 /*------------------------------------------------------------------*/
4217 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4218 int this_reg, int this_type, int vt_reg)
4220 MonoCallInst *call = (MonoCallInst*)inst;
4221 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4223 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4229 if (cinfo->ret.storage == ArgValuetypeInReg)
4232 * The valuetype is in RAX:RDX after the call, need to be copied to
4233 * the stack. Push the address here, so the call instruction can
4236 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4237 //vtarg->sreg1 = vt_reg;
4238 //mono_bblock_add_inst (cfg->cbb, vtarg);
4241 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4246 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4247 vtarg->sreg1 = vt_reg;
4248 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4249 mono_bblock_add_inst (cfg->cbb, vtarg);
4251 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4252 cinfo->ret.reg, FALSE);
4256 /* add the this argument */
4260 MONO_INST_NEW (cfg, this, OP_MOVE);
4261 this->type = this_type;
4262 this->sreg1 = this_reg;
4263 this->dreg = mono_regstate_next_int (cfg->rs);
4264 mono_bblock_add_inst (cfg->cbb, this);
4266 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4267 cinfo->args [0].reg, FALSE);
4273 /*========================= End of Function ========================*/
4275 /*------------------------------------------------------------------*/
4277 /* Name - mono_arch_is_inst_imm */
4279 /* Function - Determine if operand qualifies as an immediate */
4280 /* value. For Alpha this is a value 0 - 255 */
4282 /* Returns - True|False - is [not] immediate value. */
4284 /*------------------------------------------------------------------*/
4287 mono_arch_is_inst_imm (gint64 imm)
4289 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4291 return (imm & ~(0x0FFL)) ? 0 : 1;
4294 /*------------------------------------------------------------------*/
4296 /* Name - mono_arch_setup_jit_tls_data */
4298 /* Function - Setup the JIT's Thread Level Specific Data. */
4300 /*------------------------------------------------------------------*/
4303 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4305 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4307 if (!tls_offset_inited) {
4308 tls_offset_inited = TRUE;
4311 if (!lmf_addr_key_inited) {
4312 lmf_addr_key_inited = TRUE;
4313 pthread_key_create (&lmf_addr_key, NULL);
4316 pthread_setspecific (lmf_addr_key, &tls->lmf);
4319 /*------------------------------------------------------------------*/
4321 /* Name - mono_arch_cpu_init */
4323 /* Function - Perform CPU specific initialization to execute */
4326 /*------------------------------------------------------------------*/
4329 mono_arch_cpu_init (void)
4331 unsigned long amask, implver;
4332 register long v0 __asm__("$0") = -1;
4334 ALPHA_DEBUG("mono_arch_cpu_init");
4336 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
4338 __asm__ (".long 0x47e03d80" : "=r"(v0));
4344 //printf("amask: %x, implver: %x", amask, implver);
4351 * Obtain information about a call according to the calling convention.
4353 * For x86 ELF, see the "System V Application Binary Interface Intel386
4354 * Architecture Processor Supplment, Fourth Edition" document for more
4356 * For x86 win32, see ???.
4359 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
4361 guint32 i, gr, fr, *pgr, *pfr;
4363 int n = sig->hasthis + sig->param_count;
4364 guint32 stack_size = 0;
4367 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4382 ret_type = mono_type_get_underlying_type (sig->ret);
4383 switch (ret_type->type) {
4384 case MONO_TYPE_BOOLEAN:
4389 case MONO_TYPE_CHAR:
4395 case MONO_TYPE_FNPTR:
4396 case MONO_TYPE_CLASS:
4397 case MONO_TYPE_OBJECT:
4398 case MONO_TYPE_SZARRAY:
4399 case MONO_TYPE_ARRAY:
4400 case MONO_TYPE_STRING:
4401 cinfo->ret.storage = ArgInIReg;
4402 cinfo->ret.reg = alpha_r0;
4406 cinfo->ret.storage = ArgInIReg;
4407 cinfo->ret.reg = alpha_r0;
4410 cinfo->ret.storage = ArgInFloatReg;
4411 cinfo->ret.reg = alpha_f0;
4414 cinfo->ret.storage = ArgInDoubleReg;
4415 cinfo->ret.reg = alpha_f0;
4417 case MONO_TYPE_GENERICINST:
4418 if (!mono_type_generic_inst_is_valuetype (sig->ret))
4420 cinfo->ret.storage = ArgInIReg;
4421 cinfo->ret.reg = alpha_r0;
4425 case MONO_TYPE_VALUETYPE:
4427 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4429 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE,
4430 &tmp_gr, &tmp_fr, &tmp_stacksize);
4432 if (cinfo->ret.storage == ArgOnStack)
4433 /* The caller passes the address where the value
4435 add_general (pgr, &stack_size, &cinfo->ret);
4438 case MONO_TYPE_TYPEDBYREF:
4439 /* Same as a valuetype with size 24 */
4440 add_general (pgr, &stack_size, &cinfo->ret);
4443 case MONO_TYPE_VOID:
4446 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4452 add_general (pgr, &stack_size, cinfo->args + 0);
4454 if (!sig->pinvoke &&
4455 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4458 fr = FLOAT_PARAM_REGS;
4460 /* Emit the signature cookie just before the implicit arguments
4462 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4465 for (i = 0; i < sig->param_count; ++i)
4467 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4470 if (!sig->pinvoke &&
4471 (sig->call_convention == MONO_CALL_VARARG) &&
4472 (i == sig->sentinelpos))
4474 /* We allways pass the sig cookie on the stack for simpl
4477 * Prevent implicit arguments + the sig cookie from being passed
4481 fr = FLOAT_PARAM_REGS;
4483 /* Emit the signature cookie just before the implicit arguments */
4484 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4487 if (sig->params [i]->byref) {
4488 add_general (pgr, &stack_size, ainfo);
4492 ptype = mono_type_get_underlying_type (sig->params [i]);
4494 switch (ptype->type) {
4495 case MONO_TYPE_BOOLEAN:
4498 add_general (pgr, &stack_size, ainfo);
4502 case MONO_TYPE_CHAR:
4503 add_general (pgr, &stack_size, ainfo);
4507 add_general (pgr, &stack_size, ainfo);
4512 case MONO_TYPE_FNPTR:
4513 case MONO_TYPE_CLASS:
4514 case MONO_TYPE_OBJECT:
4515 case MONO_TYPE_STRING:
4516 case MONO_TYPE_SZARRAY:
4517 case MONO_TYPE_ARRAY:
4518 add_general (pgr, &stack_size, ainfo);
4520 case MONO_TYPE_GENERICINST:
4521 if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
4523 add_general (pgr, &stack_size, ainfo);
4527 case MONO_TYPE_VALUETYPE:
4529 /* We allways pass valuetypes on the stack */
4530 add_valuetype (sig, ainfo, sig->params [i],
4531 FALSE, pgr, pfr, &stack_size);
4533 case MONO_TYPE_TYPEDBYREF:
4534 stack_size += sizeof (MonoTypedRef);
4535 ainfo->storage = ArgOnStack;
4539 add_general (pgr, &stack_size, ainfo);
4542 add_float (pfr, &stack_size, ainfo, FALSE);
4545 add_float (pfr, &stack_size, ainfo, TRUE);
4548 g_assert_not_reached ();
4552 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4553 (n > 0) && (sig->sentinelpos == sig->param_count))
4556 fr = FLOAT_PARAM_REGS;
4558 /* Emit the signature cookie just before the implicit arguments
4560 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4563 cinfo->stack_usage = stack_size;
4564 cinfo->reg_usage = gr;
4565 cinfo->freg_usage = fr;
4570 static const char *CvtMonoType(MonoTypeEnum t)
4575 return "MONO_TYPE_END";
4576 case MONO_TYPE_VOID:
4577 return "MONO_TYPE_VOID";
4578 case MONO_TYPE_BOOLEAN:
4579 return "MONO_TYPE_BOOLEAN";
4580 case MONO_TYPE_CHAR:
4581 return "MONO_TYPE_CHAR";
4583 return "MONO_TYPE_I1";
4585 return "MONO_TYPE_U1";
4587 return "MONO_TYPE_I2";
4589 return "MONO_TYPE_U2";
4591 return "MONO_TYPE_I4";
4593 return "MONO_TYPE_U4";
4595 return "MONO_TYPE_I8";
4597 return "MONO_TYPE_U8";
4599 return "MONO_TYPE_R4";
4601 return "MONO_TYPE_R8";
4602 case MONO_TYPE_STRING:
4603 return "MONO_TYPE_STRING";
4605 return "MONO_TYPE_PTR";
4606 case MONO_TYPE_BYREF:
4607 return "MONO_TYPE_BYREF";
4608 case MONO_TYPE_VALUETYPE:
4609 return "MONO_TYPE_VALUETYPE";
4610 case MONO_TYPE_CLASS:
4611 return "MONO_TYPE_CLASS";
4613 return "MONO_TYPE_VAR";
4614 case MONO_TYPE_ARRAY:
4615 return "MONO_TYPE_ARRAY";
4616 case MONO_TYPE_GENERICINST:
4617 return "MONO_TYPE_GENERICINST";
4618 case MONO_TYPE_TYPEDBYREF:
4619 return "MONO_TYPE_TYPEDBYREF";
4621 return "MONO_TYPE_I";
4623 return "MONO_TYPE_U";
4624 case MONO_TYPE_FNPTR:
4625 return "MONO_TYPE_FNPTR";
4626 case MONO_TYPE_OBJECT:
4627 return "MONO_TYPE_OBJECT";
4628 case MONO_TYPE_SZARRAY:
4629 return "MONO_TYPE_SZARRAY";
4630 case MONO_TYPE_MVAR:
4631 return "MONO_TYPE_MVAR";
4632 case MONO_TYPE_CMOD_REQD:
4633 return "MONO_TYPE_CMOD_REQD";
4634 case MONO_TYPE_CMOD_OPT:
4635 return "MONO_TYPE_CMOD_OPT";
4636 case MONO_TYPE_INTERNAL:
4637 return "MONO_TYPE_INTERNAL";
4638 case MONO_TYPE_MODIFIER:
4639 return "MONO_TYPE_MODIFIER";
4640 case MONO_TYPE_SENTINEL:
4641 return "MONO_TYPE_SENTINEL";
4642 case MONO_TYPE_PINNED:
4643 return "MONO_TYPE_PINNED";
4651 /*------------------------------------------------------------------*/
4653 /* Name - mono_arch_call_opcode */
4655 /* Function - Take the arguments and generate the arch-specific */
4656 /* instructions to properly call the function. This */
4657 /* includes pushing, moving argments to the correct */
4660 * This method is called during converting method to IR
4661 * We need to generate IR ints to follow calling convention
4662 * cfg - points to currently compiled unit
4664 * call - points to structure that describes what we are going to
4665 * call (at least number of parameters required for the call)
4668 * On return we need to pass back modified call structure
4670 /*------------------------------------------------------------------*/
4673 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4674 MonoCallInst *call, int is_virtual)
4677 MonoMethodSignature *sig;
4682 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4684 sig = call->signature;
4685 n = sig->param_count + sig->hasthis;
4687 // Collect info about method we age going to call
4688 cinfo = get_call_info (sig, sig->pinvoke);
4690 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4691 sig->pinvoke ? "PInvoke" : "Managed",
4692 sig->param_count, sig->hasthis,
4693 CvtMonoType(sig->ret->type), sig->ret->type);
4695 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4696 cfg->arch.params_stack_size = cinfo->stack_usage;
4698 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4699 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4701 for (i = 0; i < n; ++i)
4703 ArgInfo *ainfo = cinfo->args + i;
4705 /* Emit the signature cookie just before the implicit arguments
4707 if (!sig->pinvoke &&
4708 (sig->call_convention == MONO_CALL_VARARG) &&
4711 MonoMethodSignature *tmp_sig;
4714 /* FIXME: Add support for signature tokens to AOT */
4715 cfg->disable_aot = TRUE;
4716 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4719 * mono_ArgIterator_Setup assumes the signature cookie is
4720 * passed first and all the arguments which were before it are
4721 * passed on the stack after the signature. So compensate by
4722 * passing a different signature.
4724 tmp_sig = mono_metadata_signature_dup (call->signature);
4725 tmp_sig->param_count -= call->signature->sentinelpos;
4726 tmp_sig->sentinelpos = 0;
4727 memcpy (tmp_sig->params,
4728 call->signature->params + call->signature->sentinelpos,
4729 tmp_sig->param_count * sizeof (MonoType*));
4731 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4732 sig_arg->inst_p0 = tmp_sig;
4734 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4735 arg->inst_left = sig_arg;
4736 arg->type = STACK_PTR;
4738 /* prepend, so they get reversed */
4739 arg->next = call->out_args;
4740 call->out_args = arg;
4743 if (is_virtual && i == 0) {
4744 /* the argument will be attached to the call instrucion
4746 in = call->args [i];
4750 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4751 in = call->args [i];
4752 arg->cil_code = in->cil_code;
4753 arg->inst_left = in;
4754 arg->type = in->type;
4755 /* prepend, so they get reversed */
4756 arg->next = call->out_args;
4757 call->out_args = arg;
4759 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4761 if (sig->hasthis && (i == 0))
4762 arg_type = &mono_defaults.object_class->byval_arg;
4764 arg_type = sig->params [i - sig->hasthis];
4766 if ((i >= sig->hasthis) &&
4767 (MONO_TYPE_ISSTRUCT(arg_type)))
4772 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4773 size = sizeof (MonoTypedRef);
4774 align = sizeof (gpointer);
4778 size = mono_type_native_stack_size (&in->klass->byval_arg,
4781 size = mono_type_stack_size (&in->klass->byval_arg, &align);
4783 if (ainfo->storage == ArgAggregate)
4785 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4788 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4790 vtaddr = mono_compile_create_var (cfg,
4791 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4794 * Part of the structure is passed in registers.
4796 for (j = 0; j < ainfo->nregs; ++j)
4798 int offset, load_op, dest_reg, arg_storage;
4800 slot = ainfo->reg + j;
4801 load_op = CEE_LDIND_I;
4803 dest_reg = ainfo->reg + j;
4804 arg_storage = ArgInIReg;
4806 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4807 load->ssa_op = MONO_SSA_LOAD;
4808 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4810 NEW_ICONST (cfg, offset_ins, offset);
4811 MONO_INST_NEW (cfg, load2, CEE_ADD);
4812 load2->inst_left = load;
4813 load2->inst_right = offset_ins;
4815 MONO_INST_NEW (cfg, load, load_op);
4816 load->inst_left = load2;
4821 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4823 add_outarg_reg (cfg, call, set_reg, arg_storage,
4825 if (set_reg != call->out_args)
4827 set_reg->next = call->out_args;
4828 call->out_args = set_reg;
4833 * Part of the structure is passed on the stack.
4835 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4839 slot = ainfo->reg + j;
4841 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4842 load->ssa_op = MONO_SSA_LOAD;
4843 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4845 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4846 MONO_INST_NEW (cfg, load2, CEE_ADD);
4847 load2->inst_left = load;
4848 load2->inst_right = offset_ins;
4850 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4851 load->inst_left = load2;
4856 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4858 outarg->inst_left = load;
4859 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4860 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4862 if (outarg != call->out_args)
4864 outarg->next = call->out_args;
4865 call->out_args = outarg;
4869 /* Trees can't be shared so make a copy*/
4870 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4871 arg->cil_code = in->cil_code;
4872 arg->ssa_op = MONO_SSA_STORE;
4873 arg->inst_left = vtaddr;
4874 arg->inst_right = in;
4875 arg->type = in->type;
4877 /* prepend, so they get reversed */
4878 arg->next = call->out_args;
4879 call->out_args = arg;
4883 MonoInst *stack_addr;
4885 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4887 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4888 stack_addr->inst_basereg = alpha_sp;
4889 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4890 stack_addr->inst_offset = ainfo->offset;
4891 //stack_addr->inst_offset = 16 + ainfo->offset;
4892 stack_addr->inst_imm = size;
4894 arg->opcode = OP_OUTARG_VT;
4895 arg->inst_right = stack_addr;
4899 arg->opcode = OP_OUTARG_VT;
4900 arg->klass = in->klass;
4901 arg->backend.is_pinvoke = sig->pinvoke;
4902 arg->inst_imm = size; */
4906 CFG_DEBUG(3) g_print("simple\n");
4908 switch (ainfo->storage)
4911 add_outarg_reg (cfg, call, arg, ainfo->storage,
4915 arg->opcode = OP_OUTARG;
4916 //arg->dreg = -((n - i) * 8);
4917 arg->dreg = ainfo->offset;
4918 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4920 if (!sig->params[i-sig->hasthis]->byref) {
4921 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4922 arg->opcode = OP_OUTARG_R4;
4924 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4925 arg->opcode = OP_OUTARG_R8;
4929 case ArgInDoubleReg:
4930 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4933 g_assert_not_reached ();
4939 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4941 if (cinfo->ret.storage == ArgValuetypeInReg) {
4942 MonoInst *zero_inst;
4944 * After the call, the struct is in registers, but needs to be saved
4945 to the memory pointed
4946 * to by vt_arg in this_vret_args. This means that vt_ar
4947 g needs to be saved somewhere
4948 * before calling the function. So we add a dummy instru
4949 ction to represent pushing the
4950 * struct return address to the stack. The return addres
4951 s will be saved to this stack slot
4952 * by the code emitted in this_vret_args.
4954 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4955 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
4956 zero_inst->inst_p0 = 0;
4957 arg->inst_left = zero_inst;
4958 arg->type = STACK_PTR;
4959 /* prepend, so they get reversed */
4960 arg->next = call->out_args;
4961 call->out_args = arg;
4964 /* if the function returns a struct, the called method a
4965 lready does a ret $0x4 */
4966 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4967 ; //cinfo->stack_usage -= 4;
4970 // stack_usage shows how much stack we would need to do the call
4971 // (for example for params that we pass on stack
4972 call->stack_usage = cinfo->stack_usage;
4974 // Save all used regs to do the call in compile unit structure
4975 cfg->used_int_regs |= call->used_iregs;
4982 /*========================= End of Function ========================*/
4984 /*------------------------------------------------------------------*/
4986 /* Name - mono_arch_break */
4988 /* Function - Process a "break" operation for debugging. */
4990 /*------------------------------------------------------------------*/
4993 mono_arch_break(void) {
4997 /*------------------------------------------------------------------*/
4999 /* Name - mono_arch_register_lowlevel_calls */
5001 /* Function - Register routines to help with --trace operation. */
5003 /*------------------------------------------------------------------*/
5006 mono_arch_register_lowlevel_calls (void)
5008 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
5010 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
5011 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
5015 /*========================= End of Function ========================*/
5017 /*------------------------------------------------------------------*/
5019 /* Name - mono_arch_global_int_regs */
5021 /* Function - Return a list of usable integer registers. */
5023 /*------------------------------------------------------------------*/
5026 mono_arch_get_global_int_regs (MonoCompile *cfg)
5030 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5032 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5033 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5034 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5035 regs = g_list_prepend (regs, (gpointer)alpha_r12);
5036 regs = g_list_prepend (regs, (gpointer)alpha_r13);
5037 regs = g_list_prepend (regs, (gpointer)alpha_r14);
5042 /*========================= End of Function ========================*/
5045 is_regsize_var (MonoType *t)
5050 t = mono_type_get_underlying_type (t);
5061 case MONO_TYPE_FNPTR:
5062 case MONO_TYPE_BOOLEAN:
5064 case MONO_TYPE_OBJECT:
5065 case MONO_TYPE_STRING:
5066 case MONO_TYPE_CLASS:
5067 case MONO_TYPE_SZARRAY:
5068 case MONO_TYPE_ARRAY:
5070 case MONO_TYPE_VALUETYPE:
5080 /*------------------------------------------------------------------*/
5082 /* Name - mono_arch_get_allocatable_int_vars */
5086 /*------------------------------------------------------------------*/
5089 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
5093 MonoMethodSignature *sig;
5094 MonoMethodHeader *header;
5097 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5099 header = mono_method_get_header (cfg->method);
5101 sig = mono_method_signature (cfg->method);
5103 cinfo = get_call_info (sig, FALSE);
5105 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5107 MonoInst *ins = cfg->varinfo [i];
5109 ArgInfo *ainfo = &cinfo->args [i];
5112 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5115 // if (ainfo->storage == ArgInIReg) {
5116 // /* The input registers are non-volatile */
5117 // ins->opcode = OP_REGVAR;
5118 //ins->dreg = 32 + ainfo->reg;
5122 for (i = 0; i < cfg->num_varinfo; i++)
5124 MonoInst *ins = cfg->varinfo [i];
5125 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
5128 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
5132 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
5133 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
5136 if (is_regsize_var (ins->inst_vtype))
5138 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
5139 g_assert (i == vmv->idx);
5140 vars = g_list_prepend (vars, vmv);
5144 vars = mono_varlist_sort (cfg, vars, 0);
5149 /*========================= End of Function ========================*/
5151 /*------------------------------------------------------------------*/
5153 /* Name - mono_arch_get_domain_intrinsic */
5159 /*------------------------------------------------------------------*/
5162 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5166 if (appdomain_tls_offset == -1)
5169 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5170 ins->inst_offset = appdomain_tls_offset;
5174 /*========================= End of Function ========================*/
5176 /*------------------------------------------------------------------*/
5178 /* Name - mono_arch_get_thread_intrinsic */
5184 /*------------------------------------------------------------------*/
5187 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5191 if (thread_tls_offset == -1)
5194 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5195 ins->inst_offset = thread_tls_offset;
5199 /*========================= End of Function ========================*/
5201 /*------------------------------------------------------------------*/
5203 /* Name - mono_arch_get_inst_for_method */
5205 /* Function - Check for opcodes we can handle directly in */
5208 /*------------------------------------------------------------------*/
5211 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5212 MonoMethodSignature *fsig, MonoInst **args)
5214 MonoInst *ins = NULL;
5216 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5218 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5220 if (cmethod->klass == mono_defaults.thread_class &&
5221 strcmp (cmethod->name, "MemoryBarrier") == 0) {
5222 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5228 /*========================= End of Function ========================*/
5230 /*------------------------------------------------------------------*/
5232 /* Name - mono_arch_create_class_init_trampoline */
5234 /* Function - Creates a trampoline function to run a type init- */
5235 /* ializer. If the trampoline is called, it calls */
5236 /* mono_runtime_class_init with the given vtable, */
5237 /* then patches the caller code so it does not get */
5238 /* called any more. */
5240 /* Parameter - vtable - The type to initialize */
5242 /* Returns - A pointer to the newly created code */
5244 /*------------------------------------------------------------------*/
5247 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5249 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5251 NOT_IMPLEMENTED("mono_arch_create_class_init_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
5256 /*------------------------------------------------------------------*/
5258 /* Name - mono_arch_instrument_prolog */
5260 /* Function - Create an "instrumented" prolog. */
5262 /*------------------------------------------------------------------*/
5265 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5266 gboolean enable_arguments)
5268 unsigned int *code = p;
5271 CallInfo *cinfo = NULL;
5272 MonoMethodSignature *sig;
5274 int i, n, stack_area = 0;
5275 AlphaGotData ge_data;
5277 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5279 /* Keep this in sync with mono_arch_get_argument_info */
5280 if (enable_arguments)
5282 /* Allocate a new area on the stack and save arguments there */
5283 sig = mono_method_signature (cfg->method);
5285 cinfo = get_call_info (sig, FALSE);
5287 n = sig->param_count + sig->hasthis;
5289 stack_area = ALIGN_TO (n * 8, 8);
5291 // Correct stack by calculated value
5293 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5295 for (i = 0; i < n; ++i)
5297 inst = cfg->varinfo [i];
5299 if (inst->opcode == OP_REGVAR)
5301 switch(cinfo->args[i].storage)
5303 case ArgInDoubleReg:
5304 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5307 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5310 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5315 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5316 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5321 offset = (char *)code - (char *)cfg->native_code;
5323 ge_data.data.p = cfg->method;
5325 add_got_entry(cfg, GT_PTR, ge_data,
5326 (char *)code - (char *)cfg->native_code,
5327 MONO_PATCH_INFO_METHODCONST, cfg->method);
5328 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5330 alpha_mov1(code, alpha_sp, alpha_a1);
5332 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5334 if (enable_arguments)
5336 // Correct stack back by calculated value
5338 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5346 /*========================= End of Function ========================*/
5356 /*------------------------------------------------------------------*/
5358 /* Name - mono_arch_instrument_epilog */
5360 /* Function - Create an epilog that will handle the returned */
5361 /* values used in instrumentation. */
5363 /*------------------------------------------------------------------*/
5366 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p,
5367 gboolean enable_arguments)
5369 unsigned int *code = p;
5370 int save_mode = SAVE_NONE;
5372 MonoMethod *method = cfg->method;
5373 AlphaGotData ge_data;
5374 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5376 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5380 case MONO_TYPE_VOID:
5381 /* special case string .ctor icall */
5382 if (strcmp (".ctor", method->name) &&
5383 method->klass == mono_defaults.string_class)
5384 save_mode = SAVE_R0;
5386 save_mode = SAVE_NONE;
5390 save_mode = SAVE_R0;
5394 save_mode = SAVE_XMM;
5396 case MONO_TYPE_VALUETYPE:
5397 save_mode = SAVE_STRUCT;
5400 save_mode = SAVE_R0;
5404 /* Save the result and copy it into the proper argument register */
5408 alpha_lda(code, alpha_sp, alpha_sp, -8);
5409 alpha_stq(code, alpha_r0, alpha_sp, 0);
5411 if (enable_arguments)
5412 alpha_mov1(code, alpha_r0, alpha_a1);
5417 if (enable_arguments)
5418 alpha_lda(code, alpha_a1, alpha_zero, 0);
5422 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5423 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5425 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5427 * The result is already in the proper argument register so no copying
5434 g_assert_not_reached ();
5437 offset = (char *)code - (char *)cfg->native_code;
5439 ge_data.data.p = cfg->method;
5441 add_got_entry(cfg, GT_PTR, ge_data,
5442 (char *)code - (char *)cfg->native_code,
5443 MONO_PATCH_INFO_METHODCONST, cfg->method);
5445 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5447 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5449 /* Restore result */
5453 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5454 alpha_lda(code, alpha_sp, alpha_sp, 8);
5460 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5461 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5462 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5467 g_assert_not_reached ();
5473 /*========================= End of Function ========================*/
5475 /*------------------------------------------------------------------*/
5477 /* Name - mono_arch_allocate_vars */
5479 /* Function - Set var information according to the calling */
5480 /* convention for Alpha. The local var stuff should */
5481 /* most likely be split in another method. */
5483 /* Parameter - @m - Compile unit. */
5485 * This method is called right before working with BBs. Conversion to
5486 * IR was done and some analises what registers would be used.
5487 * Collect info about registers we used - if we want to use a register
5488 * we need to allocate space for it and save on the stack in method
5491 * Alpha calling convertion:
5492 * FP -> Stack top <- SP
5493 * 0: Stack params to call others
5495 * RA <- arch.params_stack_size
5498 * [LMF info] <- arch.lmf_offset
5500 * [possible return values allocated on stack]
5504 * . caller saved regs <- arch.reg_save_area_offset
5505 * . a0 <- arch.args_save_area_offset
5511 * ------------------------
5512 * . a6 - passed args on stack
5515 /*------------------------------------------------------------------*/
5518 mono_arch_allocate_vars (MonoCompile *cfg)
5520 MonoMethodSignature *sig;
5521 MonoMethodHeader *header;
5523 int i, offset = 0, a_off = 0;
5524 guint32 locals_stack_size, locals_stack_align = 0;
5528 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5530 header = mono_method_get_header (cfg->method);
5532 sig = mono_method_signature (cfg->method);
5534 cinfo = get_call_info (sig, FALSE);
5536 /* if (cfg->arch.omit_fp) {
5537 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5538 cfg->frame_reg = AMD64_RSP;
5543 /* Locals are allocated forwards from FP. After
5544 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5545 * (starting from offset 16).
5546 * FIXME: Check there Arg6...Argn are supposed to be
5548 cfg->frame_reg = alpha_fp;
5549 // offset = MONO_ALPHA_VARS_OFFSET;
5552 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5553 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5554 offset += cfg->arch.params_stack_size;
5556 offset += 16; // Size to save RA & FP
5558 if (cfg->method->save_lmf)
5560 /* Reserve stack space for saving LMF + argument regs */
5561 guint32 size = sizeof (MonoLMF);
5563 //if (lmf_tls_offset == -1)
5564 // /* Need to save argument regs too */
5565 // size += (AMD64_NREG * 8) + (8 * 8);
5567 cfg->arch.lmf_offset = offset;
5570 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5571 cfg->method->name, cfg->arch.lmf_offset, size);
5574 if (sig->ret->type != MONO_TYPE_VOID)
5576 switch (cinfo->ret.storage)
5580 case ArgInDoubleReg:
5581 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5582 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5583 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5585 /* The register is volatile */
5586 cfg->ret->opcode = OP_REGOFFSET;
5587 cfg->ret->inst_basereg = cfg->frame_reg;
5589 /*if (cfg->arch.omit_fp) {
5590 cfg->ret->inst_offset = offset;
5594 cfg->ret->inst_offset = offset;
5595 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5601 cfg->ret->opcode = OP_REGVAR;
5602 cfg->ret->inst_c0 = cinfo->ret.reg;
5605 case ArgValuetypeInReg:
5606 /* Allocate a local to hold the result, the epilog will
5607 copy it to the correct place */
5608 // g_assert (!cfg->arch.omit_fp);
5610 cfg->ret->opcode = OP_REGOFFSET;
5611 cfg->ret->inst_basereg = cfg->frame_reg;
5612 cfg->ret->inst_offset = offset;
5615 g_assert_not_reached ();
5617 cfg->ret->dreg = cfg->ret->inst_c0;
5620 /* Allocate locals */
5621 offsets = mono_allocate_stack_slots_full (cfg,
5622 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5624 &locals_stack_align);
5626 //g_assert((locals_stack_size % 8) == 0);
5627 if (locals_stack_size % 8)
5629 locals_stack_size += 8 - (locals_stack_size % 8);
5632 /* if (locals_stack_align)
5634 offset += (locals_stack_align - 1);
5635 offset &= ~(locals_stack_align - 1);
5639 cfg->arch.localloc_offset = offset;
5641 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5642 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5643 locals_stack_size, locals_stack_size);
5645 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5647 if (offsets [i] != -1) {
5648 MonoInst *inst = cfg->varinfo [i];
5649 inst->opcode = OP_REGOFFSET;
5650 inst->inst_basereg = cfg->frame_reg;
5651 //if (cfg->arch.omit_fp)
5652 // inst->inst_offset = (offset + offsets [i]);
5654 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5656 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5657 CFG_DEBUG(3) mono_print_tree_nl (inst);
5661 // TODO check how offsets[i] are calculated
5662 // it seems they are points to the end on data. Like 8, but it actually - 0
5664 offset += locals_stack_size; //+8;
5666 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5667 // g_assert (!cfg->arch.omit_fp);
5668 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5669 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5672 // Save offset for caller saved regs
5673 cfg->arch.reg_save_area_offset = offset;
5675 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5677 // Reserve space for caller saved registers
5678 for (i = 0; i < MONO_MAX_IREGS; ++i)
5679 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5680 (cfg->used_int_regs & (1 << i)))
5682 offset += sizeof (gpointer);
5685 // Save offset to args regs
5686 cfg->arch.args_save_area_offset = offset;
5688 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5690 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5692 ArgInfo *ainfo = &cinfo->args [i];
5694 switch(ainfo->storage)
5698 case ArgInDoubleReg:
5699 offset += sizeof (gpointer);
5702 offset += ainfo->nregs * sizeof (gpointer);
5709 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5712 // Reserve space for method params
5713 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5715 inst = cfg->varinfo [i];
5717 if (inst->opcode != OP_REGVAR)
5719 ArgInfo *ainfo = &cinfo->args [i];
5720 gboolean inreg = TRUE;
5723 if (sig->hasthis && (i == 0))
5724 arg_type = &mono_defaults.object_class->byval_arg;
5726 arg_type = sig->params [i - sig->hasthis];
5728 /* FIXME: Allocate volatile arguments to registers */
5729 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5733 * Under AMD64, all registers used to pass arguments to functions
5734 * are volatile across calls. For Alpha too.
5735 * FIXME: Optimize this.
5739 if (inreg && (ainfo->storage == ArgInIReg)
5740 //&& cfg->used_int_regs & (1 << ainfo->reg)
5744 if (//(ainfo->storage == ArgInIReg) ||
5745 (ainfo->storage == ArgInFloatReg) ||
5746 (ainfo->storage == ArgInDoubleReg) ||
5747 (ainfo->storage == ArgValuetypeInReg))
5750 inst->opcode = OP_REGOFFSET;
5752 switch (ainfo->storage)
5756 case ArgInDoubleReg:
5757 inst->opcode = OP_REGVAR;
5758 inst->dreg = ainfo->reg;
5761 // g_assert (!cfg->arch.omit_fp);
5762 inst->opcode = OP_REGOFFSET;
5763 inst->inst_basereg = cfg->frame_reg;
5765 // "offset" here will point to the end of
5766 // array of saved ret,locals, args
5767 // Ideally it would point to "a7"
5768 inst->inst_offset = ainfo->offset + offset;
5770 case ArgValuetypeInReg:
5777 NOT_IMPLEMENTED("");
5780 if (!inreg && (ainfo->storage != ArgOnStack))
5782 inst->opcode = OP_REGOFFSET;
5783 inst->inst_basereg = cfg->frame_reg;
5785 /* These arguments are saved to the stack in the prolog */
5786 /*if (cfg->arch.omit_fp) {
5787 inst->inst_offset = offset;
5788 offset += (ainfo->storage == ArgValuetypeInReg) ?
5789 2 * sizeof (gpointer) : sizeof (gpointer);
5792 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5793 // 2 * sizeof (gpointer) : sizeof (gpointer);
5795 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5796 switch(ainfo->storage)
5799 a_off += ainfo->nslots * 8;
5802 a_off += sizeof (gpointer);
5804 // (/*(ainfo->reg - 16)*/ i * 8);
5810 cfg->stack_offset = offset;
5815 /*========================= End of Function ========================*/
5817 /*------------------------------------------------------------------*/
5819 /* Name - mono_arch_print_tree */
5821 /* Function - Print platform-specific opcode details. */
5823 /* Returns - 1 - opcode details have been printed */
5824 /* 0 - opcode details have not been printed */
5826 /*------------------------------------------------------------------*/
5829 mono_arch_print_tree (MonoInst *tree, int arity)
5833 ALPHA_DEBUG("mono_arch_print_tree");
5835 switch (tree->opcode) {
5842 /*========================= End of Function ========================*/
5846 ** mono_arch_get_vcall_slot_addr
5847 ** is called by mono_magic_trampoline to determine that the JIT compiled
5848 ** method is called via vtable slot. We need to analyze call sequence
5849 ** and determine that. In case it is true - we need to return address
5852 ** code - points to the next instruction after call
5853 ** reg - points to saved regs before the call (this is done
5854 ** by mono_magic_trampoline function
5858 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
5860 unsigned int *pc = (unsigned int *)code;
5862 int start_index = -2;
5864 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5867 // Check if we have parameters on stack
5868 if (pc[-2] & 0xFFFF0000 == 0x23DE0000) // lda sp,-n(sp)
5871 // Check for (call_membase):
5872 // -4: mov v0,a0 - load this ???
5873 // -3: ldq v0,0(v0) - load vtable
5874 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5875 if ((pc[start_index-1] & 0xFC00FFFF) == 0xA4000000 &&
5876 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5879 disp = pc[start_index] & 0xFFFF;
5880 reg = (pc[start_index-1] >> AXP_REG1_SHIFT) & AXP_REG_MASK;
5881 //reg = 0; // For now
5883 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5885 return (gpointer)(((guint64)(regs [reg])) + disp);
5888 // Check for interface call
5891 // -3: ldq v0,-n(v0)
5892 // -2: ldq t12,0(v0)
5893 if ((pc[start_index-2] & 0xFC00FFFF) == 0xA4000000 &&
5894 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5895 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5898 disp = pc[start_index] & 0xFFFF;;
5901 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5903 return (gpointer)(((guint64)(regs [reg])) + disp);
5911 mono_arch_get_patch_offset (guint8 *code)