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;
86 static const char*const * ins_spec = alpha_desc;
88 static gboolean tls_offset_inited = FALSE;
90 static int appdomain_tls_offset = -1,
92 thread_tls_offset = -1;
94 pthread_key_t lmf_addr_key;
96 gboolean lmf_addr_key_inited = FALSE;
98 /*====================== End of Global Variables ===================*/
100 static void mono_arch_break(void);
101 gpointer mono_arch_get_lmf_addr (void);
108 ArgValuetypeInReg, // ??
119 /* Only if storage == ArgAggregate */
121 //AggregateType atype; // So far use only AggregateNormal
127 // guint32 struct_ret; /// ???
131 gboolean need_stack_align;
138 static CallInfo* get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke);
139 static unsigned int *emit_call(MonoCompile *cfg, unsigned int *code,
140 guint32 patch_type, gconstpointer data);
143 static int param_regs [] =
150 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
153 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
155 ainfo->offset = *stack_size;
157 if (*gr >= PARAM_REGS)
159 ainfo->storage = ArgOnStack;
160 (*stack_size) += sizeof (gpointer);
164 ainfo->storage = ArgInIReg;
165 ainfo->reg = param_regs [*gr];
170 #define FLOAT_PARAM_REGS 6
171 static int fparam_regs [] = { alpha_fa0, alpha_fa1, alpha_fa2, alpha_fa3,
172 alpha_fa4, alpha_fa5 };
175 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo,
178 ainfo->offset = *stack_size;
180 if (*gr >= FLOAT_PARAM_REGS)
182 ainfo->storage = ArgOnStack;
183 (*stack_size) += sizeof (gpointer);
187 /* A double register */
189 ainfo->storage = ArgInDoubleReg;
191 ainfo->storage = ArgInFloatReg;
193 ainfo->reg = fparam_regs [*gr];
199 add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
201 guint32 *gr, guint32 *fr, guint32 *stack_size)
205 MonoMarshalType *info;
206 gboolean is_hfa = TRUE;
207 guint32 hfa_type = 0;
209 klass = mono_class_from_mono_type (type);
210 if (type->type == MONO_TYPE_TYPEDBYREF)
211 size = 3 * sizeof (gpointer);
212 else if (sig->pinvoke)
213 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
215 size = mono_type_stack_size (&klass->byval_arg, NULL);
217 if (!sig->pinvoke || (size == 0) || is_return) {
218 /* Allways pass in memory */
219 ainfo->offset = *stack_size;
220 *stack_size += ALIGN_TO (size, 8);
221 ainfo->storage = ArgOnStack;
226 info = mono_marshal_load_type_info (klass);
229 ainfo->storage = ArgAggregate;
230 //ainfo->atype = AggregateNormal;
233 /* This also handles returning of TypedByRef used by some icalls */
236 ainfo->reg = IA64_R8;
237 ainfo->nregs = (size + 7) / 8;
238 ainfo->nslots = ainfo->nregs;
245 ainfo->reg = param_regs [*gr];
246 ainfo->offset = *stack_size;
247 ainfo->nslots = (size + 7) / 8;
249 if (((*gr) + ainfo->nslots) <= 6) {
250 /* Fits entirely in registers */
251 ainfo->nregs = ainfo->nslots;
252 (*gr) += ainfo->nregs;
256 ainfo->nregs = 6 - (*gr);
258 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
262 // This function is called from mono_arch_call_opcode and
263 // should determine which registers will be used to do the call
264 // For Alpha we could calculate number of parameter used for each
265 // call and allocate space in stack only for whose "a0-a5" registers
266 // that will be used in calls
268 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
269 ArgStorage storage, int reg, MonoInst *tree)
274 arg->opcode = OP_OUTARG_REG;
275 arg->inst_left = tree;
276 arg->inst_right = (MonoInst*)call;
277 arg->backend.reg3 = reg;
278 call->used_iregs |= 1 << reg;
281 arg->opcode = OP_OUTARG_FREG;
282 arg->inst_left = tree;
283 arg->inst_right = (MonoInst*)call;
284 arg->backend.reg3 = reg;
285 call->used_fregs |= 1 << reg;
288 arg->opcode = OP_OUTARG_FREG;
289 arg->inst_left = tree;
290 arg->inst_right = (MonoInst*)call;
291 arg->backend.reg3 = reg;
292 call->used_fregs |= 1 << reg;
295 g_assert_not_reached ();
300 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
305 bb->code = to_insert;
306 to_insert->next = ins;
310 to_insert->next = ins->next;
311 ins->next = to_insert;
315 static void add_got_entry(MonoCompile *cfg, AlphaGotType ge_type,
316 AlphaGotData ge_data,
317 int ip, MonoJumpInfoType type, gconstpointer target)
319 AlphaGotEntry *AGE = mono_mempool_alloc (cfg->mempool,
320 sizeof (AlphaGotEntry));
327 AGE->value.data.i = ge_data.data.i;
330 AGE->value.data.l = ge_data.data.l;
333 AGE->value.data.p = ge_data.data.p;
336 AGE->value.data.f = ge_data.data.f;
339 AGE->value.data.d = ge_data.data.d;
342 AGE->value.data.l = ip;
348 if (type != MONO_PATCH_INFO_NONE)
350 mono_add_patch_info(cfg, ip, type, target);
351 AGE->patch_info = cfg->patch_info;
356 if (AGE->type != GT_LD_GTADDR)
358 mono_add_patch_info(cfg, ip, MONO_PATCH_INFO_GOT_OFFSET, 0);
359 AGE->got_patch_info = cfg->patch_info;
362 AGE->next = cfg->arch.got_data;
364 cfg->arch.got_data = AGE;
367 /*------------------------------------------------------------------*/
369 /* Name - mono_arch_create_vars */
376 * cfg - pointer to compile unit
379 * This method is called right before starting converting compiled
380 * method to IR. I guess we could find out how many arguments we
381 * should expect, what type and what return value would be.
382 * After that we could correct "cfg" structure, or "arch" part of
386 /*------------------------------------------------------------------*/
389 mono_arch_create_vars (MonoCompile *cfg)
391 MonoMethodSignature *sig;
394 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
396 sig = mono_method_signature (cfg->method);
398 cinfo = get_call_info (sig, FALSE);
400 if (cinfo->ret.storage == ArgValuetypeInReg)
401 cfg->ret_var_is_local = TRUE;
407 /*------------------------------------------------------------------*/
409 /* Name - mono_arch_get_lmf_addr */
415 /*------------------------------------------------------------------*/
418 mono_arch_get_lmf_addr (void)
420 ALPHA_DEBUG("mono_arch_get_lmf_addr");
422 return pthread_getspecific (lmf_addr_key);
425 /*========================= End of Function ========================*/
427 /*------------------------------------------------------------------*/
429 /* Name - mono_arch_free_jit_tls_data */
431 /* Function - Free tls data. */
433 /*------------------------------------------------------------------*/
436 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
438 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
441 /*========================= End of Function ========================*/
444 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
446 MonoInst *ins, *last_ins = NULL;
459 * OP_MOVE reg, reg except special case (mov at, at)
461 if (ins->dreg == ins->sreg1 &&
462 ins->dreg != alpha_at)
465 last_ins->next = ins->next;
477 if (last_ins && last_ins->opcode == OP_MOVE &&
478 ins->sreg1 == last_ins->dreg &&
479 last_ins->dreg != alpha_at &&
480 ins->dreg == last_ins->sreg1)
482 last_ins->next = ins->next;
491 /* remove unnecessary multiplication with 1 */
492 if (ins->inst_imm == 1)
494 if (ins->dreg != ins->sreg1)
496 ins->opcode = OP_MOVE;
500 last_ins->next = ins->next;
508 case OP_LOADI8_MEMBASE:
510 * Note: if reg1 = reg2 the load op is removed
512 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
513 * OP_LOADI8_MEMBASE offset(basereg), reg2
515 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
518 if (last_ins && (last_ins->opcode == OP_STOREI8_MEMBASE_REG) &&
519 ins->inst_basereg == last_ins->inst_destbasereg &&
520 ins->inst_offset == last_ins->inst_offset)
522 if (ins->dreg == last_ins->sreg1)
524 last_ins->next = ins->next;
531 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
532 ins->opcode = OP_MOVE;
533 ins->sreg1 = last_ins->sreg1;
539 case OP_LOAD_MEMBASE:
540 case OP_LOADI4_MEMBASE:
542 * Note: if reg1 = reg2 the load op is removed
544 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
545 * OP_LOAD_MEMBASE offset(basereg), reg2
547 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
550 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
551 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
552 ins->inst_basereg == last_ins->inst_destbasereg &&
553 ins->inst_offset == last_ins->inst_offset)
555 if (ins->dreg == last_ins->sreg1)
557 last_ins->next = ins->next;
564 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
565 ins->opcode = OP_MOVE;
566 ins->sreg1 = last_ins->sreg1;
570 * Note: reg1 must be different from the basereg in the second load
571 * Note: if reg1 = reg2 is equal then second load is removed
573 * OP_LOAD_MEMBASE offset(basereg), reg1
574 * OP_LOAD_MEMBASE offset(basereg), reg2
576 * OP_LOAD_MEMBASE offset(basereg), reg1
580 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
581 || last_ins->opcode == OP_LOAD_MEMBASE) &&
582 ins->inst_basereg != last_ins->dreg &&
583 ins->inst_basereg == last_ins->inst_basereg &&
584 ins->inst_offset == last_ins->inst_offset)
586 if (ins->dreg == last_ins->dreg)
588 last_ins->next = ins->next;
595 ins->opcode = OP_MOVE;
596 ins->sreg1 = last_ins->dreg;
599 //g_assert_not_reached ();
609 bb->last_ins = last_ins;
614 // Convert to opposite branch opcode
615 static guint16 cvt_branch_opcode(guint16 opcode)
620 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
625 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
629 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
633 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
637 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
641 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
645 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
649 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
653 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
657 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
661 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
665 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
669 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
673 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
677 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
681 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
685 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
689 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
693 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
697 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
701 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
705 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
709 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
713 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
717 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
724 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
729 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
731 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
737 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
748 return OP_ALPHA_CMP_EQ;
750 return OP_ALPHA_CMP_ULE;
752 return OP_ALPHA_CMP_LE;
754 return OP_ALPHA_CMP_LT;
756 return OP_ALPHA_CMP_ULT;
761 case OP_ICOMPARE_IMM:
767 return OP_ALPHA_CMP_IMM_EQ;
769 return OP_ALPHA_CMP_IMM_ULE;
771 return OP_ALPHA_CMP_IMM_LE;
773 return OP_ALPHA_CMP_IMM_LT;
775 return OP_ALPHA_CMP_IMM_ULT;
780 g_assert_not_reached();
785 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
787 // Instead of compare+b<cond>,
788 // Alpha has compare<cond>+br<cond>
789 // we need to convert
790 // Handle floating compare here too
796 // Convert cmp + beq -> cmpeq + bne
797 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
798 next->opcode = cvt_branch_opcode(next->opcode);
803 // cmp + ibne_un -> cmpeq + beq
804 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
805 next->opcode = cvt_branch_opcode(next->opcode);
810 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
811 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
812 next->opcode = cvt_branch_opcode(next->opcode);
817 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
818 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
819 next->opcode = cvt_branch_opcode(next->opcode);
824 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
825 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
826 next->opcode = cvt_branch_opcode(next->opcode);
831 // lcmp + blt.un -> cmpult + bne
832 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
833 next->opcode = cvt_branch_opcode(next->opcode);
838 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
839 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
840 next->opcode = cvt_branch_opcode(next->opcode);
845 //lcmp + bge.un -> cmpult + beq
846 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
847 next->opcode = cvt_branch_opcode(next->opcode);
852 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
853 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
854 next->opcode = cvt_branch_opcode(next->opcode);
859 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
860 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
861 next->opcode = cvt_branch_opcode(next->opcode);
867 // cmp + cgt_un -> cmpule + beq
868 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
873 // cmp + iceq -> cmpeq + bne
874 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
879 // cmp + int_cgt -> cmple + beq
880 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
885 // cmp + int_clt -> cmplt + bne
886 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
891 // cmp + int_clt_un -> cmpult + bne
892 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
896 // The conditional exceptions will be handled in
897 // output_basic_blocks. Here we just determine correct
900 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
903 case OP_COND_EXC_GT_UN:
904 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
908 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
911 case OP_COND_EXC_LT_UN:
912 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
915 case OP_COND_EXC_LE_UN:
916 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
919 case OP_COND_EXC_NE_UN:
920 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
924 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
929 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
930 mono_inst_name(next->opcode), next->opcode);
932 // g_assert_not_reached();
940 * mono_arch_lowering_pass:
942 * Converts complex opcodes into simpler ones so that each IR instruction
943 * corresponds to one machine instruction.
946 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
948 MonoInst *ins, *temp, *last_ins = NULL;
953 if (bb->max_ireg > cfg->rs->next_vireg)
954 cfg->rs->next_vireg = bb->max_ireg;
955 if (bb->max_freg > cfg->rs->next_vfreg)
956 cfg->rs->next_vfreg = bb->max_freg;
959 * FIXME: Need to add more instructions, but the current machine
960 * description can't model some parts of the composite instructions like
973 NEW_INS (cfg, temp, OP_I8CONST);
974 temp->inst_c0 = ins->inst_imm;
975 temp->dreg = mono_regstate_next_int (cfg->rs);
980 ins->opcode = CEE_MUL;
983 ins->opcode = OP_LDIV;
986 ins->opcode = OP_LREM;
989 ins->opcode = OP_IDIV;
992 ins->opcode = OP_IREM;
996 ins->sreg2 = temp->dreg;
1004 // Instead of compare+b<cond>/fcompare+b<cond>,
1005 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
1006 // we need to convert
1009 cvt_cmp_branch(ins, next);
1013 case OP_COMPARE_IMM:
1014 if (!alpha_is_imm (ins->inst_imm))
1016 NEW_INS (cfg, temp, OP_I8CONST);
1017 temp->inst_c0 = ins->inst_imm;
1018 temp->dreg = mono_regstate_next_int (cfg->rs);
1019 ins->opcode = OP_COMPARE;
1020 ins->sreg2 = temp->dreg;
1022 // We should try to reevaluate new IR opcode
1028 cvt_cmp_branch(ins, next);
1032 case OP_ICOMPARE_IMM:
1033 if (!alpha_is_imm (ins->inst_imm))
1035 NEW_INS (cfg, temp, OP_ICONST);
1036 temp->inst_c0 = ins->inst_imm;
1037 temp->dreg = mono_regstate_next_int (cfg->rs);
1038 ins->opcode = OP_ICOMPARE;
1039 ins->sreg2 = temp->dreg;
1041 // We should try to reevaluate new IR opcode
1047 cvt_cmp_branch(ins, next);
1052 case OP_LOAD_MEMBASE:
1053 case OP_LOADI8_MEMBASE:
1054 if (!amd64_is_imm32 (ins->inst_offset))
1057 NEW_INS (cfg, temp, OP_I8CONST);
1058 temp->inst_c0 = ins->inst_offset;
1059 temp->dreg = mono_regstate_next_int (cfg->rs);
1060 ins->opcode = OP_AMD64_LOADI8_MEMINDEX;
1061 ins->inst_indexreg = temp->dreg;
1067 case OP_STORE_MEMBASE_IMM:
1068 case OP_STOREI8_MEMBASE_IMM:
1069 if (ins->inst_imm != 0)
1071 NEW_INS (cfg, temp, OP_I8CONST);
1072 temp->inst_c0 = ins->inst_imm;
1073 temp->dreg = mono_regstate_next_int (cfg->rs);
1074 ins->opcode = OP_STOREI8_MEMBASE_REG;
1075 ins->sreg1 = temp->dreg;
1079 case OP_STOREI4_MEMBASE_IMM:
1080 if (ins->inst_imm != 0)
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_STOREI4_MEMBASE_REG;
1087 ins->sreg1 = temp->dreg;
1091 case OP_STOREI1_MEMBASE_IMM:
1094 NEW_INS (cfg, temp, OP_ICONST);
1095 temp->inst_c0 = ins->inst_imm;
1096 temp->dreg = mono_regstate_next_int (cfg->rs);
1097 ins->opcode = OP_STOREI1_MEMBASE_REG;
1098 ins->sreg1 = temp->dreg;
1102 case OP_STOREI2_MEMBASE_IMM:
1105 NEW_INS (cfg, temp, OP_ICONST);
1106 temp->inst_c0 = ins->inst_imm;
1107 temp->dreg = mono_regstate_next_int (cfg->rs);
1108 ins->opcode = OP_STOREI2_MEMBASE_REG;
1109 ins->sreg1 = temp->dreg;
1120 case OP_ISHR_UN_IMM:
1121 if (!alpha_is_imm(ins->inst_imm))
1124 NEW_INS (cfg, temp, OP_ICONST);
1125 temp->inst_c0 = ins->inst_imm;
1126 temp->dreg = mono_regstate_next_int (cfg->rs);
1131 ins->opcode = OP_IADD;
1134 ins->opcode = OP_ISUB;
1137 ins->opcode = OP_IAND;
1140 ins->opcode = OP_IOR;
1143 ins->opcode = OP_IXOR;
1146 ins->opcode = OP_ISHL;
1149 ins->opcode = OP_ISHR;
1151 case OP_ISHR_UN_IMM:
1152 ins->opcode = OP_ISHR_UN;
1158 ins->sreg2 = temp->dreg;
1164 if (!alpha_is_imm(ins->inst_imm))
1167 NEW_INS (cfg, temp, OP_ICONST);
1168 temp->inst_c0 = ins->inst_imm;
1169 temp->dreg = mono_regstate_next_int (cfg->rs);
1174 ins->opcode = CEE_ADD;
1177 ins->opcode = CEE_SUB;
1180 ins->opcode = CEE_AND;
1183 ins->opcode = CEE_SHL;
1189 ins->sreg2 = temp->dreg;
1193 if (!alpha_is_imm(ins->inst_imm))
1196 NEW_INS(cfg, temp, OP_ICONST);
1197 temp->inst_c0 = ins->inst_imm;
1198 temp->dreg = mono_regstate_next_int(cfg->rs);
1199 ins->sreg2 = temp->dreg;
1200 ins->opcode = OP_LSHR;
1210 bb->last_ins = last_ins;
1212 bb->max_ireg = cfg->rs->next_vireg;
1213 bb->max_freg = cfg->rs->next_vfreg;
1216 /*------------------------------------------------------------------*/
1218 /* Name - mono_arch_local_regalloc. */
1220 /* Function - We first scan the list of instructions and we */
1221 /* save the liveness information of each register */
1222 /* (when the register is first used, when its value */
1223 /* is set etc.). We also reverse the list of instr- */
1224 /* uctions (in the InstList list) because assigning */
1225 /* registers backwards allows for more tricks to be */
1228 /*------------------------------------------------------------------*/
1231 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1233 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_local_regalloc");
1238 mono_arch_lowering_pass (cfg, bb);
1240 mono_local_regalloc(cfg, bb);
1243 /*========================= End of Function ========================*/
1245 #define AXP_GENERAL_REGS 6
1246 #define AXP_MIN_STACK_SIZE 24
1248 /* A typical Alpha stack frame looks like this */
1250 fun: // called from outside the module.
1251 ldgp gp,0(pv) // load the global pointer
1252 fun..ng: // called from inside the module.
1253 lda sp, -SIZE( sp ) // grow the stack downwards.
1255 stq ra, 0(sp) // save the return address.
1257 stq s0, 8(sp) // callee-saved registers.
1258 stq s1, 16(sp) // ...
1260 // Move the arguments to the argument registers...
1262 mov addr, pv // Load the callee address
1263 jsr ra, (pv) // call the method.
1264 ldgp gp, 0(ra) // restore gp
1266 // return value is in v0
1268 ldq ra, 0(sp) // free stack frame
1269 ldq s0, 8(sp) // restore callee-saved registers.
1271 ldq sp, 32(sp) // restore stack pointer
1273 ret zero, (ra), 1 // return.
1276 // our call must look like this.
1282 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1283 stq ra, SIZE-48(sp) // store ra
1284 stq fp, SIZE-40(sp) // store fp (frame pointer)
1285 stq a0, SIZE-32(sp) // store args. a0 = func
1286 stq a1, SIZE-24(sp) // a1 = retval
1287 stq a2, SIZE-16(sp) // a2 = this
1288 stq a3, SIZE-8(sp) // a3 = args
1289 mov sp, fp // set frame pointer
1309 jsr ra, (pv) // call func
1310 ldgp gp, 0(ra) // restore gp.
1311 mov v0, t1 // move return value into t1
1314 ldq t0, SIZE-24(fp) // load retval into t2
1315 stl t1, 0(t0) // store value.
1326 * emit_load_volatile_arguments:
1328 * Load volatile arguments from the stack to the original input registers.
1329 * Required before a tail call.
1331 static unsigned int*
1332 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1334 MonoMethod *method = cfg->method;
1335 MonoMethodSignature *sig;
1340 /* FIXME: Generate intermediate code instead */
1342 sig = mono_method_signature (method);
1344 cinfo = get_call_info (sig, FALSE);
1346 if (sig->ret->type != MONO_TYPE_VOID) {
1347 if ((cinfo->ret.storage == ArgInIReg) &&
1348 (cfg->ret->opcode != OP_REGVAR))
1350 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1351 cfg->ret->inst_offset);
1355 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1357 ArgInfo *ainfo = &cinfo->args [i];
1358 MonoInst *inst = cfg->varinfo [i];
1360 switch(ainfo->storage)
1363 // We need to save all used a0-a5 params
1364 //for (i=0; i<PARAM_REGS; i++)
1366 // if (i < cinfo->reg_usage)
1368 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1369 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1371 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1372 ainfo->reg, inst->inst_offset/*offset*/);
1376 case ArgInDoubleReg:
1378 // We need to save all used af0-af5 params
1379 //for (i=0; i<PARAM_REGS; i++)
1381 // if (i < cinfo->freg_usage)
1383 switch(cinfo->args[i].storage)
1386 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1387 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1389 case ArgInDoubleReg:
1390 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1391 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1397 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1398 ainfo->reg, /*offset*/inst->inst_offset);
1407 /*------------------------------------------------------------------*/
1409 /* Name - mono_arch_emit_prolog */
1411 /* Function - Create the instruction sequence for a function */
1414 * How to handle consts and method addreses:
1415 * For method we will allocate array of qword after method epiloge.
1416 * These qword will hold readonly info to method to properly to run.
1417 * For example: qword constants, method addreses
1418 * GP will point to start of data. Offsets to the data will be equal
1419 * to "address" of data - start of GP. (GP = 0 during method jiting).
1420 * GP is easily calculated from passed PV (method start address).
1421 * The patch will update GP loadings.
1422 * The GOT section should be more than 32Kb.
1423 * The patch code should put proper offset since the real position of
1424 * qword array will be known after the function epiloge.
1426 /*------------------------------------------------------------------*/
1429 mono_arch_emit_prolog (MonoCompile *cfg)
1431 MonoMethod *method = cfg->method;
1432 MonoMethodSignature *sig = mono_method_signature (method);
1433 //int alloc_size, code_size, max_offset, quad;
1436 int i, stack_size, offset;
1437 gint32 lmf_offset = cfg->arch.lmf_offset;
1439 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1441 // FIXME: Use just one field to hold calculated stack size
1442 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1443 cfg->arch.got_data = 0;
1445 cfg->code_size = 512;
1447 code = (unsigned int *)g_malloc(cfg->code_size);
1448 cfg->native_code = (void *)code;
1450 // Emit method prolog
1451 // Calculate GP from passed PV, allocate stack
1453 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1454 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1455 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1457 offset = cfg->arch.params_stack_size;
1459 /* store call convention parameters on stack */
1460 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1461 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1463 /* set the frame pointer */
1464 alpha_mov1( code, alpha_sp, alpha_fp );
1467 if (method->save_lmf)
1470 alpha_stq(code, alpha_pv, alpha_fp,
1471 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1473 alpha_stq(code, alpha_sp, alpha_fp,
1474 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1476 alpha_stq(code, alpha_fp, alpha_fp,
1477 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1479 alpha_stq(code, alpha_gp, alpha_fp,
1480 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1483 alpha_stq(code, alpha_pv, alpha_fp,
1484 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1488 offset = cfg->arch.args_save_area_offset;
1490 cinfo = get_call_info (sig, FALSE);
1492 if (sig->ret->type != MONO_TYPE_VOID)
1494 if ((cinfo->ret.storage == ArgInIReg) &&
1495 (cfg->ret->opcode != OP_REGVAR))
1497 /* Save volatile arguments to the stack */
1498 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1499 cfg->ret->inst_offset);
1503 /* Keep this in sync with emit_load_volatile_arguments */
1504 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1506 ArgInfo *ainfo = &cinfo->args [i];
1507 MonoInst *inst = cfg->varinfo [i];
1509 switch(ainfo->storage)
1512 // We need to save all used a0-a5 params
1513 //for (i=0; i<PARAM_REGS; i++)
1515 // if (i < cinfo->reg_usage)
1517 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1518 alpha_stq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1520 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1521 ainfo->reg, inst->inst_offset/*offset*/);
1527 case ArgInDoubleReg:
1529 // We need to save all used af0-af5 params
1530 //for (i=0; i<PARAM_REGS; i++)
1532 // if (i < cinfo->freg_usage)
1534 switch(cinfo->args[i].storage)
1537 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1538 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1540 case ArgInDoubleReg:
1541 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1542 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1548 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1549 ainfo->reg, /*offset*/inst->inst_offset);
1556 offset = cfg->arch.reg_save_area_offset;
1558 for (i = 0; i < MONO_MAX_IREGS; ++i)
1559 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1560 (cfg->used_int_regs & (1 << i)) &&
1561 !( ALPHA_ARGS_REGS & (1 << i)) )
1563 alpha_stq(code, i, alpha_fp, offset);
1564 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1569 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1571 if (method->save_lmf)
1574 * The call might clobber argument registers, but they are already
1575 * saved to the stack/global regs.
1578 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1579 (gpointer)"mono_get_lmf_addr");
1582 alpha_stq(code, alpha_r0, alpha_fp,
1583 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1584 // Load "previous_lmf" member of MonoLMF struct
1585 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1587 // Save it to MonoLMF struct
1588 alpha_stq(code, alpha_r1, alpha_fp,
1589 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1592 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1593 alpha_stq(code, alpha_r1, alpha_r0, 0);
1598 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1599 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1602 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1604 g_assert (cfg->code_len < cfg->code_size);
1606 return (gint8 *)code;
1609 /*========================= End of Function ========================*/
1611 /*------------------------------------------------------------------*/
1613 /* Name - mono_arch_flush_register_windows */
1619 /*------------------------------------------------------------------*/
1622 mono_arch_flush_register_windows (void)
1624 ALPHA_DEBUG("mono_arch_flush_register_windows");
1626 /*========================= End of Function ========================*/
1628 /*------------------------------------------------------------------*/
1630 /* Name - mono_arch_regalloc_cost */
1632 /* Function - Determine the cost, in the number of memory */
1633 /* references, of the action of allocating the var- */
1634 /* iable VMV into a register during global register */
1637 /* Returns - Cost */
1639 /*------------------------------------------------------------------*/
1642 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1645 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1650 /*========================= End of Function ========================*/
1654 ** This method emits call sequience
1657 static unsigned int *
1658 emit_call(MonoCompile *cfg, unsigned int *code,
1659 guint32 patch_type, gconstpointer data)
1662 AlphaGotData ge_data;
1664 offset = (char *)code - (char *)cfg->native_code;
1666 ge_data.data.p = (void *)data;
1667 add_got_entry(cfg, GT_PTR, ge_data,
1668 offset, patch_type, data);
1670 // Load call address into PV
1671 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1674 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1676 offset = (char *)code - (char *)cfg->native_code;
1679 ALPHA_LOAD_GP(offset)
1680 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1681 alpha_lda(code, alpha_gp, alpha_gp, 0);
1686 /*------------------------------------------------------------------*/
1688 /* Name - arch_get_argument_info */
1690 /* Function - Gathers information on parameters such as size, */
1691 /* alignment, and padding. arg_info should be large */
1692 /* enough to hold param_count + 1 entries. */
1694 /* Parameters - @csig - Method signature */
1695 /* @param_count - No. of parameters to consider */
1696 /* @arg_info - An array to store the result info */
1698 /* Returns - Size of the activation frame */
1700 /*------------------------------------------------------------------*/
1703 mono_arch_get_argument_info (MonoMethodSignature *csig,
1705 MonoJitArgumentInfo *arg_info)
1708 CallInfo *cinfo = get_call_info (csig, FALSE);
1709 guint32 args_size = cinfo->stack_usage;
1711 ALPHA_DEBUG("mono_arch_get_argument_info");
1713 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1716 arg_info [0].offset = 0;
1719 for (k = 0; k < param_count; k++)
1721 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1725 // The size is checked only for valuetype in trace.c
1726 arg_info [k + 1].size = 8;
1734 /*------------------------------------------------------------------*/
1736 /* Name - mono_arch_emit_epilog */
1738 /* Function - Emit the instructions for a function epilog. */
1740 /*------------------------------------------------------------------*/
1743 mono_arch_emit_epilog (MonoCompile *cfg)
1745 MonoMethod *method = cfg->method;
1746 int quad, offset, i;
1748 int max_epilog_size = 128;
1749 int stack_size = cfg->arch.stack_size;
1751 gint32 lmf_offset = cfg->arch.lmf_offset;
1753 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1755 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1757 cfg->code_size *= 2;
1758 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1759 mono_jit_stats.code_reallocs++;
1762 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1764 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1765 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1768 if (method->save_lmf)
1770 /* Restore previous lmf */
1771 alpha_ldq(code, alpha_at, alpha_fp,
1772 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1773 alpha_ldq(code, alpha_ra, alpha_fp,
1774 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1775 alpha_stq(code, alpha_at, alpha_ra, 0);
1779 alpha_mov1( code, alpha_fp, alpha_sp );
1781 // Restore saved regs
1782 offset = cfg->arch.reg_save_area_offset;
1784 for (i = 0; i < MONO_MAX_IREGS; ++i)
1785 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1786 (cfg->used_int_regs & (1 << i)) &&
1787 !( ALPHA_ARGS_REGS & (1 << i)) )
1789 alpha_ldq(code, i, alpha_sp, offset);
1790 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1795 /* restore fp, ra, sp */
1796 offset = cfg->arch.params_stack_size;
1798 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1799 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1800 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1803 alpha_ret( code, alpha_ra, 1 );
1805 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1807 g_assert (cfg->code_len < cfg->code_size);
1810 /*========================= End of Function ========================*/
1812 /*------------------------------------------------------------------*/
1814 /* Name - mono_arch_emit_exceptions */
1816 /* Function - Emit the blocks to handle exception conditions. */
1818 /*------------------------------------------------------------------*/
1821 mono_arch_emit_exceptions (MonoCompile *cfg)
1823 MonoJumpInfo *patch_info;
1825 unsigned int *code, *got_start;
1826 unsigned long *corlib_exc_adr;
1827 MonoClass *exc_classes [16];
1828 guint8 *exc_throw_start [16], *exc_throw_end [16];
1829 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1830 AlphaGotEntry *got_data;
1832 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1834 /* Compute needed space */
1835 for (patch_info = cfg->patch_info; patch_info;
1836 patch_info = patch_info->next)
1838 if (patch_info->type == MONO_PATCH_INFO_EXC)
1840 if (patch_info->type == MONO_PATCH_INFO_R8)
1841 code_size += 8 + 7; /* sizeof (double) + alignment */
1842 if (patch_info->type == MONO_PATCH_INFO_R4)
1843 code_size += 4 + 7; /* sizeof (float) + alignment */
1846 // Reserve space for GOT entries
1847 for (got_data = cfg->arch.got_data; got_data;
1848 got_data = got_data->next)
1850 // Reserve space for 8 byte const (for now)
1851 if (got_data->type != GT_LD_GTADDR)
1855 while (cfg->code_len + code_size > (cfg->code_size - 16))
1857 cfg->code_size *= 2;
1858 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1859 mono_jit_stats.code_reallocs++;
1862 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1864 // Set code alignment
1865 if (((unsigned long)code) % 8)
1870 /* Add code to store conts and modify patch into to store offset in got */
1871 for (got_data = cfg->arch.got_data; got_data;
1872 got_data = got_data->next)
1874 unsigned long data = got_data->value.data.l;
1875 MonoJumpInfo *got_ref = got_data->got_patch_info;
1877 // Modify loading of GP
1878 if (got_data->type == GT_LD_GTADDR)
1880 short high_off, low_off;
1881 unsigned int *ldgp_code =
1882 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1883 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1885 high_off = got_off / 0x10000;
1886 low_off = got_off % 0x10000;
1890 // Set offset from current point to GOT array
1891 // modify the following code sequence
1892 // ldah gp, 0(pv) or ldah gp, 0(ra)
1894 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1896 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1901 patch_info = got_data->patch_info;
1903 // Check code alignment
1904 if (((unsigned long)code) % 8)
1907 got_ref->data.offset = ((char *)code - (char *)got_start);
1910 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1912 *code = (unsigned int)(data & 0xFFFFFFFF);
1914 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1919 corlib_exc_adr = (unsigned long *)code;
1921 /* add code to raise exceptions */
1923 for (patch_info = cfg->patch_info; patch_info;
1924 patch_info = patch_info->next)
1926 switch (patch_info->type)
1928 case MONO_PATCH_INFO_EXC:
1930 MonoClass *exc_class;
1931 unsigned int *buf, *buf2;
1936 // Add patch info to call mono_arch_throw_corlib_exception
1937 // method to raise corlib exception
1938 // Will be added at the begining of the patch info list
1939 mono_add_patch_info(cfg,
1940 ((char *)code - (char *)cfg->native_code),
1941 MONO_PATCH_INFO_INTERNAL_METHOD,
1942 "mono_arch_throw_corlib_exception");
1944 // Skip longword before starting the code
1949 exc_class = mono_class_from_name (mono_defaults.corlib,
1950 "System", patch_info->data.name);
1952 g_assert (exc_class);
1953 throw_ip = patch_info->ip.i;
1955 //x86_breakpoint (code);
1956 /* Find a throw sequence for the same exception class */
1957 for (i = 0; i < nthrows; ++i)
1958 if (exc_classes [i] == exc_class)
1965 // Patch original branch (patch info) to jump here
1966 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1967 patch_info->data.target =
1968 (char *)code - (char *)cfg->native_code;
1970 alpha_lda(code, alpha_a1, alpha_zero,
1971 -((short)((((char *)exc_throw_end[i] -
1972 (char *)cfg->native_code)) - throw_ip) - 4) );
1974 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
1976 alpha_bsr(code, alpha_zero, br_offset);
1982 // Save exception token type as first 32bit word for new
1983 // exception handling jump code
1984 *code = exc_class->type_token;
1987 // Patch original branch (patch info) to jump here
1988 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1989 patch_info->data.target =
1990 (char *)code - (char *)cfg->native_code;
1993 alpha_lda(code, alpha_a1, alpha_zero, 0);
1997 exc_classes [nthrows] = exc_class;
1998 exc_throw_start [nthrows] = code;
2001 // Load exception token
2002 alpha_ldl(code, alpha_a0, alpha_gp,
2003 ((char *)buf - (char *)got_start /*cfg->native_code*/));
2004 // Load corlib exception raiser code address
2005 alpha_ldq(code, alpha_pv, alpha_gp,
2006 ((char *)corlib_exc_adr -
2007 (char *)got_start /*cfg->native_code*/));
2009 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
2010 //patch_info->data.name = "mono_arch_throw_corlib_exception";
2011 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
2012 //patch_info->type = MONO_PATCH_INFO_NONE;
2013 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
2015 if (cfg->compile_aot)
2017 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
2018 //amd64_call_reg (code, GP_SCRATCH_REG);
2020 /* The callee is in memory allocated using
2022 alpha_jsr(code, alpha_ra, alpha_pv, 0);
2025 alpha_lda(buf2, alpha_a1, alpha_zero,
2026 -((short)(((char *)code - (char *)cfg->native_code) -
2031 exc_throw_end [nthrows] = code;
2043 /* Handle relocations with RIP relative addressing */
2044 for (patch_info = cfg->patch_info; patch_info;
2045 patch_info = patch_info->next)
2047 gboolean remove = FALSE;
2049 switch (patch_info->type)
2051 case MONO_PATCH_INFO_R8:
2055 code = (guint8*)ALIGN_TO (code, 8);
2057 pos = cfg->native_code + patch_info->ip.i;
2059 *(double*)code = *(double*)patch_info->data.target;
2062 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2064 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2070 case MONO_PATCH_INFO_R4:
2074 code = (guint8*)ALIGN_TO (code, 8);
2076 pos = cfg->native_code + patch_info->ip.i;
2078 *(float*)code = *(float*)patch_info->data.target;
2081 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2083 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2095 if (patch_info == cfg->patch_info)
2096 cfg->patch_info = patch_info->next;
2101 for (tmp = cfg->patch_info; tmp->next != patch_info;
2104 tmp->next = patch_info->next;
2109 cfg->code_len = (char *)code - (char *)cfg->native_code;
2111 g_assert (cfg->code_len < cfg->code_size);
2115 /*========================= End of Function ========================*/
2117 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2118 offset = ((char *)code - \
2119 (char *)cfg->native_code); \
2120 if (Tins->flags & MONO_INST_BRLABEL) \
2122 if (Tins->inst_i0->inst_c0) \
2124 CFG_DEBUG(3) g_print("inst_c0: %0lX, data: %p]\n", \
2125 Tins->inst_i0->inst_c0, \
2126 cfg->native_code + Tins->inst_i0->inst_c0); \
2127 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2131 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n", \
2132 offset, Tins->inst_i0); \
2133 mono_add_patch_info (cfg, offset, \
2134 MONO_PATCH_INFO_LABEL, Tins->inst_i0); \
2135 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2140 if (Tins->inst_true_bb->native_offset) \
2142 long br_offset = (char *)cfg->native_code + \
2143 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2144 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2145 Tins->inst_target_bb->native_offset, \
2146 cfg->native_code + \
2147 Tins->inst_true_bb->native_offset); \
2148 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2152 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2153 offset, Tins->inst_target_bb); \
2154 mono_add_patch_info (cfg, offset, \
2155 MONO_PATCH_INFO_BB, \
2156 Tins->inst_true_bb); \
2157 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2162 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2165 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2170 mono_add_patch_info (cfg, \
2172 (char *)cfg->native_code), \
2173 MONO_PATCH_INFO_EXC, EXC_NAME); \
2174 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2178 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2183 /*------------------------------------------------------------------*/
2185 /* Name - mono_arch_output_basic_block */
2187 /* Function - Perform the "real" work of emitting instructions */
2188 /* that will do the work of in the basic block. */
2190 /*------------------------------------------------------------------*/
2193 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2198 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2199 MonoInst *last_ins = NULL;
2200 guint last_offset = 0;
2203 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2205 if (cfg->opt & MONO_OPT_PEEPHOLE)
2206 peephole_pass (cfg, bb);
2208 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2209 bb->block_num, bb, bb->native_offset);
2211 cpos = bb->max_offset;
2213 offset = ((char *)code) - ((char *)cfg->native_code);
2215 mono_debug_open_block (cfg, bb, offset);
2220 offset = ((char *)code) - ((char *)cfg->native_code);
2222 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2224 if (offset > (cfg->code_size - max_len - 16))
2226 cfg->code_size *= 2;
2227 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2228 code = (unsigned int *)(cfg->native_code + offset);
2229 mono_jit_stats.code_reallocs++;
2232 mono_debug_record_line_number (cfg, ins, offset);
2234 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2235 mono_inst_name(ins->opcode));
2237 switch (ins->opcode)
2240 // Shift 64 bit value right
2241 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2242 ins->dreg, ins->sreg1, ins->sreg2);
2243 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2247 // Shift 64 bit value right by constant
2248 g_assert(alpha_is_imm(ins->inst_imm));
2249 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, const=%ld\n",
2250 ins->dreg, ins->sreg1, ins->inst_imm);
2251 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2255 // Shift 32 bit value left
2256 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2257 ins->dreg, ins->sreg1, ins->sreg2);
2258 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2262 // Shift 32 bit value left by constant
2263 g_assert(alpha_is_imm(ins->inst_imm));
2264 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2265 ins->dreg, ins->sreg1, ins->inst_imm);
2266 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2270 g_assert(alpha_is_imm(ins->inst_imm));
2271 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2272 ins->dreg, ins->sreg1, ins->inst_imm);
2273 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2277 // Shift 32 bit value left
2278 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2279 ins->dreg, ins->sreg1, ins->sreg2);
2280 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2285 // Shift 32 bit value right
2286 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2287 ins->dreg, ins->sreg1, ins->sreg2);
2288 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2289 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2293 // Shift 32 bit value rigth by constant
2294 g_assert(alpha_is_imm(ins->inst_imm));
2295 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2296 ins->dreg, ins->sreg1, ins->inst_imm);
2297 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2298 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2302 // Shift 32 bit unsigned value right
2303 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2304 ins->dreg, ins->sreg1, ins->sreg2);
2305 alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2306 alpha_srl(code, ins->dreg, ins->sreg2, ins->dreg);
2309 case OP_ISHR_UN_IMM:
2310 // Shift 32 bit unassigned value rigth by constant
2311 g_assert(alpha_is_imm(ins->inst_imm));
2312 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2313 ins->dreg, ins->sreg1, ins->inst_imm);
2314 alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2315 alpha_srl_(code, ins->dreg, ins->inst_imm, ins->dreg);
2318 case OP_LSHR_UN_IMM:
2319 // Shift 64 bit unassigned value rigth by constant
2320 g_assert(alpha_is_imm(ins->inst_imm));
2321 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2322 ins->dreg, ins->sreg1, ins->inst_imm);
2323 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2327 // Sum two 64 bits regs
2328 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2329 ins->dreg, ins->sreg1, ins->sreg2);
2330 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2334 // Subtract two 64 bit regs
2335 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2336 ins->dreg, ins->sreg1, ins->sreg2);
2337 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2341 // Add imm value to 64 bits int
2342 g_assert(alpha_is_imm(ins->inst_imm));
2343 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2344 ins->dreg, ins->sreg1, ins->inst_imm);
2345 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2349 // Add two 32 bit ints
2350 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2351 ins->dreg, ins->sreg1, ins->sreg2);
2352 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2356 // Add two 32 bit ints with overflow detection
2357 // Use AT to hold flag of signed overflow
2358 // Use t12(PV) to hold unsigned overflow
2359 // Use RA to hold intermediate result
2360 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2361 ins->dreg, ins->sreg1, ins->sreg2);
2362 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2363 alpha_ble(code, ins->sreg2, 2);
2365 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2366 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2367 alpha_br(code, alpha_zero, 1);
2369 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2370 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2372 /* res <u sreg1 => unsigned overflow */
2373 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2375 alpha_mov1(code, alpha_ra, ins->dreg);
2379 // Add two 64 bit ints with overflow detection
2380 // Use AT to hold flag of signed overflow
2381 // Use t12(PV) to hold unsigned overflow
2382 // Use RA to hold intermediate result
2383 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2384 ins->dreg, ins->sreg1, ins->sreg2);
2385 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2386 alpha_ble(code, ins->sreg2, 2);
2388 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2389 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2390 alpha_br(code, alpha_zero, 1);
2392 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2393 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2395 /* res <u sreg1 => unsigned overflow */
2396 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2398 alpha_mov1(code, alpha_ra, ins->dreg);
2402 // Add imm value to 32 bits int
2403 g_assert(alpha_is_imm(ins->inst_imm));
2404 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2405 ins->dreg, ins->sreg1, ins->inst_imm);
2406 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2410 // Substract to 32 bit ints
2411 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2412 ins->dreg, ins->sreg1, ins->sreg2);
2413 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2417 // Sub imm value from 32 bits int
2418 g_assert(alpha_is_imm(ins->inst_imm));
2419 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2420 ins->dreg, ins->sreg1, ins->inst_imm);
2421 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2425 // Sub to 32 bit ints with overflow detection
2426 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2427 ins->dreg, ins->sreg1, ins->sreg2);
2428 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2429 alpha_ble(code, ins->sreg2, 2);
2431 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2432 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2433 alpha_br(code, alpha_zero, 1);
2435 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2436 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2438 /* sreg1 <u sreg2 => unsigned overflow */
2439 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2441 alpha_mov1(code, alpha_ra, ins->dreg);
2445 // Sub to 64 bit ints with overflow detection
2446 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2447 ins->dreg, ins->sreg1, ins->sreg2);
2449 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2450 alpha_ble(code, ins->sreg2, 2);
2452 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2453 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2454 alpha_br(code, alpha_zero, 1);
2456 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2457 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2459 /* sreg1 <u sreg2 => unsigned overflow */
2460 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2462 alpha_mov1(code, alpha_ra, ins->dreg);
2467 // AND to 32 bit ints
2468 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2469 ins->dreg, ins->sreg1, ins->sreg2);
2470 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2475 // AND imm value with 32 bit int
2476 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2477 ins->dreg, ins->sreg1, ins->inst_imm);
2479 g_assert(alpha_is_imm(ins->inst_imm));
2480 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2486 // OR two 32/64 bit ints
2487 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2488 ins->dreg, ins->sreg1, ins->sreg2);
2489 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2493 // OR imm value with 32 bit int
2494 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2495 ins->dreg, ins->sreg1, ins->inst_imm);
2497 g_assert(alpha_is_imm(ins->inst_imm));
2498 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2504 // XOR two 32/64 bit ints
2505 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2506 ins->dreg, ins->sreg1, ins->sreg2);
2507 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2511 // XOR imm value with 32 bit int
2512 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2513 ins->dreg, ins->sreg1, ins->inst_imm);
2515 g_assert(alpha_is_imm(ins->inst_imm));
2516 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2522 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2523 ins->dreg, ins->sreg1);
2524 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2529 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2530 ins->dreg, ins->sreg1);
2531 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2536 // NOT 32/64 bit reg
2537 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2538 ins->dreg, ins->sreg1);
2539 alpha_not(code, ins->sreg1, ins->dreg);
2547 case OP_IMUL_OVF_UN:
2550 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",
2551 ins->dreg, ins->sreg1, ins->sreg2);
2555 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2556 ins->dreg, ins->sreg1, ins->sreg2);
2557 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2561 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2562 ins->dreg, ins->sreg1, ins->inst_imm);
2566 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2568 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2572 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2573 ins->dreg, ins->sreg1);
2574 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2575 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2579 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2580 ins->dreg, ins->sreg1);
2581 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2582 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2586 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2587 ins->dreg, ins->sreg1);
2588 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2589 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2593 // Actually ICONST is 32 bits long
2594 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2595 ins->dreg, ins->inst_c0);
2598 if (ins->inst_c0 == 0)
2600 alpha_clr(code, ins->dreg);
2604 // if -32768 < const <= 32767
2605 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2607 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2608 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2609 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2613 int lo = (char *)code - (char *)cfg->native_code;
2614 AlphaGotData ge_data;
2616 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2617 ge_data.data.l = ins->inst_c0;
2619 add_got_entry(cfg, GT_LONG, ge_data,
2620 lo, MONO_PATCH_INFO_NONE, 0);
2621 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2623 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2624 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2632 // To load 64 bit values we will have to use ldah/lda combination
2633 // and temporary register. As temporary register use r28
2634 // Divide 64 bit value in two parts and load upper 32 bits into
2635 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2636 // dreg from temp reg
2637 // the 32 bit value could be loaded with ldah/lda
2638 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2639 ins->dreg, ins->inst_c0);
2642 if (ins->inst_c0 == 0)
2644 alpha_clr(code, ins->dreg);
2648 // if -32768 < const <= 32767
2649 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2650 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2653 AlphaGotData ge_data;
2655 lo = (char *)code - (char *)cfg->native_code;
2657 ge_data.data.l = ins->inst_c0;
2659 add_got_entry(cfg, GT_LONG, ge_data,
2660 lo, MONO_PATCH_INFO_NONE, 0);
2661 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2668 double d = *(double *)ins->inst_p0;
2669 AlphaGotData ge_data;
2671 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2675 add_got_entry(cfg, GT_DOUBLE, ge_data,
2676 (char *)code - (char *)cfg->native_code,
2677 MONO_PATCH_INFO_NONE, 0);
2678 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2685 float d = *(float *)ins->inst_p0;
2686 AlphaGotData ge_data;
2688 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2692 add_got_entry(cfg, GT_FLOAT, ge_data,
2693 (char *)code - (char *)cfg->native_code,
2694 MONO_PATCH_INFO_NONE, 0);
2695 alpha_lds(code, ins->dreg, alpha_gp, 0);
2700 case OP_LOADU4_MEMBASE:
2701 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2702 ins->dreg, ins->inst_basereg, ins->inst_offset);
2704 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2705 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2708 case OP_LOADU1_MEMBASE:
2709 // Load unassigned byte from REGOFFSET
2710 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2711 ins->dreg, ins->inst_basereg, ins->inst_offset);
2713 alpha_ldq_u(code, alpha_r25, ins->inst_basereg, ins->inst_offset);
2714 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2715 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2718 case OP_LOADU2_MEMBASE:
2719 // Load unassigned word from REGOFFSET
2720 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2721 ins->dreg, ins->inst_basereg, ins->inst_offset);
2723 alpha_ldq_u(code, alpha_r24, ins->inst_basereg, ins->inst_offset);
2724 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2725 (ins->inst_offset+1));
2726 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2727 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2728 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2729 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2733 case OP_LOAD_MEMBASE:
2734 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2735 ins->dreg, ins->inst_basereg, ins->inst_offset);
2736 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2739 case OP_LOADI8_MEMBASE:
2740 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2741 ins->dreg, ins->inst_basereg, ins->inst_offset);
2742 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2745 case OP_LOADI4_MEMBASE:
2746 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2747 ins->dreg, ins->inst_basereg, ins->inst_offset);
2748 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2751 case OP_LOADI1_MEMBASE:
2752 // Load sign-extended byte from REGOFFSET
2753 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2754 ins->dreg, ins->inst_basereg, ins->inst_offset);
2755 alpha_ldq_u(code, alpha_r25, ins->inst_basereg, ins->inst_offset);
2756 alpha_lda(code, alpha_at, ins->inst_basereg, (ins->inst_offset+1));
2757 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2758 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2761 case OP_LOADI2_MEMBASE:
2762 // Load sign-extended word from REGOFFSET
2763 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2764 ins->dreg, ins->inst_basereg, ins->inst_offset);
2765 alpha_ldq_u(code, alpha_r24, ins->inst_basereg, ins->inst_offset);
2766 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2767 (ins->inst_offset+1));
2768 alpha_lda(code, alpha_at, ins->inst_basereg, (ins->inst_offset+2));
2769 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2770 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2771 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2772 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2776 case OP_STOREI1_MEMBASE_IMM:
2777 // Store signed byte at REGOFFSET
2778 // For now storei1_membase_reg will do the work
2779 g_assert_not_reached();
2781 printf("ALPHA_TODO: [storei1_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2782 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2783 g_assert(alpha_is_imm(ins->inst_imm));
2785 alpha_lda(code, alpha_r25, alpha_zero, ins->inst_imm);
2787 alpha_lda(code, alpha_at, ins->inst_destbasereg, ins->inst_offset);
2788 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg, ins->inst_offset);
2789 alpha_insbl(code, alpha_r25, alpha_at, alpha_r23);
2790 alpha_mskbl(code, alpha_r24, alpha_at, alpha_r24);
2791 alpha_bis(code, alpha_r24, alpha_r23, alpha_r24);
2792 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg, ins->inst_offset);
2796 case OP_STOREI1_MEMBASE_REG:
2797 // Store byte at REGOFFSET
2798 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2799 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2801 alpha_lda(code, alpha_at, ins->inst_destbasereg, ins->inst_offset);
2802 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2804 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2805 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2806 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2807 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2812 case OP_STOREI2_MEMBASE_IMM:
2813 // Store signed word at REGOFFSET
2814 // For now storei2_membase_reg will do the work
2815 g_assert_not_reached();
2817 printf("ALPHA_TODO: [storei2_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2818 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2822 case OP_STOREI2_MEMBASE_REG:
2823 // Store signed word from reg to REGOFFSET
2824 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2825 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2827 alpha_lda(code, alpha_at, ins->inst_destbasereg, ins->inst_offset);
2828 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2829 (ins->inst_offset+1));
2830 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2832 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2833 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2834 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2835 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2836 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2837 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2838 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2839 (ins->inst_offset+1));
2840 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2845 case OP_STOREI4_MEMBASE_IMM:
2846 // We will get here only with ins->inst_imm = 0
2847 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2848 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2850 g_assert(ins->inst_imm == 0);
2852 alpha_stl(code, alpha_zero,
2853 ins->inst_destbasereg, ins->inst_offset);
2856 case OP_STORER4_MEMBASE_REG:
2857 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2858 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2859 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2862 case OP_STORER8_MEMBASE_REG:
2863 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2864 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2865 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2869 case OP_LOADR4_MEMBASE:
2870 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2871 ins->dreg, ins->inst_basereg, ins->inst_offset);
2872 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2875 case OP_LOADR8_MEMBASE:
2876 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2877 ins->dreg, ins->inst_basereg, ins->inst_offset);
2878 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2882 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2883 ins->sreg1, ins->dreg);
2884 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
2888 // Later check different rounding and exc modes
2889 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2890 ins->sreg1, ins->sreg2, ins->dreg);
2891 alpha_addt(code, ins->sreg1, ins->sreg2, ins->dreg);
2895 // Later check different rounding and exc modes
2896 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2897 ins->sreg1, ins->sreg2, ins->dreg);
2898 alpha_subt(code, ins->sreg1, ins->sreg2, ins->dreg);
2902 // Later check different rounding and exc modes
2903 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2904 ins->sreg1, ins->sreg2, ins->dreg);
2905 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
2909 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2910 ins->sreg1, ins->dreg);
2911 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
2914 case OP_ALPHA_TRAPB:
2915 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2920 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2921 ins->sreg1, ins->dreg);
2922 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
2925 case OP_STORE_MEMBASE_IMM:
2926 case OP_STOREI8_MEMBASE_IMM:
2927 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2928 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2929 g_assert(ins->inst_imm == 0);
2931 alpha_stq(code, alpha_zero,
2932 ins->inst_destbasereg, ins->inst_offset);
2935 case OP_STORE_MEMBASE_REG:
2936 case OP_STOREI8_MEMBASE_REG:
2937 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2938 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2939 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2942 case OP_STOREI4_MEMBASE_REG:
2943 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2944 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2945 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2948 case OP_ICOMPARE_IMM:
2949 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2950 ins->sreg1, ins->dreg, ins->inst_imm);
2952 g_assert_not_reached();
2956 case OP_COMPARE_IMM:
2957 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2958 ins->sreg1, ins->dreg, ins->inst_imm);
2960 g_assert_not_reached();
2964 case OP_COMPARE: // compare two 32 bit regs
2965 case OP_LCOMPARE: // compare two 64 bit regs
2966 case OP_FCOMPARE: // compare two floats
2967 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
2968 ins->sreg1, ins->sreg2, ins->dreg);
2970 g_assert_not_reached();
2974 case OP_ALPHA_CMPT_UN:
2975 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
2976 ins->sreg1, ins->sreg2, ins->dreg);
2977 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
2980 case OP_ALPHA_CMPT_UN_SU:
2981 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
2982 ins->sreg1, ins->sreg2, ins->dreg);
2983 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
2986 case OP_ALPHA_CMPT_EQ:
2987 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
2988 ins->sreg1, ins->sreg2, ins->dreg);
2989 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
2992 case OP_ALPHA_CMPT_EQ_SU:
2993 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
2994 ins->sreg1, ins->sreg2, ins->dreg);
2995 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
2999 case OP_ALPHA_CMPT_LT:
3000 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3001 ins->sreg1, ins->sreg2, ins->dreg);
3002 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3005 case OP_ALPHA_CMPT_LT_SU:
3006 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3007 ins->sreg1, ins->sreg2, ins->dreg);
3008 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3011 case OP_ALPHA_CMPT_LE:
3012 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3013 ins->sreg1, ins->sreg2, ins->dreg);
3014 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3017 case OP_ALPHA_CMPT_LE_SU:
3018 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3019 ins->sreg1, ins->sreg2, ins->dreg);
3020 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3023 case OP_ALPHA_CMP_EQ:
3024 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3025 ins->sreg1, ins->sreg2, ins->dreg);
3026 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3029 case OP_ALPHA_CMP_IMM_EQ:
3030 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3031 ins->sreg1, ins->inst_imm, ins->dreg);
3032 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3035 case OP_ALPHA_CMP_IMM_ULE:
3036 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%\d\n",
3037 ins->sreg1, ins->inst_imm, ins->dreg);
3038 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3041 case OP_ALPHA_CMP_ULT:
3042 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3043 ins->sreg1, ins->sreg2, ins->dreg);
3044 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3047 case OP_ALPHA_CMP_IMM_ULT:
3048 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3049 ins->sreg1, ins->inst_imm, ins->dreg);
3050 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3053 case OP_ALPHA_CMP_LE:
3054 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3055 ins->sreg1, ins->sreg2, ins->dreg);
3056 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3059 case OP_ALPHA_CMP_ULE:
3060 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3061 ins->sreg1, ins->sreg2, ins->dreg);
3062 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3066 case OP_ALPHA_CMP_IMM_LE:
3067 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%\d\n",
3068 ins->sreg1, ins->inst_imm, ins->dreg);
3069 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3072 case OP_ALPHA_CMP_LT:
3073 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3074 ins->sreg1, ins->sreg2, ins->dreg);
3075 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3078 case OP_ALPHA_CMP_IMM_LT:
3079 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3080 ins->sreg1, ins->inst_imm, ins->dreg);
3081 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3084 case OP_COND_EXC_GT:
3085 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3086 (char *)ins->inst_p1);
3088 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3091 case OP_COND_EXC_GT_UN:
3092 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3093 (char *)ins->inst_p1);
3095 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3098 case OP_COND_EXC_LT:
3099 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3100 (char *)ins->inst_p1);
3102 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3105 case OP_COND_EXC_LT_UN:
3106 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3107 (char *)ins->inst_p1);
3109 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3113 case OP_COND_EXC_LE_UN:
3114 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3115 (char *)ins->inst_p1);
3116 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3119 case OP_COND_EXC_NE_UN:
3120 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3121 (char *)ins->inst_p1);
3122 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3125 case OP_COND_EXC_EQ:
3126 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3127 (char *)ins->inst_p1);
3128 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3131 case OP_COND_EXC_IOV:
3132 case OP_COND_EXC_OV:
3133 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3136 case OP_COND_EXC_IC:
3138 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3141 case CEE_CONV_OVF_U4:
3142 // Convert unsigned 32 bit value to 64 bit reg
3144 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3145 ins->sreg1, ins->dreg);
3146 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3147 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3148 alpha_mov1(code, ins->sreg1, ins->dreg);
3151 case CEE_CONV_OVF_I4_UN:
3152 // Convert unsigned 32 bit value to 64 bit reg
3154 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3155 ins->sreg1, ins->dreg);
3156 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3158 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3159 alpha_mov1(code, ins->sreg1, ins->dreg);
3163 // Move I1 (byte) to dreg(64 bits) and sign extend it
3165 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3166 ins->sreg1, ins->dreg);
3167 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3168 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3169 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3173 // Move I2 (word) to dreg(64 bits) and sign extend it
3174 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3175 ins->sreg1, ins->dreg);
3176 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3177 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3178 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3182 // Move I4 (long) to dreg(64 bits) and sign extend it
3183 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3184 ins->sreg1, ins->dreg);
3185 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3190 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3191 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3192 ins->sreg1, ins->dreg);
3193 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3194 alpha_mov1(code, ins->sreg1, ins->dreg);
3198 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3199 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3200 ins->sreg1, ins->dreg);
3201 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3205 // Move U2 (word) to dreg(64 bits) don't sign extend it
3206 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3207 ins->sreg1, ins->dreg);
3208 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3212 // Move U4 (long) to dreg(64 bits) don't sign extend it
3213 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3214 ins->sreg1, ins->dreg);
3215 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3220 // Move U4 (long) to dreg(64 bits) don't sign extend it
3221 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3222 ins->sreg1, ins->dreg);
3223 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3226 case OP_FCONV_TO_I4:
3227 case OP_FCONV_TO_I8:
3228 // Move float to 32 bit reg
3229 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3230 ins->sreg1, ins->dreg);
3231 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3232 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3233 alpha_lda(code, alpha_sp, alpha_sp, -8);
3234 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3235 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3236 alpha_lda(code, alpha_sp, alpha_sp, 8);
3239 case OP_FCONV_TO_I2:
3240 // Move float to 16 bit reg
3241 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3242 ins->sreg1, ins->dreg);
3243 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3244 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3245 alpha_lda(code, alpha_sp, alpha_sp, -8);
3246 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3247 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3248 alpha_lda(code, alpha_sp, alpha_sp, 8);
3249 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3250 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3253 case OP_FCONV_TO_U2:
3254 // Move float to 16 bit reg as unsigned
3255 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3256 ins->sreg1, ins->dreg);
3257 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3258 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3259 alpha_lda(code, alpha_sp, alpha_sp, -8);
3260 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3261 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3262 alpha_lda(code, alpha_sp, alpha_sp, 8);
3263 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3266 case OP_FCONV_TO_U1:
3267 // Move float to 8 bit reg as unsigned
3268 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3269 ins->sreg1, ins->dreg);
3270 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3271 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3272 alpha_lda(code, alpha_sp, alpha_sp, -8);
3273 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3274 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3275 alpha_lda(code, alpha_sp, alpha_sp, 8);
3276 alpha_and_(code, ins->dreg, 0xff, ins->dreg);
3279 case OP_FCONV_TO_I1:
3280 // Move float to 8 bit reg
3281 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3282 ins->sreg1, ins->dreg);
3283 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3284 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3285 alpha_lda(code, alpha_sp, alpha_sp, -8);
3286 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3287 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3288 alpha_lda(code, alpha_sp, alpha_sp, 8);
3289 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3290 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3294 case OP_LCONV_TO_R4:
3295 // Move 32/64 bit int into float
3296 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3297 ins->sreg1, ins->dreg);
3298 alpha_lda(code, alpha_sp, alpha_sp, -8);
3299 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3300 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3301 alpha_lda(code, alpha_sp, alpha_sp, 8);
3302 alpha_cvtqs(code, ins->dreg, ins->dreg);
3306 case OP_LCONV_TO_R8:
3307 // Move 32/64 bit int into double
3308 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3309 ins->sreg1, ins->dreg);
3310 alpha_lda(code, alpha_sp, alpha_sp, -8);
3311 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3312 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3313 alpha_lda(code, alpha_sp, alpha_sp, 8);
3314 alpha_cvtqt(code, ins->dreg, ins->dreg);
3317 case OP_FCONV_TO_R4:
3318 // Convert 64 bit float to 32 bit float (T -> S)
3319 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3320 ins->sreg1, ins->dreg);
3321 alpha_cvtts(code, ins->sreg1, ins->dreg);
3325 // Allocate sreg1 bytes on stack, round bytes by 8,
3326 // modify SP, set dreg to end of current stack frame
3327 // top of stack is used for call params
3328 CFG_DEBUG(4) g_print("ALPHA_FIX: [localloc] sreg=%d, dreg=%d\n",
3329 ins->sreg1, ins->dreg);
3330 alpha_addq_(code, ins->sreg1, (MONO_ARCH_FRAME_ALIGNMENT - 1), ins->sreg1);
3331 alpha_and_(code, ins->sreg1, ~(MONO_ARCH_FRAME_ALIGNMENT - 1), ins->sreg1);
3332 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3333 alpha_lda(code, ins->dreg, alpha_zero, (cfg->arch.params_stack_size));
3334 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3338 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3339 ins->sreg1, ins->dreg);
3340 alpha_mov1(code, ins->sreg1, ins->dreg);
3347 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3349 alpha_clr(code, ins->dreg);
3350 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3357 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3359 alpha_clr(code, ins->dreg);
3360 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3365 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3367 alpha_clr(code, ins->dreg);
3368 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3372 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3374 alpha_clr(code, ins->dreg);
3375 alpha_fbeq(code, alpha_at, 1);
3376 alpha_lda(code, ins->dreg, alpha_zero, 1);
3379 alpha_cvttq_c(code, alpha_at, alpha_at);
3380 alpha_lda(code, alpha_sp, alpha_sp, -8);
3381 alpha_stt(code, alpha_at, alpha_sp, 0);
3382 alpha_ldq(code, alpha_at, alpha_sp, 0);
3383 alpha_lda(code, alpha_sp, alpha_sp, 8);
3385 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3390 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3392 alpha_clr(code, ins->dreg);
3393 alpha_fbne(code, alpha_at, 1);
3394 alpha_lda(code, ins->dreg, alpha_zero, 1);
3397 alpha_cvttq_c(code, alpha_at, alpha_at);
3398 alpha_lda(code, alpha_sp, alpha_sp, -8);
3399 alpha_stt(code, alpha_at, alpha_sp, 0);
3400 alpha_ldq(code, alpha_at, alpha_sp, 0);
3401 alpha_lda(code, alpha_sp, alpha_sp, 8);
3403 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3409 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3411 alpha_clr(code, ins->dreg);
3412 alpha_fbeq(code, alpha_at, 1);
3413 alpha_lda(code, ins->dreg, alpha_zero, 1);
3417 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3420 alpha_clr(code, ins->dreg);
3421 alpha_fbne(code, (alpha_at+1), 1);
3422 alpha_fbeq(code, alpha_at, 1);
3423 alpha_lda(code, ins->dreg, alpha_zero, 1);
3428 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3429 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3433 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3434 alpha_fbeq(code, (alpha_at+1), 1);
3435 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3436 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3440 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3441 alpha_fbeq(code, (alpha_at+1), 1);
3442 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3443 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3447 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3448 alpha_fbeq(code, (alpha_at+1), 1);
3449 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3450 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3454 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3455 alpha_fbeq(code, (alpha_at+1), 1);
3456 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3457 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3461 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3462 alpha_fbeq(code, (alpha_at+1), 1);
3463 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3464 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3468 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3469 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3473 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3474 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3478 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3479 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3483 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3484 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3488 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3489 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3493 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br] target: %p, next: %p, curr: %p, last: %p [",
3494 ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3496 if (ins->flags & MONO_INST_BRLABEL)
3498 if (ins->inst_i0->inst_c0)
3500 CFG_DEBUG(4) g_print("inst_c0: %0lX, data: %p]\n",
3501 ins->inst_i0->inst_c0,
3502 cfg->native_code + ins->inst_i0->inst_c0);
3503 alpha_br(code, alpha_zero, 0);
3507 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n",
3508 offset, ins->inst_i0);
3509 mono_add_patch_info (cfg, offset,
3510 MONO_PATCH_INFO_LABEL, ins->inst_i0);
3512 alpha_br(code, alpha_zero, 0);
3517 if (ins->inst_target_bb->native_offset)
3519 // Somehow native offset is offset from
3520 // start of the code. So convert it to
3522 long br_offset = (char *)cfg->native_code +
3523 ins->inst_target_bb->native_offset - 4 - (char *)code;
3525 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3526 ins->inst_target_bb->native_offset,
3528 ins->inst_target_bb->native_offset);
3529 alpha_br(code, alpha_zero, br_offset/4);
3533 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3534 offset, ins->inst_target_bb);
3536 mono_add_patch_info (cfg, offset,
3538 ins->inst_target_bb);
3539 alpha_br(code, alpha_zero, 0);
3546 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3549 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3557 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3558 call = (MonoCallInst*)ins;
3560 if (ins->flags & MONO_INST_HAS_METHOD)
3562 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3563 code = emit_call (cfg, code,
3564 MONO_PATCH_INFO_METHOD, call->method);
3568 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3569 code = emit_call (cfg, code,
3570 MONO_PATCH_INFO_ABS, call->fptr);
3573 //code = emit_move_return_value (cfg, ins, code);
3580 case OP_VOIDCALL_REG:
3585 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3586 call = (MonoCallInst*)ins;
3588 alpha_mov1(code, ins->sreg1, alpha_pv);
3590 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3592 offset = (char *)code - (char *)cfg->native_code;
3595 ALPHA_LOAD_GP(offset)
3596 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3597 alpha_lda(code, alpha_gp, alpha_gp, 0);
3601 case OP_FCALL_MEMBASE:
3602 case OP_CALL_MEMBASE:
3603 case OP_LCALL_MEMBASE:
3604 case OP_VCALL_MEMBASE:
3608 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3609 ins->inst_basereg, ins->inst_offset);
3610 call = (MonoCallInst*)ins;
3612 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3613 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3615 offset = (char *)code - (char *)cfg->native_code;
3618 ALPHA_LOAD_GP(offset)
3619 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3620 alpha_lda(code, alpha_gp, alpha_gp, 0);
3624 case OP_VOIDCALL_MEMBASE:
3628 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3629 ins->inst_basereg, ins->inst_offset);
3630 call = (MonoCallInst*)ins;
3632 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3633 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3635 offset = (char *)code - (char *)cfg->native_code;
3638 ALPHA_LOAD_GP(offset)
3639 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3640 alpha_lda(code, alpha_gp, alpha_gp, 0);
3644 case OP_START_HANDLER:
3646 // TODO - find out when we called by call_handler or resume_context
3647 // of by call_filter. There should be difference. For now just
3648 // handle - call_handler
3650 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0x\n",
3651 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3653 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3654 ins->inst_left->inst_offset);
3658 case CEE_ENDFINALLY:
3660 // Keep in sync with start_handler
3661 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0x\n",
3662 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3664 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3665 ins->inst_left->inst_offset);
3667 alpha_ret(code, alpha_ra, 1);
3673 // Keep in sync with start_handler
3674 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0x\n",
3675 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3677 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3678 ins->inst_left->inst_offset);
3680 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3681 alpha_mov1(code, ins->sreg1, alpha_r0);
3683 alpha_ret(code, alpha_ra, 1);
3687 case OP_CALL_HANDLER:
3691 offset = (char *)code - (char *)cfg->native_code;
3693 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3694 offset, ins->inst_target_bb);
3696 mono_add_patch_info (cfg, offset,
3698 ins->inst_target_bb);
3699 alpha_bsr(code, alpha_ra, 0);
3705 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ret]\n");
3707 alpha_ret(code, alpha_ra, 1);
3711 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0lx\n",
3713 alpha_mov1(code, ins->sreg1, alpha_a0);
3714 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3715 (gpointer)"mono_arch_throw_exception");
3719 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0lx\n",
3721 alpha_mov1(code, ins->sreg1, alpha_a0);
3722 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3723 (gpointer)"mono_arch_rethrow_exception");
3728 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3730 * Note: this 'frame destruction' logic is useful for tail calls, too.
3731 * Keep in sync with the code in emit_epilog.
3733 int pos = 0, i, offset;
3734 AlphaGotData ge_data;
3736 /* FIXME: no tracing support... */
3737 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3738 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
3739 g_assert (!cfg->method->save_lmf);
3741 alpha_mov1( code, alpha_fp, alpha_sp );
3743 code = emit_load_volatile_arguments (cfg, code);
3745 offset = cfg->arch.params_stack_size;
3747 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3748 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3749 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3751 ge_data.data.p = ins->inst_p0;
3752 add_got_entry(cfg, GT_PTR, ge_data,
3753 (char *)code - (char *)cfg->native_code,
3754 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3755 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3757 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3762 mono_add_patch_info (cfg, offset,
3763 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3767 g_warning ("unknown opcode %s in %s()\n",
3768 mono_inst_name (ins->opcode), __FUNCTION__);
3770 // g_assert_not_reached ();
3774 if ( (((char *)code) -
3775 ((char *)cfg->native_code) -
3778 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3779 mono_inst_name (ins->opcode), max_len,
3780 ((char *)code) - ((char *)cfg->native_code) - offset );
3781 //g_assert_not_reached ();
3787 last_offset = offset;
3792 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3795 /*========================= End of Function ========================*/
3800 /*------------------------------------------------------------------*/
3802 /* Name - mono_arch_cpu_optimizazions */
3804 /* Function - Returns the optimizations supported on this CPU */
3806 /*------------------------------------------------------------------*/
3809 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3813 if (getenv("MONO_ALPHA_DEBUG"))
3814 mini_alpha_verbose_level = 1;
3816 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3818 /*----------------------------------------------------------*/
3819 /* no alpha-specific optimizations yet */
3820 /*----------------------------------------------------------*/
3821 *exclude_mask = MONO_OPT_LINEARS;
3822 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3826 /*========================= End of Function ========================*/
3828 /*------------------------------------------------------------------*/
3830 /* Name - mono_arch_flush_icache */
3832 /* Function - Flush the CPU icache. */
3834 /*------------------------------------------------------------------*/
3837 mono_arch_flush_icache (guint8 *code, gint size)
3839 //ALPHA_DEBUG("mono_arch_flush_icache");
3841 /* flush instruction cache to see trampoline code */
3842 asm volatile("imb":::"memory");
3845 /*========================= End of Function ========================*/
3847 /*------------------------------------------------------------------*/
3849 /* Name - mono_arch_regname */
3851 /* Function - Returns the name of the register specified by */
3852 /* the input parameter. */
3854 /*------------------------------------------------------------------*/
3857 mono_arch_regname (int reg) {
3858 static const char * rnames[] = {
3859 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
3860 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
3861 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
3862 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
3863 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
3864 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
3865 "alpha_r30", "alpha_r31"
3868 if (reg >= 0 && reg < 32)
3869 return rnames [reg];
3873 /*========================= End of Function ========================*/
3875 /*------------------------------------------------------------------*/
3877 /* Name - mono_arch_fregname */
3879 /* Function - Returns the name of the register specified by */
3880 /* the input parameter. */
3882 /*------------------------------------------------------------------*/
3885 mono_arch_fregname (int reg) {
3886 static const char * rnames[] = {
3887 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
3888 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
3889 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
3890 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
3891 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
3892 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
3893 "alpha_f30", "alpha_f31"
3896 if (reg >= 0 && reg < 32)
3897 return rnames [reg];
3902 /*========================= End of Function ========================*/
3904 /*------------------------------------------------------------------*/
3906 /* Name - mono_arch_patch_code */
3908 /* Function - Process the patch data created during the */
3909 /* instruction build process. This resolves jumps, */
3910 /* calls, variables etc. */
3912 /*------------------------------------------------------------------*/
3915 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
3916 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3918 MonoJumpInfo *patch_info;
3919 gboolean compile_aot = !run_cctors;
3921 ALPHA_DEBUG("mono_arch_patch_code");
3923 for (patch_info = ji; patch_info; patch_info = patch_info->next)
3925 unsigned char *ip = patch_info->ip.i + code;
3926 const unsigned char *target;
3928 target = mono_resolve_patch_target (method, domain,
3929 code, patch_info, run_cctors);
3933 switch (patch_info->type)
3936 case MONO_PATCH_INFO_BB:
3937 case MONO_PATCH_INFO_LABEL:
3940 /* No need to patch these */
3945 switch (patch_info->type)
3947 case MONO_PATCH_INFO_NONE:
3950 case MONO_PATCH_INFO_GOT_OFFSET:
3952 unsigned int *ip2 = ip;
3953 unsigned int inst = *ip2;
3954 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
3956 g_assert(!(off & 0xFFFF8000));
3964 case MONO_PATCH_INFO_CLASS_INIT:
3966 /* Might already been changed to a nop */
3967 unsigned int* ip2 = ip;
3968 unsigned long t_addr = (unsigned long)target;
3970 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
3971 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
3972 NOT_IMPLEMENTED("mono_arch_patch_code: MONO_PATCH_INFO_CLASS_INIT");
3973 // amd64_call_code (ip2, 0);
3977 // case MONO_PATCH_INFO_METHOD_REL:
3978 case MONO_PATCH_INFO_R8:
3979 case MONO_PATCH_INFO_R4:
3980 g_assert_not_reached ();
3982 case MONO_PATCH_INFO_BB:
3985 case MONO_PATCH_INFO_METHOD:
3986 case MONO_PATCH_INFO_METHODCONST:
3987 case MONO_PATCH_INFO_INTERNAL_METHOD:
3988 case MONO_PATCH_INFO_METHOD_JUMP:
3990 volatile unsigned int *p = (unsigned int *)ip;
3991 unsigned long t_addr;
3998 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4000 if (target != ((void *)t_addr))
4002 t_addr = (unsigned long)target;
4003 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4004 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4009 case MONO_PATCH_INFO_ABS:
4011 volatile unsigned int *p = (unsigned int *)ip;
4012 unsigned long t_addr;
4018 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4023 case MONO_PATCH_INFO_SWITCH:
4025 unsigned int *pcode = (unsigned int *)ip;
4026 unsigned long t_addr;
4028 t_addr = (unsigned long)target;
4030 if (((unsigned long)ip) % 8)
4036 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4037 alpha_nop(pcode); // TODO optimize later
4038 alpha_bsr(pcode, alpha_at, 2);
4040 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4042 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4045 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4055 volatile unsigned int *p = (unsigned int *)ip;
4056 unsigned int alpha_ins = *p;
4057 unsigned int opcode;
4060 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4062 if (opcode >= 0x30 && opcode <= 0x3f)
4064 // This is branch with offset instruction
4065 br_offset = (target - ip - 4);
4067 g_assert(!(br_offset & 3));
4069 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4077 /*========================= End of Function ========================*/
4078 /*------------------------------------------------------------------*/
4080 /* Name - mono_arch_emit_this_vret_args */
4084 /*------------------------------------------------------------------*/
4087 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4088 int this_reg, int this_type, int vt_reg)
4090 MonoCallInst *call = (MonoCallInst*)inst;
4091 CallInfo * cinfo = get_call_info (inst->signature, FALSE);
4093 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4099 if (cinfo->ret.storage == ArgValuetypeInReg)
4102 * The valuetype is in RAX:RDX after the call, need to be copied to
4103 * the stack. Push the address here, so the call instruction can
4106 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4107 //vtarg->sreg1 = vt_reg;
4108 //mono_bblock_add_inst (cfg->cbb, vtarg);
4111 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4116 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4117 vtarg->sreg1 = vt_reg;
4118 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4119 mono_bblock_add_inst (cfg->cbb, vtarg);
4121 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4122 cinfo->ret.reg, FALSE);
4126 /* add the this argument */
4130 MONO_INST_NEW (cfg, this, OP_MOVE);
4131 this->type = this_type;
4132 this->sreg1 = this_reg;
4133 this->dreg = mono_regstate_next_int (cfg->rs);
4134 mono_bblock_add_inst (cfg->cbb, this);
4136 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4137 cinfo->args [0].reg, FALSE);
4143 /*========================= End of Function ========================*/
4145 /*------------------------------------------------------------------*/
4147 /* Name - mono_arch_is_inst_imm */
4149 /* Function - Determine if operand qualifies as an immediate */
4150 /* value. For Alpha this is a value 0 - 255 */
4152 /* Returns - True|False - is [not] immediate value. */
4154 /*------------------------------------------------------------------*/
4157 mono_arch_is_inst_imm (gint64 imm)
4159 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4161 return (imm & ~(0x0FFL)) ? 0 : 1;
4164 /*------------------------------------------------------------------*/
4166 /* Name - mono_arch_setup_jit_tls_data */
4168 /* Function - Setup the JIT's Thread Level Specific Data. */
4170 /*------------------------------------------------------------------*/
4173 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4175 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4177 if (!tls_offset_inited) {
4178 tls_offset_inited = TRUE;
4181 if (!lmf_addr_key_inited) {
4182 lmf_addr_key_inited = TRUE;
4183 pthread_key_create (&lmf_addr_key, NULL);
4186 pthread_setspecific (lmf_addr_key, &tls->lmf);
4189 /*------------------------------------------------------------------*/
4191 /* Name - mono_arch_cpu_init */
4193 /* Function - Perform CPU specific initialization to execute */
4196 /*------------------------------------------------------------------*/
4199 mono_arch_cpu_init (void)
4201 ALPHA_DEBUG("mono_arch_cpu_init");
4208 * Obtain information about a call according to the calling convention.
4210 * For x86 ELF, see the "System V Application Binary Interface Intel386
4211 * Architecture Processor Supplment, Fourth Edition" document for more
4213 * For x86 win32, see ???.
4216 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
4218 guint32 i, gr, fr, *pgr, *pfr;
4220 int n = sig->hasthis + sig->param_count;
4221 guint32 stack_size = 0;
4224 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4239 ret_type = mono_type_get_underlying_type (sig->ret);
4240 switch (ret_type->type) {
4241 case MONO_TYPE_BOOLEAN:
4246 case MONO_TYPE_CHAR:
4252 case MONO_TYPE_FNPTR:
4253 case MONO_TYPE_CLASS:
4254 case MONO_TYPE_OBJECT:
4255 case MONO_TYPE_SZARRAY:
4256 case MONO_TYPE_ARRAY:
4257 case MONO_TYPE_STRING:
4258 cinfo->ret.storage = ArgInIReg;
4259 cinfo->ret.reg = alpha_r0;
4263 cinfo->ret.storage = ArgInIReg;
4264 cinfo->ret.reg = alpha_r0;
4267 cinfo->ret.storage = ArgInFloatReg;
4268 cinfo->ret.reg = alpha_f0;
4271 cinfo->ret.storage = ArgInDoubleReg;
4272 cinfo->ret.reg = alpha_f0;
4274 case MONO_TYPE_GENERICINST:
4275 if (!mono_type_generic_inst_is_valuetype (sig->ret))
4277 cinfo->ret.storage = ArgInIReg;
4278 cinfo->ret.reg = alpha_r0;
4282 case MONO_TYPE_VALUETYPE:
4284 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4286 add_valuetype (sig, &cinfo->ret, sig->ret, TRUE,
4287 &tmp_gr, &tmp_fr, &tmp_stacksize);
4289 if (cinfo->ret.storage == ArgOnStack)
4290 /* The caller passes the address where the value
4292 add_general (pgr, &stack_size, &cinfo->ret);
4295 case MONO_TYPE_TYPEDBYREF:
4296 /* Same as a valuetype with size 24 */
4297 add_general (pgr, &stack_size, &cinfo->ret);
4300 case MONO_TYPE_VOID:
4303 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4309 add_general (pgr, &stack_size, cinfo->args + 0);
4311 if (!sig->pinvoke &&
4312 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4315 fr = FLOAT_PARAM_REGS;
4317 /* Emit the signature cookie just before the implicit arguments
4319 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4322 for (i = 0; i < sig->param_count; ++i)
4324 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4327 if (!sig->pinvoke &&
4328 (sig->call_convention == MONO_CALL_VARARG) &&
4329 (i == sig->sentinelpos))
4331 /* We allways pass the sig cookie on the stack for simpl
4334 * Prevent implicit arguments + the sig cookie from being passed
4338 fr = FLOAT_PARAM_REGS;
4340 /* Emit the signature cookie just before the implicit arguments */
4341 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4344 if (sig->params [i]->byref) {
4345 add_general (pgr, &stack_size, ainfo);
4349 ptype = mono_type_get_underlying_type (sig->params [i]);
4351 switch (ptype->type) {
4352 case MONO_TYPE_BOOLEAN:
4355 add_general (pgr, &stack_size, ainfo);
4359 case MONO_TYPE_CHAR:
4360 add_general (pgr, &stack_size, ainfo);
4364 add_general (pgr, &stack_size, ainfo);
4369 case MONO_TYPE_FNPTR:
4370 case MONO_TYPE_CLASS:
4371 case MONO_TYPE_OBJECT:
4372 case MONO_TYPE_STRING:
4373 case MONO_TYPE_SZARRAY:
4374 case MONO_TYPE_ARRAY:
4375 add_general (pgr, &stack_size, ainfo);
4377 case MONO_TYPE_GENERICINST:
4378 if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
4380 add_general (pgr, &stack_size, ainfo);
4384 case MONO_TYPE_VALUETYPE:
4386 /* We allways pass valuetypes on the stack */
4387 add_valuetype (sig, ainfo, sig->params [i],
4388 FALSE, pgr, pfr, &stack_size);
4390 case MONO_TYPE_TYPEDBYREF:
4391 stack_size += sizeof (MonoTypedRef);
4392 ainfo->storage = ArgOnStack;
4396 add_general (pgr, &stack_size, ainfo);
4399 add_float (pfr, &stack_size, ainfo, FALSE);
4402 add_float (pfr, &stack_size, ainfo, TRUE);
4405 g_assert_not_reached ();
4409 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4410 (n > 0) && (sig->sentinelpos == sig->param_count))
4413 fr = FLOAT_PARAM_REGS;
4415 /* Emit the signature cookie just before the implicit arguments
4417 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4420 cinfo->stack_usage = stack_size;
4421 cinfo->reg_usage = gr;
4422 cinfo->freg_usage = fr;
4427 static const char *CvtMonoType(MonoTypeEnum t)
4432 return "MONO_TYPE_END";
4433 case MONO_TYPE_VOID:
4434 return "MONO_TYPE_VOID";
4435 case MONO_TYPE_BOOLEAN:
4436 return "MONO_TYPE_BOOLEAN";
4437 case MONO_TYPE_CHAR:
4438 return "MONO_TYPE_CHAR";
4440 return "MONO_TYPE_I1";
4442 return "MONO_TYPE_U1";
4444 return "MONO_TYPE_I2";
4446 return "MONO_TYPE_U2";
4448 return "MONO_TYPE_I4";
4450 return "MONO_TYPE_U4";
4452 return "MONO_TYPE_I8";
4454 return "MONO_TYPE_U8";
4456 return "MONO_TYPE_R4";
4458 return "MONO_TYPE_R8";
4459 case MONO_TYPE_STRING:
4460 return "MONO_TYPE_STRING";
4462 return "MONO_TYPE_PTR";
4463 case MONO_TYPE_BYREF:
4464 return "MONO_TYPE_BYREF";
4465 case MONO_TYPE_VALUETYPE:
4466 return "MONO_TYPE_VALUETYPE";
4467 case MONO_TYPE_CLASS:
4468 return "MONO_TYPE_CLASS";
4470 return "MONO_TYPE_VAR";
4471 case MONO_TYPE_ARRAY:
4472 return "MONO_TYPE_ARRAY";
4473 case MONO_TYPE_GENERICINST:
4474 return "MONO_TYPE_GENERICINST";
4475 case MONO_TYPE_TYPEDBYREF:
4476 return "MONO_TYPE_TYPEDBYREF";
4478 return "MONO_TYPE_I";
4480 return "MONO_TYPE_U";
4481 case MONO_TYPE_FNPTR:
4482 return "MONO_TYPE_FNPTR";
4483 case MONO_TYPE_OBJECT:
4484 return "MONO_TYPE_OBJECT";
4485 case MONO_TYPE_SZARRAY:
4486 return "MONO_TYPE_SZARRAY";
4487 case MONO_TYPE_MVAR:
4488 return "MONO_TYPE_MVAR";
4489 case MONO_TYPE_CMOD_REQD:
4490 return "MONO_TYPE_CMOD_REQD";
4491 case MONO_TYPE_CMOD_OPT:
4492 return "MONO_TYPE_CMOD_OPT";
4493 case MONO_TYPE_INTERNAL:
4494 return "MONO_TYPE_INTERNAL";
4495 case MONO_TYPE_MODIFIER:
4496 return "MONO_TYPE_MODIFIER";
4497 case MONO_TYPE_SENTINEL:
4498 return "MONO_TYPE_SENTINEL";
4499 case MONO_TYPE_PINNED:
4500 return "MONO_TYPE_PINNED";
4508 /*------------------------------------------------------------------*/
4510 /* Name - mono_arch_call_opcode */
4512 /* Function - Take the arguments and generate the arch-specific */
4513 /* instructions to properly call the function. This */
4514 /* includes pushing, moving argments to the correct */
4517 * This method is called during converting method to IR
4518 * We need to generate IR ints to follow calling convention
4519 * cfg - points to currently compiled unit
4521 * call - points to structure that describes what we are going to
4522 * call (at least number of parameters required for the call)
4525 * On return we need to pass back modified call structure
4527 /*------------------------------------------------------------------*/
4530 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4531 MonoCallInst *call, int is_virtual)
4534 MonoMethodSignature *sig;
4539 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4541 sig = call->signature;
4542 n = sig->param_count + sig->hasthis;
4544 // Collect info about method we age going to call
4545 cinfo = get_call_info (sig, sig->pinvoke);
4547 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4548 sig->pinvoke ? "PInvoke" : "Managed",
4549 sig->param_count, sig->hasthis,
4550 CvtMonoType(sig->ret->type), sig->ret->type);
4552 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4553 cfg->arch.params_stack_size = cinfo->stack_usage;
4555 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4556 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4558 for (i = 0; i < n; ++i)
4560 ArgInfo *ainfo = cinfo->args + i;
4562 /* Emit the signature cookie just before the implicit arguments
4564 if (!sig->pinvoke &&
4565 (sig->call_convention == MONO_CALL_VARARG) &&
4568 MonoMethodSignature *tmp_sig;
4571 /* FIXME: Add support for signature tokens to AOT */
4572 cfg->disable_aot = TRUE;
4573 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4576 * mono_ArgIterator_Setup assumes the signature cookie is
4577 * passed first and all the arguments which were before it are
4578 * passed on the stack after the signature. So compensate by
4579 * passing a different signature.
4581 tmp_sig = mono_metadata_signature_dup (call->signature);
4582 tmp_sig->param_count -= call->signature->sentinelpos;
4583 tmp_sig->sentinelpos = 0;
4584 memcpy (tmp_sig->params,
4585 call->signature->params + call->signature->sentinelpos,
4586 tmp_sig->param_count * sizeof (MonoType*));
4588 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4589 sig_arg->inst_p0 = tmp_sig;
4591 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4592 arg->inst_left = sig_arg;
4593 arg->type = STACK_PTR;
4595 /* prepend, so they get reversed */
4596 arg->next = call->out_args;
4597 call->out_args = arg;
4600 if (is_virtual && i == 0) {
4601 /* the argument will be attached to the call instrucion
4603 in = call->args [i];
4607 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4608 in = call->args [i];
4609 arg->cil_code = in->cil_code;
4610 arg->inst_left = in;
4611 arg->type = in->type;
4612 /* prepend, so they get reversed */
4613 arg->next = call->out_args;
4614 call->out_args = arg;
4616 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4618 if (sig->hasthis && (i == 0))
4619 arg_type = &mono_defaults.object_class->byval_arg;
4621 arg_type = sig->params [i - sig->hasthis];
4623 if ((i >= sig->hasthis) &&
4624 (MONO_TYPE_ISSTRUCT(arg_type)))
4629 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4630 size = sizeof (MonoTypedRef);
4631 align = sizeof (gpointer);
4635 size = mono_type_native_stack_size (&in->klass->byval_arg,
4638 size = mono_type_stack_size (&in->klass->byval_arg, &align);
4640 if (ainfo->storage == ArgAggregate)
4642 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4645 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4647 vtaddr = mono_compile_create_var (cfg,
4648 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4651 * Part of the structure is passed in registers.
4653 for (j = 0; j < ainfo->nregs; ++j)
4655 int offset, load_op, dest_reg, arg_storage;
4657 slot = ainfo->reg + j;
4658 load_op = CEE_LDIND_I;
4660 dest_reg = ainfo->reg + j;
4661 arg_storage = ArgInIReg;
4663 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4664 load->ssa_op = MONO_SSA_LOAD;
4665 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4667 NEW_ICONST (cfg, offset_ins, offset);
4668 MONO_INST_NEW (cfg, load2, CEE_ADD);
4669 load2->inst_left = load;
4670 load2->inst_right = offset_ins;
4672 MONO_INST_NEW (cfg, load, load_op);
4673 load->inst_left = load2;
4678 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4680 add_outarg_reg (cfg, call, set_reg, arg_storage,
4682 if (set_reg != call->out_args)
4684 set_reg->next = call->out_args;
4685 call->out_args = set_reg;
4690 * Part of the structure is passed on the stack.
4692 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4696 slot = ainfo->reg + j;
4698 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4699 load->ssa_op = MONO_SSA_LOAD;
4700 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4702 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4703 MONO_INST_NEW (cfg, load2, CEE_ADD);
4704 load2->inst_left = load;
4705 load2->inst_right = offset_ins;
4707 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4708 load->inst_left = load2;
4713 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4715 outarg->inst_left = load;
4716 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4717 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4719 if (outarg != call->out_args)
4721 outarg->next = call->out_args;
4722 call->out_args = outarg;
4726 /* Trees can't be shared so make a copy*/
4727 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4728 arg->cil_code = in->cil_code;
4729 arg->ssa_op = MONO_SSA_STORE;
4730 arg->inst_left = vtaddr;
4731 arg->inst_right = in;
4732 arg->type = in->type;
4734 /* prepend, so they get reversed */
4735 arg->next = call->out_args;
4736 call->out_args = arg;
4740 MonoInst *stack_addr;
4742 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4744 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4745 stack_addr->inst_basereg = alpha_sp;
4746 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4747 stack_addr->inst_offset = ainfo->offset;
4748 //stack_addr->inst_offset = 16 + ainfo->offset;
4749 stack_addr->inst_imm = size;
4751 arg->opcode = OP_OUTARG_VT;
4752 arg->inst_right = stack_addr;
4756 arg->opcode = OP_OUTARG_VT;
4757 arg->klass = in->klass;
4758 arg->backend.is_pinvoke = sig->pinvoke;
4759 arg->inst_imm = size; */
4763 CFG_DEBUG(3) g_print("simple\n");
4765 switch (ainfo->storage)
4768 add_outarg_reg (cfg, call, arg, ainfo->storage,
4772 arg->opcode = OP_OUTARG;
4773 //arg->dreg = -((n - i) * 8);
4774 arg->dreg = ainfo->offset;
4775 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4777 if (!sig->params[i-sig->hasthis]->byref) {
4778 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4779 arg->opcode = OP_OUTARG_R4;
4781 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4782 arg->opcode = OP_OUTARG_R8;
4786 case ArgInDoubleReg:
4787 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4790 g_assert_not_reached ();
4796 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4798 if (cinfo->ret.storage == ArgValuetypeInReg) {
4799 MonoInst *zero_inst;
4801 * After the call, the struct is in registers, but needs to be saved
4802 to the memory pointed
4803 * to by vt_arg in this_vret_args. This means that vt_ar
4804 g needs to be saved somewhere
4805 * before calling the function. So we add a dummy instru
4806 ction to represent pushing the
4807 * struct return address to the stack. The return addres
4808 s will be saved to this stack slot
4809 * by the code emitted in this_vret_args.
4811 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4812 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
4813 zero_inst->inst_p0 = 0;
4814 arg->inst_left = zero_inst;
4815 arg->type = STACK_PTR;
4816 /* prepend, so they get reversed */
4817 arg->next = call->out_args;
4818 call->out_args = arg;
4821 /* if the function returns a struct, the called method a
4822 lready does a ret $0x4 */
4823 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4824 ; //cinfo->stack_usage -= 4;
4827 // stack_usage shows how much stack we would need to do the call
4828 // (for example for params that we pass on stack
4829 call->stack_usage = cinfo->stack_usage;
4831 // Save all used regs to do the call in compile unit structure
4832 cfg->used_int_regs |= call->used_iregs;
4839 /*========================= End of Function ========================*/
4841 /*------------------------------------------------------------------*/
4843 /* Name - mono_arch_break */
4845 /* Function - Process a "break" operation for debugging. */
4847 /*------------------------------------------------------------------*/
4850 mono_arch_break(void) {
4854 /*------------------------------------------------------------------*/
4856 /* Name - mono_arch_register_lowlevel_calls */
4858 /* Function - Register routines to help with --trace operation. */
4860 /*------------------------------------------------------------------*/
4863 mono_arch_register_lowlevel_calls (void)
4865 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
4867 mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE);
4868 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
4872 /*========================= End of Function ========================*/
4874 /*------------------------------------------------------------------*/
4876 /* Name - mono_arch_global_int_regs */
4878 /* Function - Return a list of usable integer registers. */
4880 /*------------------------------------------------------------------*/
4883 mono_arch_get_global_int_regs (MonoCompile *cfg)
4887 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
4889 regs = g_list_prepend (regs, (gpointer)alpha_r9);
4890 regs = g_list_prepend (regs, (gpointer)alpha_r10);
4891 regs = g_list_prepend (regs, (gpointer)alpha_r11);
4892 regs = g_list_prepend (regs, (gpointer)alpha_r12);
4893 regs = g_list_prepend (regs, (gpointer)alpha_r13);
4894 regs = g_list_prepend (regs, (gpointer)alpha_r14);
4899 /*========================= End of Function ========================*/
4902 is_regsize_var (MonoType *t)
4907 t = mono_type_get_underlying_type (t);
4918 case MONO_TYPE_FNPTR:
4919 case MONO_TYPE_BOOLEAN:
4921 case MONO_TYPE_OBJECT:
4922 case MONO_TYPE_STRING:
4923 case MONO_TYPE_CLASS:
4924 case MONO_TYPE_SZARRAY:
4925 case MONO_TYPE_ARRAY:
4927 case MONO_TYPE_VALUETYPE:
4937 /*------------------------------------------------------------------*/
4939 /* Name - mono_arch_get_allocatable_int_vars */
4943 /*------------------------------------------------------------------*/
4946 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
4950 MonoMethodSignature *sig;
4951 MonoMethodHeader *header;
4954 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
4956 header = mono_method_get_header (cfg->method);
4958 sig = mono_method_signature (cfg->method);
4960 cinfo = get_call_info (sig, FALSE);
4962 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
4964 MonoInst *ins = cfg->varinfo [i];
4966 ArgInfo *ainfo = &cinfo->args [i];
4969 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
4972 // if (ainfo->storage == ArgInIReg) {
4973 // /* The input registers are non-volatile */
4974 // ins->opcode = OP_REGVAR;
4975 //ins->dreg = 32 + ainfo->reg;
4979 for (i = 0; i < cfg->num_varinfo; i++)
4981 MonoInst *ins = cfg->varinfo [i];
4982 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
4985 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
4989 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
4990 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
4993 if (is_regsize_var (ins->inst_vtype))
4995 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
4996 g_assert (i == vmv->idx);
4997 vars = g_list_prepend (vars, vmv);
5001 vars = mono_varlist_sort (cfg, vars, 0);
5006 /*========================= End of Function ========================*/
5008 /*------------------------------------------------------------------*/
5010 /* Name - mono_arch_get_domain_intrinsic */
5016 /*------------------------------------------------------------------*/
5019 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5023 if (appdomain_tls_offset == -1)
5026 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5027 ins->inst_offset = appdomain_tls_offset;
5031 /*========================= End of Function ========================*/
5033 /*------------------------------------------------------------------*/
5035 /* Name - mono_arch_get_thread_intrinsic */
5041 /*------------------------------------------------------------------*/
5044 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5048 if (thread_tls_offset == -1)
5051 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5052 ins->inst_offset = thread_tls_offset;
5056 /*========================= End of Function ========================*/
5058 /*------------------------------------------------------------------*/
5060 /* Name - mono_arch_get_inst_for_method */
5062 /* Function - Check for opcodes we can handle directly in */
5065 /*------------------------------------------------------------------*/
5068 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5069 MonoMethodSignature *fsig, MonoInst **args)
5071 MonoInst *ins = NULL;
5073 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5075 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5077 if (cmethod->klass == mono_defaults.thread_class &&
5078 strcmp (cmethod->name, "MemoryBarrier") == 0) {
5079 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5085 /*========================= End of Function ========================*/
5087 /*------------------------------------------------------------------*/
5089 /* Name - mono_arch_create_class_init_trampoline */
5091 /* Function - Creates a trampoline function to run a type init- */
5092 /* ializer. If the trampoline is called, it calls */
5093 /* mono_runtime_class_init with the given vtable, */
5094 /* then patches the caller code so it does not get */
5095 /* called any more. */
5097 /* Parameter - vtable - The type to initialize */
5099 /* Returns - A pointer to the newly created code */
5101 /*------------------------------------------------------------------*/
5104 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5106 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5108 NOT_IMPLEMENTED("mono_arch_create_class_init_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
5113 /*------------------------------------------------------------------*/
5115 /* Name - mono_arch_instrument_prolog */
5117 /* Function - Create an "instrumented" prolog. */
5119 /*------------------------------------------------------------------*/
5122 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5123 gboolean enable_arguments)
5125 unsigned int *code = p;
5128 CallInfo *cinfo = NULL;
5129 MonoMethodSignature *sig;
5131 int i, n, stack_area = 0;
5132 AlphaGotData ge_data;
5134 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5136 /* Keep this in sync with mono_arch_get_argument_info */
5137 if (enable_arguments)
5139 /* Allocate a new area on the stack and save arguments there */
5140 sig = mono_method_signature (cfg->method);
5142 cinfo = get_call_info (sig, FALSE);
5144 n = sig->param_count + sig->hasthis;
5146 stack_area = ALIGN_TO (n * 8, 8);
5148 // Correct stack by calculated value
5150 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5152 for (i = 0; i < n; ++i)
5154 inst = cfg->varinfo [i];
5156 if (inst->opcode == OP_REGVAR)
5158 switch(cinfo->args[i].storage)
5160 case ArgInDoubleReg:
5161 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5164 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5167 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5172 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5173 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5178 offset = (char *)code - (char *)cfg->native_code;
5180 ge_data.data.p = cfg->method;
5182 add_got_entry(cfg, GT_PTR, ge_data,
5183 (char *)code - (char *)cfg->native_code,
5184 MONO_PATCH_INFO_METHODCONST, cfg->method);
5185 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5187 alpha_mov1(code, alpha_sp, alpha_a1);
5189 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5191 if (enable_arguments)
5193 // Correct stack back by calculated value
5195 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5203 /*========================= End of Function ========================*/
5213 /*------------------------------------------------------------------*/
5215 /* Name - mono_arch_instrument_epilog */
5217 /* Function - Create an epilog that will handle the returned */
5218 /* values used in instrumentation. */
5220 /*------------------------------------------------------------------*/
5223 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p,
5224 gboolean enable_arguments)
5226 unsigned int *code = p;
5227 int save_mode = SAVE_NONE;
5229 MonoMethod *method = cfg->method;
5230 AlphaGotData ge_data;
5231 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5233 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5237 case MONO_TYPE_VOID:
5238 /* special case string .ctor icall */
5239 if (strcmp (".ctor", method->name) &&
5240 method->klass == mono_defaults.string_class)
5241 save_mode = SAVE_R0;
5243 save_mode = SAVE_NONE;
5247 save_mode = SAVE_R0;
5251 save_mode = SAVE_XMM;
5253 case MONO_TYPE_VALUETYPE:
5254 save_mode = SAVE_STRUCT;
5257 save_mode = SAVE_R0;
5261 /* Save the result and copy it into the proper argument register */
5265 alpha_lda(code, alpha_sp, alpha_sp, -8);
5266 alpha_stq(code, alpha_r0, alpha_sp, 0);
5268 if (enable_arguments)
5269 alpha_mov1(code, alpha_r0, alpha_a1);
5274 if (enable_arguments)
5275 alpha_lda(code, alpha_a1, alpha_zero, 0);
5279 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5280 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5282 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5284 * The result is already in the proper argument register so no copying
5291 g_assert_not_reached ();
5294 offset = (char *)code - (char *)cfg->native_code;
5296 ge_data.data.p = cfg->method;
5298 add_got_entry(cfg, GT_PTR, ge_data,
5299 (char *)code - (char *)cfg->native_code,
5300 MONO_PATCH_INFO_METHODCONST, cfg->method);
5302 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5304 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5306 /* Restore result */
5310 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5311 alpha_lda(code, alpha_sp, alpha_sp, 8);
5317 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5318 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5319 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5324 g_assert_not_reached ();
5330 /*========================= End of Function ========================*/
5332 /*------------------------------------------------------------------*/
5334 /* Name - mono_arch_allocate_vars */
5336 /* Function - Set var information according to the calling */
5337 /* convention for Alpha. The local var stuff should */
5338 /* most likely be split in another method. */
5340 /* Parameter - @m - Compile unit. */
5342 * This method is called right before working with BBs. Conversion to
5343 * IR was done and some analises what registers would be used.
5344 * Collect info about registers we used - if we want to use a register
5345 * we need to allocate space for it and save on the stack in method
5348 * Alpha calling convertion:
5349 * FP -> Stack top <- SP
5350 * 0: Stack params to call others
5352 * RA <- arch.params_stack_size
5355 * [LMF info] <- arch.lmf_offset
5357 * [possible return values allocated on stack]
5361 * . caller saved regs <- arch.reg_save_area_offset
5362 * . a0 <- arch.args_save_area_offset
5368 * ------------------------
5369 * . a6 - passed args on stack
5372 /*------------------------------------------------------------------*/
5375 mono_arch_allocate_vars (MonoCompile *cfg)
5377 MonoMethodSignature *sig;
5378 MonoMethodHeader *header;
5380 int i, offset = 0, a_off = 0;
5381 guint32 locals_stack_size, locals_stack_align = 0;
5385 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5387 header = mono_method_get_header (cfg->method);
5389 sig = mono_method_signature (cfg->method);
5391 cinfo = get_call_info (sig, FALSE);
5393 /* if (cfg->arch.omit_fp) {
5394 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5395 cfg->frame_reg = AMD64_RSP;
5400 /* Locals are allocated forwards from FP. After
5401 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5402 * (starting from offset 16).
5403 * FIXME: Check there Arg6...Argn are supposed to be
5405 cfg->frame_reg = alpha_fp;
5406 // offset = MONO_ALPHA_VARS_OFFSET;
5409 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5410 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5411 offset += cfg->arch.params_stack_size;
5413 offset += 16; // Size to save RA & FP
5415 if (cfg->method->save_lmf)
5417 /* Reserve stack space for saving LMF + argument regs */
5418 guint32 size = sizeof (MonoLMF);
5420 //if (lmf_tls_offset == -1)
5421 // /* Need to save argument regs too */
5422 // size += (AMD64_NREG * 8) + (8 * 8);
5424 cfg->arch.lmf_offset = offset;
5427 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5428 cfg->method->name, cfg->arch.lmf_offset, size);
5431 if (sig->ret->type != MONO_TYPE_VOID)
5433 switch (cinfo->ret.storage)
5437 case ArgInDoubleReg:
5438 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5439 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5440 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5442 /* The register is volatile */
5443 cfg->ret->opcode = OP_REGOFFSET;
5444 cfg->ret->inst_basereg = cfg->frame_reg;
5446 /*if (cfg->arch.omit_fp) {
5447 cfg->ret->inst_offset = offset;
5451 cfg->ret->inst_offset = offset;
5452 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5458 cfg->ret->opcode = OP_REGVAR;
5459 cfg->ret->inst_c0 = cinfo->ret.reg;
5462 case ArgValuetypeInReg:
5463 /* Allocate a local to hold the result, the epilog will
5464 copy it to the correct place */
5465 // g_assert (!cfg->arch.omit_fp);
5467 cfg->ret->opcode = OP_REGOFFSET;
5468 cfg->ret->inst_basereg = cfg->frame_reg;
5469 cfg->ret->inst_offset = offset;
5472 g_assert_not_reached ();
5474 cfg->ret->dreg = cfg->ret->inst_c0;
5477 /* Allocate locals */
5478 offsets = mono_allocate_stack_slots_full (cfg,
5479 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5481 &locals_stack_align);
5483 //g_assert((locals_stack_size % 8) == 0);
5484 if (locals_stack_size % 8)
5486 locals_stack_size += 8 - (locals_stack_size % 8);
5489 /* if (locals_stack_align)
5491 offset += (locals_stack_align - 1);
5492 offset &= ~(locals_stack_align - 1);
5496 cfg->arch.localloc_offset = offset;
5498 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5499 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5500 locals_stack_size, locals_stack_size);
5502 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5504 if (offsets [i] != -1) {
5505 MonoInst *inst = cfg->varinfo [i];
5506 inst->opcode = OP_REGOFFSET;
5507 inst->inst_basereg = cfg->frame_reg;
5508 //if (cfg->arch.omit_fp)
5509 // inst->inst_offset = (offset + offsets [i]);
5511 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5513 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5514 CFG_DEBUG(3) mono_print_tree_nl (inst);
5520 // TODO check how offsets[i] are calculated
5521 // it seems they are points to the end on data. Like 8, but it actually - 0
5523 offset += locals_stack_size; //+8;
5525 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5526 // g_assert (!cfg->arch.omit_fp);
5527 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5528 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5531 // Save offset for caller saved regs
5532 cfg->arch.reg_save_area_offset = offset;
5534 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5536 // Reserve space for caller saved registers
5537 for (i = 0; i < MONO_MAX_IREGS; ++i)
5538 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5539 (cfg->used_int_regs & (1 << i)))
5541 offset += sizeof (gpointer);
5544 // Save offset to args regs
5545 cfg->arch.args_save_area_offset = offset;
5547 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5549 // Consider floats passed in regs too
5550 for (i = 0; i < (PARAM_REGS*2); ++i)
5551 if (i < (sig->param_count + sig->hasthis))
5552 //(cfg->used_int_regs & (1 << param_regs[i])))
5554 offset += sizeof (gpointer);
5557 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5560 // Reserve space for method params
5561 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5563 inst = cfg->varinfo [i];
5565 if (inst->opcode != OP_REGVAR)
5567 ArgInfo *ainfo = &cinfo->args [i];
5568 gboolean inreg = TRUE;
5571 if (sig->hasthis && (i == 0))
5572 arg_type = &mono_defaults.object_class->byval_arg;
5574 arg_type = sig->params [i - sig->hasthis];
5576 /* FIXME: Allocate volatile arguments to registers */
5577 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5581 * Under AMD64, all registers used to pass arguments to functions
5582 * are volatile across calls. For Alpha too.
5583 * FIXME: Optimize this.
5587 if (inreg && (ainfo->storage == ArgInIReg)
5588 //&& cfg->used_int_regs & (1 << ainfo->reg)
5592 if (//(ainfo->storage == ArgInIReg) ||
5593 (ainfo->storage == ArgInFloatReg) ||
5594 (ainfo->storage == ArgInDoubleReg) ||
5595 (ainfo->storage == ArgValuetypeInReg))
5598 inst->opcode = OP_REGOFFSET;
5600 switch (ainfo->storage)
5604 case ArgInDoubleReg:
5605 inst->opcode = OP_REGVAR;
5606 inst->dreg = ainfo->reg;
5609 // g_assert (!cfg->arch.omit_fp);
5610 inst->opcode = OP_REGOFFSET;
5611 inst->inst_basereg = cfg->frame_reg;
5613 // "offset" here will point to the end of
5614 // array of saved ret,locals, args
5615 // Ideally it would point to "a7"
5616 inst->inst_offset = ainfo->offset + offset;
5618 case ArgValuetypeInReg:
5625 NOT_IMPLEMENTED("");
5628 if (!inreg && (ainfo->storage != ArgOnStack))
5630 inst->opcode = OP_REGOFFSET;
5631 inst->inst_basereg = cfg->frame_reg;
5633 /* These arguments are saved to the stack in the prolog */
5634 /*if (cfg->arch.omit_fp) {
5635 inst->inst_offset = offset;
5636 offset += (ainfo->storage == ArgValuetypeInReg) ?
5637 2 * sizeof (gpointer) : sizeof (gpointer);
5640 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5641 // 2 * sizeof (gpointer) : sizeof (gpointer);
5643 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5644 switch(ainfo->storage)
5647 a_off += ainfo->nslots * 8;
5650 a_off += sizeof (gpointer);
5652 // (/*(ainfo->reg - 16)*/ i * 8);
5658 cfg->stack_offset = offset;
5663 /*========================= End of Function ========================*/
5665 /*------------------------------------------------------------------*/
5667 /* Name - mono_arch_print_tree */
5669 /* Function - Print platform-specific opcode details. */
5671 /* Returns - 1 - opcode details have been printed */
5672 /* 0 - opcode details have not been printed */
5674 /*------------------------------------------------------------------*/
5677 mono_arch_print_tree (MonoInst *tree, int arity)
5681 ALPHA_DEBUG("mono_arch_print_tree");
5683 switch (tree->opcode) {
5690 /*========================= End of Function ========================*/
5694 ** mono_arch_get_vcall_slot_addr
5695 ** is called by mono_magic_trampoline to determine that the JIT compiled
5696 ** method is called via vtable slot. We need to analyze call sequence
5697 ** and determine that. In case it is true - we need to return address
5700 ** code - points to the next instruction after call
5701 ** reg - points to saved regs before the call (this is done
5702 ** by mono_magic_trampoline function
5706 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
5708 unsigned int *pc = (unsigned int *)code;
5710 int start_index = -2;
5712 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5715 // Check if we have parameters on stack
5716 if (pc[-2] & 0xFFFF0000 == 0x23DE0000) // lda sp,-n(sp)
5719 // Check for (call_membase):
5720 // -4: mov v0,a0 - load this ???
5721 // -3: ldq v0,0(v0) - load vtable
5722 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5723 if ((pc[start_index-1] & 0xFFFFFFFF) == 0xA4000000 &&
5724 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5727 disp = pc[start_index] & 0xFFFF;
5730 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5732 return (gpointer)(((guint64)(regs [reg])) + disp);
5735 // Check for interface call
5738 // -3: ldq v0,-n(v0)
5739 // -2: ldq t12,0(v0)
5740 if ((pc[start_index-2] & 0xFFFFFFFF) == 0xA4000000 &&
5741 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5742 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5745 disp = pc[start_index] & 0xFFFF;;
5748 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5750 return (gpointer)(((guint64)(regs [reg])) + disp);
5758 mono_arch_get_patch_offset (guint8 *code)