1 /*------------------------------------------------------------------*/
3 /* Name - mini-alpha.c */
5 /* Function - Alpha backend for the Mono code generator. */
7 /* Name - Sergey Tikhonov (tsv@solvo.ru) */
9 /* Date - January, 2006 */
11 /* Derivation - From mini-am64 & mini-ia64 & mini-s390 by - */
12 /* Paolo Molaro (lupus@ximian.com) */
13 /* Dietmar Maurer (dietmar@ximian.com) */
14 /* Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
16 /*------------------------------------------------------------------*/
18 /*------------------------------------------------------------------*/
20 /*------------------------------------------------------------------*/
21 #define ALPHA_DEBUG(x) \
22 if (mini_alpha_verbose_level) \
23 g_debug ("ALPHA_DEBUG: %s is called.", x);
25 #define ALPHA_PRINT if (mini_alpha_verbose_level)
27 #define NEW_INS(cfg,dest,op) do { \
28 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
29 (dest)->opcode = (op); \
30 insert_after_ins (bb, last_ins, (dest)); \
33 #define NEW_ICONST(cfg,dest,val) do { \
34 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
35 (dest)->opcode = OP_ICONST; \
36 (dest)->inst_c0 = (val); \
37 (dest)->type = STACK_I4; \
42 #define DEBUG(a) if (cfg->verbose_level > 1) a
44 #define CFG_DEBUG(LVL) if (cfg->verbose_level > LVL)
46 //#define ALPHA_IS_CALLEE_SAVED_REG(reg) (MONO_ARCH_CALLEE_SAVED_REGS & (1 << (reg)))
47 #define ALPHA_ARGS_REGS ((regmask_t)0x03F0000)
48 #define ARGS_OFFSET 16
50 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
51 #define alpha_is_imm(X) ((X >= 0 && X <= 255))
52 #define ALPHA_LOAD_GP(IP) { AlphaGotData ge_data; add_got_entry(cfg, GT_LD_GTADDR, ge_data, IP, MONO_PATCH_INFO_NONE, 0); }
54 /*========================= End of Defines =========================*/
56 /*------------------------------------------------------------------*/
58 /*------------------------------------------------------------------*/
63 #include <mono/metadata/appdomain.h>
64 #include <mono/metadata/debug-helpers.h>
65 #include <mono/metadata/profiler-private.h>
66 #include <mono/utils/mono-math.h>
69 #include "mini-alpha.h"
71 #include "cpu-alpha.h"
72 #include "jit-icalls.h"
74 /*========================= End of Includes ========================*/
76 /*------------------------------------------------------------------*/
77 /* G l o b a l V a r i a b l e s */
78 /*------------------------------------------------------------------*/
79 static int indent_level = 0;
81 int mini_alpha_verbose_level = 0;
82 static int bwx_supported = 0;
84 static gboolean tls_offset_inited = FALSE;
86 static int appdomain_tls_offset = -1,
88 thread_tls_offset = -1;
90 pthread_key_t lmf_addr_key;
92 gboolean lmf_addr_key_inited = FALSE;
95 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
97 /*====================== End of Global Variables ===================*/
99 gpointer mono_arch_get_lmf_addr (void);
106 ArgValuetypeInReg, // ??
117 /* Only if storage == ArgAggregate */
119 //AggregateType atype; // So far use only AggregateNormal
125 // guint32 struct_ret; /// ???
129 gboolean need_stack_align;
136 static CallInfo* get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke);
137 static unsigned int *emit_call(MonoCompile *cfg, unsigned int *code,
138 guint32 patch_type, gconstpointer data);
141 static int param_regs [] =
148 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
151 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
153 ainfo->offset = *stack_size;
155 if (*gr >= PARAM_REGS)
157 ainfo->storage = ArgOnStack;
158 (*stack_size) += sizeof (gpointer);
162 ainfo->storage = ArgInIReg;
163 ainfo->reg = param_regs [*gr];
168 #define FLOAT_PARAM_REGS 6
169 static int fparam_regs [] = { alpha_fa0, alpha_fa1, alpha_fa2, alpha_fa3,
170 alpha_fa4, alpha_fa5 };
173 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo,
176 ainfo->offset = *stack_size;
178 if (*gr >= FLOAT_PARAM_REGS)
180 ainfo->storage = ArgOnStack;
181 (*stack_size) += sizeof (gpointer);
185 /* A double register */
187 ainfo->storage = ArgInDoubleReg;
189 ainfo->storage = ArgInFloatReg;
191 ainfo->reg = fparam_regs [*gr];
197 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
199 guint32 *gr, guint32 *fr, guint32 *stack_size)
203 MonoMarshalType *info;
204 //gboolean is_hfa = TRUE;
205 //guint32 hfa_type = 0;
207 klass = mono_class_from_mono_type (type);
208 if (type->type == MONO_TYPE_TYPEDBYREF)
209 size = 3 * sizeof (gpointer);
210 else if (sig->pinvoke)
211 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
213 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
215 if (!sig->pinvoke || (size == 0) || is_return) {
216 /* Allways pass in memory */
217 ainfo->offset = *stack_size;
218 *stack_size += ALIGN_TO (size, 8);
219 ainfo->storage = ArgOnStack;
224 info = mono_marshal_load_type_info (klass);
227 ainfo->storage = ArgAggregate;
228 //ainfo->atype = AggregateNormal;
231 /* This also handles returning of TypedByRef used by some icalls */
234 ainfo->reg = IA64_R8;
235 ainfo->nregs = (size + 7) / 8;
236 ainfo->nslots = ainfo->nregs;
243 ainfo->reg = param_regs [*gr];
244 ainfo->offset = *stack_size;
245 ainfo->nslots = (size + 7) / 8;
247 if (((*gr) + ainfo->nslots) <= 6) {
248 /* Fits entirely in registers */
249 ainfo->nregs = ainfo->nslots;
250 (*gr) += ainfo->nregs;
254 ainfo->nregs = 6 - (*gr);
256 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
260 // This function is called from mono_arch_call_opcode and
261 // should determine which registers will be used to do the call
262 // For Alpha we could calculate number of parameter used for each
263 // call and allocate space in stack only for whose "a0-a5" registers
264 // that will be used in calls
266 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
267 ArgStorage storage, int reg, MonoInst *tree)
272 arg->opcode = OP_OUTARG_REG;
273 arg->inst_left = tree;
274 arg->inst_right = (MonoInst*)call;
275 arg->backend.reg3 = reg;
276 call->used_iregs |= 1 << reg;
279 arg->opcode = OP_OUTARG_FREG;
280 arg->inst_left = tree;
281 arg->inst_right = (MonoInst*)call;
282 arg->backend.reg3 = reg;
283 call->used_fregs |= 1 << reg;
286 arg->opcode = OP_OUTARG_FREG;
287 arg->inst_left = tree;
288 arg->inst_right = (MonoInst*)call;
289 arg->backend.reg3 = reg;
290 call->used_fregs |= 1 << reg;
293 g_assert_not_reached ();
298 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
303 bb->code = to_insert;
304 to_insert->next = ins;
308 to_insert->next = ins->next;
309 ins->next = to_insert;
313 static void add_got_entry(MonoCompile *cfg, AlphaGotType ge_type,
314 AlphaGotData ge_data,
315 int ip, MonoJumpInfoType type, gconstpointer target)
317 AlphaGotEntry *AGE = mono_mempool_alloc (cfg->mempool,
318 sizeof (AlphaGotEntry));
325 AGE->value.data.i = ge_data.data.i;
328 AGE->value.data.l = ge_data.data.l;
331 AGE->value.data.p = ge_data.data.p;
334 AGE->value.data.f = ge_data.data.f;
337 AGE->value.data.d = ge_data.data.d;
340 AGE->value.data.l = ip;
346 if (type != MONO_PATCH_INFO_NONE)
348 mono_add_patch_info(cfg, ip, type, target);
349 AGE->patch_info = cfg->patch_info;
354 if (AGE->type != GT_LD_GTADDR)
356 mono_add_patch_info(cfg, ip, MONO_PATCH_INFO_GOT_OFFSET, 0);
357 AGE->got_patch_info = cfg->patch_info;
360 AGE->next = cfg->arch.got_data;
362 cfg->arch.got_data = AGE;
365 /*------------------------------------------------------------------*/
367 /* Name - mono_arch_create_vars */
374 * cfg - pointer to compile unit
377 * This method is called right before starting converting compiled
378 * method to IR. I guess we could find out how many arguments we
379 * should expect, what type and what return value would be.
380 * After that we could correct "cfg" structure, or "arch" part of
384 /*------------------------------------------------------------------*/
387 mono_arch_create_vars (MonoCompile *cfg)
389 MonoMethodSignature *sig;
392 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
394 sig = mono_method_signature (cfg->method);
396 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
398 if (cinfo->ret.storage == ArgValuetypeInReg)
399 cfg->ret_var_is_local = TRUE;
405 /*------------------------------------------------------------------*/
407 /* Name - mono_arch_get_lmf_addr */
413 /*------------------------------------------------------------------*/
416 mono_arch_get_lmf_addr (void)
418 ALPHA_DEBUG("mono_arch_get_lmf_addr");
420 return pthread_getspecific (lmf_addr_key);
423 /*========================= End of Function ========================*/
425 /*------------------------------------------------------------------*/
427 /* Name - mono_arch_free_jit_tls_data */
429 /* Function - Free tls data. */
431 /*------------------------------------------------------------------*/
434 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
436 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
439 /*========================= End of Function ========================*/
441 // This peephole function is called before "local_regalloc" method
442 // TSV_TODO - Check what we need to move here
444 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
446 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_1 pass\n");
449 // This peephole function is called after "local_regalloc" method
451 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
453 MonoInst *ins, *n, *last_ins = NULL;
456 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_2 pass\n");
458 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
466 * OP_MOVE reg, reg except special case (mov at, at)
468 if (ins->dreg == ins->sreg1 &&
469 ins->dreg != alpha_at)
471 MONO_DELETE_INS (bb, ins);
481 if (last_ins && last_ins->opcode == OP_MOVE &&
482 ins->sreg1 == last_ins->dreg &&
483 last_ins->dreg != alpha_at &&
484 ins->dreg == last_ins->sreg1)
486 MONO_DELETE_INS (bb, ins);
493 /* remove unnecessary multiplication with 1 */
494 if (ins->inst_imm == 1)
496 if (ins->dreg != ins->sreg1)
498 ins->opcode = OP_MOVE;
502 MONO_DELETE_INS (bb, ins);
509 case OP_LOADI8_MEMBASE:
510 case OP_LOAD_MEMBASE:
512 * Note: if reg1 = reg2 the load op is removed
514 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
515 * OP_LOADI8_MEMBASE offset(basereg), reg2
517 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
521 (last_ins->opcode == OP_STOREI8_MEMBASE_REG ||
522 last_ins->opcode == OP_STORE_MEMBASE_REG) &&
523 ins->inst_basereg == last_ins->inst_destbasereg &&
524 ins->inst_offset == last_ins->inst_offset)
526 if (ins->dreg == last_ins->sreg1)
528 MONO_DELETE_INS (bb, ins);
533 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
534 ins->opcode = OP_MOVE;
535 ins->sreg1 = last_ins->sreg1;
541 case OP_LOAD_MEMBASE:
542 case OP_LOADI4_MEMBASE:
544 * Note: if reg1 = reg2 the load op is removed
546 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
547 * OP_LOAD_MEMBASE offset(basereg), reg2
549 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
552 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
553 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
554 ins->inst_basereg == last_ins->inst_destbasereg &&
555 ins->inst_offset == last_ins->inst_offset)
557 if (ins->dreg == last_ins->sreg1)
559 MONO_DELETE_INS (bb, ins);
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 MONO_DELETE_INS (bb, ins);
593 ins->opcode = OP_MOVE;
594 ins->sreg1 = last_ins->dreg;
597 //g_assert_not_reached ();
607 bb->last_ins = last_ins;
610 // Convert to opposite branch opcode
611 static guint16 cvt_branch_opcode(guint16 opcode)
616 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
621 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
625 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
629 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
633 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
637 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
641 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
645 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
649 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
653 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
657 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
661 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
665 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
669 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
673 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
677 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
681 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
685 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
689 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
693 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
697 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
701 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
705 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
709 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
713 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
720 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
725 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
727 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
733 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
744 return OP_ALPHA_CMP_EQ;
746 return OP_ALPHA_CMP_ULE;
748 return OP_ALPHA_CMP_LE;
750 return OP_ALPHA_CMP_LT;
752 return OP_ALPHA_CMP_ULT;
757 case OP_ICOMPARE_IMM:
763 return OP_ALPHA_CMP_IMM_EQ;
765 return OP_ALPHA_CMP_IMM_ULE;
767 return OP_ALPHA_CMP_IMM_LE;
769 return OP_ALPHA_CMP_IMM_LT;
771 return OP_ALPHA_CMP_IMM_ULT;
776 g_assert_not_reached();
781 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
783 // Instead of compare+b<cond>,
784 // Alpha has compare<cond>+br<cond>
785 // we need to convert
786 // Handle floating compare here too
792 // Convert cmp + beq -> cmpeq + bne
793 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
794 next->opcode = cvt_branch_opcode(next->opcode);
799 // cmp + ibne_un -> cmpeq + beq
800 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
801 next->opcode = cvt_branch_opcode(next->opcode);
806 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
807 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
808 next->opcode = cvt_branch_opcode(next->opcode);
813 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
814 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
815 next->opcode = cvt_branch_opcode(next->opcode);
820 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
821 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
822 next->opcode = cvt_branch_opcode(next->opcode);
827 // lcmp + blt.un -> cmpult + bne
828 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
829 next->opcode = cvt_branch_opcode(next->opcode);
834 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
835 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
836 next->opcode = cvt_branch_opcode(next->opcode);
841 //lcmp + bge.un -> cmpult + beq
842 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
843 next->opcode = cvt_branch_opcode(next->opcode);
848 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
849 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
850 next->opcode = cvt_branch_opcode(next->opcode);
855 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
856 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
857 next->opcode = cvt_branch_opcode(next->opcode);
863 // cmp + cgt_un -> cmpule + beq
864 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
869 // cmp + iceq -> cmpeq + bne
870 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
875 // cmp + int_cgt -> cmple + beq
876 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
881 // cmp + int_clt -> cmplt + bne
882 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
887 // cmp + int_clt_un -> cmpult + bne
888 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
892 // The conditional exceptions will be handled in
893 // output_basic_blocks. Here we just determine correct
896 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
899 case OP_COND_EXC_GT_UN:
900 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
904 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
907 case OP_COND_EXC_LT_UN:
908 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
911 case OP_COND_EXC_LE_UN:
912 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
915 case OP_COND_EXC_NE_UN:
916 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
920 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
925 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
926 mono_inst_name(next->opcode), next->opcode);
928 // g_assert_not_reached();
936 * mono_arch_lowering_pass:
938 * Converts complex opcodes into simpler ones so that each IR instruction
939 * corresponds to one machine instruction.
942 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
944 MonoInst *ins, *n, *temp, *last_ins = NULL;
949 if (bb->max_vreg > cfg->rs->next_vreg)
950 cfg->rs->next_vreg = bb->max_vreg;
953 * FIXME: Need to add more instructions, but the current machine
954 * description can't model some parts of the composite instructions like
958 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
966 NEW_INS (cfg, temp, OP_I8CONST);
967 temp->inst_c0 = ins->inst_imm;
968 temp->dreg = mono_regstate_next_int (cfg->rs);
973 ins->opcode = CEE_MUL;
976 ins->opcode = OP_LDIV;
979 ins->opcode = OP_LREM;
982 ins->opcode = OP_IDIV;
985 ins->opcode = OP_IREM;
989 ins->sreg2 = temp->dreg;
997 // Instead of compare+b<cond>/fcompare+b<cond>,
998 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
999 // we need to convert
1002 cvt_cmp_branch(ins, next);
1006 case OP_COMPARE_IMM:
1007 if (!alpha_is_imm (ins->inst_imm))
1009 NEW_INS (cfg, temp, OP_I8CONST);
1010 temp->inst_c0 = ins->inst_imm;
1011 temp->dreg = mono_regstate_next_int (cfg->rs);
1012 ins->opcode = OP_COMPARE;
1013 ins->sreg2 = temp->dreg;
1015 // We should try to reevaluate new IR opcode
1021 cvt_cmp_branch(ins, next);
1025 case OP_ICOMPARE_IMM:
1026 if (!alpha_is_imm (ins->inst_imm))
1028 NEW_INS (cfg, temp, OP_ICONST);
1029 temp->inst_c0 = ins->inst_imm;
1030 temp->dreg = mono_regstate_next_int (cfg->rs);
1031 ins->opcode = OP_ICOMPARE;
1032 ins->sreg2 = temp->dreg;
1034 // We should try to reevaluate new IR opcode
1040 cvt_cmp_branch(ins, next);
1044 case OP_STORE_MEMBASE_IMM:
1045 case OP_STOREI8_MEMBASE_IMM:
1046 if (ins->inst_imm != 0)
1048 NEW_INS (cfg, temp, OP_I8CONST);
1049 temp->inst_c0 = ins->inst_imm;
1050 temp->dreg = mono_regstate_next_int (cfg->rs);
1051 ins->opcode = OP_STOREI8_MEMBASE_REG;
1052 ins->sreg1 = temp->dreg;
1056 case OP_STOREI4_MEMBASE_IMM:
1057 if (ins->inst_imm != 0)
1060 NEW_INS (cfg, temp, OP_ICONST);
1061 temp->inst_c0 = ins->inst_imm;
1062 temp->dreg = mono_regstate_next_int (cfg->rs);
1063 ins->opcode = OP_STOREI4_MEMBASE_REG;
1064 ins->sreg1 = temp->dreg;
1068 case OP_STOREI1_MEMBASE_IMM:
1069 if (ins->inst_imm != 0 || !bwx_supported)
1072 NEW_INS (cfg, temp, OP_ICONST);
1073 temp->inst_c0 = ins->inst_imm;
1074 temp->dreg = mono_regstate_next_int (cfg->rs);
1075 ins->opcode = OP_STOREI1_MEMBASE_REG;
1076 ins->sreg1 = temp->dreg;
1080 case OP_STOREI2_MEMBASE_IMM:
1081 if (ins->inst_imm != 0 || !bwx_supported)
1084 NEW_INS (cfg, temp, OP_ICONST);
1085 temp->inst_c0 = ins->inst_imm;
1086 temp->dreg = mono_regstate_next_int (cfg->rs);
1087 ins->opcode = OP_STOREI2_MEMBASE_REG;
1088 ins->sreg1 = temp->dreg;
1099 case OP_ISHR_UN_IMM:
1100 if (!alpha_is_imm(ins->inst_imm))
1103 NEW_INS (cfg, temp, OP_ICONST);
1104 temp->inst_c0 = ins->inst_imm;
1105 temp->dreg = mono_regstate_next_int (cfg->rs);
1110 ins->opcode = OP_IADD;
1113 ins->opcode = OP_ISUB;
1116 ins->opcode = OP_IAND;
1119 ins->opcode = OP_IOR;
1122 ins->opcode = OP_IXOR;
1125 ins->opcode = OP_ISHL;
1128 ins->opcode = OP_ISHR;
1130 case OP_ISHR_UN_IMM:
1131 ins->opcode = OP_ISHR_UN;
1137 ins->sreg2 = temp->dreg;
1143 if (!alpha_is_imm(ins->inst_imm))
1146 NEW_INS (cfg, temp, OP_ICONST);
1147 temp->inst_c0 = ins->inst_imm;
1148 temp->dreg = mono_regstate_next_int (cfg->rs);
1153 ins->opcode = CEE_ADD;
1156 ins->opcode = CEE_SUB;
1159 ins->opcode = CEE_AND;
1162 ins->opcode = CEE_SHL;
1168 ins->sreg2 = temp->dreg;
1172 if (!alpha_is_imm(ins->inst_imm))
1175 NEW_INS(cfg, temp, OP_ICONST);
1176 temp->inst_c0 = ins->inst_imm;
1177 temp->dreg = mono_regstate_next_int(cfg->rs);
1178 ins->sreg2 = temp->dreg;
1179 ins->opcode = OP_LSHR;
1183 if (!alpha_is_imm(ins->inst_imm))
1186 NEW_INS(cfg, temp, OP_ICONST);
1187 temp->inst_c0 = ins->inst_imm;
1188 temp->dreg = mono_regstate_next_int(cfg->rs);
1189 ins->sreg2 = temp->dreg;
1190 ins->opcode = OP_LSHL;
1202 bb->last_ins = last_ins;
1204 bb->max_vreg = cfg->rs->next_vreg;
1207 /*========================= End of Function ========================*/
1209 #define AXP_GENERAL_REGS 6
1210 #define AXP_MIN_STACK_SIZE 24
1212 /* A typical Alpha stack frame looks like this */
1214 fun: // called from outside the module.
1215 ldgp gp,0(pv) // load the global pointer
1216 fun..ng: // called from inside the module.
1217 lda sp, -SIZE( sp ) // grow the stack downwards.
1219 stq ra, 0(sp) // save the return address.
1221 stq s0, 8(sp) // callee-saved registers.
1222 stq s1, 16(sp) // ...
1224 // Move the arguments to the argument registers...
1226 mov addr, pv // Load the callee address
1227 jsr ra, (pv) // call the method.
1228 ldgp gp, 0(ra) // restore gp
1230 // return value is in v0
1232 ldq ra, 0(sp) // free stack frame
1233 ldq s0, 8(sp) // restore callee-saved registers.
1235 ldq sp, 32(sp) // restore stack pointer
1237 ret zero, (ra), 1 // return.
1240 // our call must look like this.
1246 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1247 stq ra, SIZE-48(sp) // store ra
1248 stq fp, SIZE-40(sp) // store fp (frame pointer)
1249 stq a0, SIZE-32(sp) // store args. a0 = func
1250 stq a1, SIZE-24(sp) // a1 = retval
1251 stq a2, SIZE-16(sp) // a2 = this
1252 stq a3, SIZE-8(sp) // a3 = args
1253 mov sp, fp // set frame pointer
1273 jsr ra, (pv) // call func
1274 ldgp gp, 0(ra) // restore gp.
1275 mov v0, t1 // move return value into t1
1278 ldq t0, SIZE-24(fp) // load retval into t2
1279 stl t1, 0(t0) // store value.
1290 * emit_load_volatile_arguments:
1292 * Load volatile arguments from the stack to the original input registers.
1293 * Required before a tail call.
1295 static unsigned int*
1296 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1298 MonoMethod *method = cfg->method;
1299 MonoMethodSignature *sig;
1304 /* FIXME: Generate intermediate code instead */
1306 sig = mono_method_signature (method);
1308 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1310 if (sig->ret->type != MONO_TYPE_VOID) {
1311 if ((cinfo->ret.storage == ArgInIReg) &&
1312 (cfg->ret->opcode != OP_REGVAR))
1314 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1315 cfg->ret->inst_offset);
1319 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1321 ArgInfo *ainfo = &cinfo->args [i];
1322 MonoInst *inst = cfg->args [i];
1324 switch(ainfo->storage)
1327 // We need to save all used a0-a5 params
1328 //for (i=0; i<PARAM_REGS; i++)
1330 // if (i < cinfo->reg_usage)
1332 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1333 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1335 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1336 ainfo->reg, inst->inst_offset/*offset*/);
1340 case ArgInDoubleReg:
1342 // We need to save all used af0-af5 params
1343 //for (i=0; i<PARAM_REGS; i++)
1345 // if (i < cinfo->freg_usage)
1347 switch(cinfo->args[i].storage)
1350 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1351 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1353 case ArgInDoubleReg:
1354 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1355 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1361 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1362 ainfo->reg, /*offset*/inst->inst_offset);
1371 /*------------------------------------------------------------------*/
1373 /* Name - mono_arch_emit_prolog */
1375 /* Function - Create the instruction sequence for a function */
1378 * How to handle consts and method addreses:
1379 * For method we will allocate array of qword after method epiloge.
1380 * These qword will hold readonly info to method to properly to run.
1381 * For example: qword constants, method addreses
1382 * GP will point to start of data. Offsets to the data will be equal
1383 * to "address" of data - start of GP. (GP = 0 during method jiting).
1384 * GP is easily calculated from passed PV (method start address).
1385 * The patch will update GP loadings.
1386 * The GOT section should be more than 32Kb.
1387 * The patch code should put proper offset since the real position of
1388 * qword array will be known after the function epiloge.
1390 /*------------------------------------------------------------------*/
1393 mono_arch_emit_prolog (MonoCompile *cfg)
1395 MonoMethod *method = cfg->method;
1396 MonoMethodSignature *sig = mono_method_signature (method);
1397 //int alloc_size, code_size, max_offset, quad;
1400 int i, stack_size, offset;
1401 gint32 lmf_offset = cfg->arch.lmf_offset;
1403 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1405 // FIXME: Use just one field to hold calculated stack size
1406 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1407 cfg->arch.got_data = 0;
1409 cfg->code_size = 512;
1411 code = (unsigned int *)g_malloc(cfg->code_size);
1412 cfg->native_code = (void *)code;
1414 // Emit method prolog
1415 // Calculate GP from passed PV, allocate stack
1417 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1418 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1419 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1421 offset = cfg->arch.params_stack_size;
1423 /* store call convention parameters on stack */
1424 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1425 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1427 /* set the frame pointer */
1428 alpha_mov1( code, alpha_sp, alpha_fp );
1431 if (method->save_lmf)
1434 alpha_stq(code, alpha_pv, alpha_fp,
1435 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1437 alpha_stq(code, alpha_sp, alpha_fp,
1438 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1440 alpha_stq(code, alpha_fp, alpha_fp,
1441 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1443 alpha_stq(code, alpha_gp, alpha_fp,
1444 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1447 alpha_stq(code, alpha_pv, alpha_fp,
1448 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1451 /* Save (global) regs */
1452 offset = cfg->arch.reg_save_area_offset;
1454 for (i = 0; i < MONO_MAX_IREGS; ++i)
1455 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1456 (cfg->used_int_regs & (1 << i)) &&
1457 !( ALPHA_ARGS_REGS & (1 << i)) )
1459 alpha_stq(code, i, alpha_fp, offset);
1460 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1465 offset = cfg->arch.args_save_area_offset;
1467 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1469 if (sig->ret->type != MONO_TYPE_VOID)
1471 if ((cinfo->ret.storage == ArgInIReg) &&
1472 (cfg->ret->opcode != OP_REGVAR))
1474 /* Save volatile arguments to the stack */
1475 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1476 cfg->ret->inst_offset);
1480 /* Keep this in sync with emit_load_volatile_arguments */
1481 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1483 ArgInfo *ainfo = &cinfo->args [i];
1484 MonoInst *inst = cfg->args [i];
1487 switch(ainfo->storage)
1490 // We need to save all used a0-a5 params
1492 if (inst->opcode == OP_REGVAR)
1494 alpha_mov1(code, ainfo->reg, inst->dreg);
1495 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1496 ainfo->reg, inst->dreg);
1500 alpha_stq(code, ainfo->reg, inst->inst_basereg,
1503 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1504 ainfo->reg, inst->inst_offset);
1512 for(j=0; j<ainfo->nregs; j++)
1514 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1515 ainfo->reg + j, inst->inst_offset + (8*j));
1516 alpha_stq(code, (ainfo->reg+j), inst->inst_basereg,
1517 (inst->inst_offset + (8*j)));
1522 case ArgInDoubleReg:
1524 // We need to save all used af0-af5 params
1526 switch(cinfo->args[i].storage)
1529 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1530 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1532 case ArgInDoubleReg:
1533 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1534 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1540 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1541 ainfo->reg, /*offset*/inst->inst_offset);
1548 offset = cfg->arch.reg_save_area_offset;
1551 for (i = 0; i < MONO_MAX_VREGS; ++i)
1552 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1553 (cfg->used_int_regs & (1 << i)) &&
1554 !( ALPHA_ARGS_REGS & (1 << i)) )
1556 alpha_stq(code, i, alpha_fp, offset);
1557 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1562 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1564 if (method->save_lmf)
1567 * The call might clobber argument registers, but they are already
1568 * saved to the stack/global regs.
1571 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1572 (gpointer)"mono_get_lmf_addr");
1575 alpha_stq(code, alpha_r0, alpha_fp,
1576 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1577 // Load "previous_lmf" member of MonoLMF struct
1578 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1580 // Save it to MonoLMF struct
1581 alpha_stq(code, alpha_r1, alpha_fp,
1582 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1585 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1586 alpha_stq(code, alpha_r1, alpha_r0, 0);
1591 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1592 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1595 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1597 g_assert (cfg->code_len < cfg->code_size);
1599 return (gint8 *)code;
1602 /*========================= End of Function ========================*/
1604 /*------------------------------------------------------------------*/
1606 /* Name - mono_arch_flush_register_windows */
1612 /*------------------------------------------------------------------*/
1615 mono_arch_flush_register_windows (void)
1617 ALPHA_DEBUG("mono_arch_flush_register_windows");
1619 /*========================= End of Function ========================*/
1621 /*------------------------------------------------------------------*/
1623 /* Name - mono_arch_regalloc_cost */
1625 /* Function - Determine the cost, in the number of memory */
1626 /* references, of the action of allocating the var- */
1627 /* iable VMV into a register during global register */
1630 /* Returns - Cost */
1632 /*------------------------------------------------------------------*/
1635 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1637 MonoInst *ins = cfg->varinfo [vmv->idx];
1640 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1642 if (cfg->method->save_lmf)
1643 /* The register is already saved */
1644 /* substract 1 for the invisible store in the prolog */
1645 return (ins->opcode == OP_ARG) ? 1 : 0;
1648 return (ins->opcode == OP_ARG) ? 2 : 1;
1651 /*========================= End of Function ========================*/
1655 ** This method emits call sequience
1658 static unsigned int *
1659 emit_call(MonoCompile *cfg, unsigned int *code,
1660 guint32 patch_type, gconstpointer data)
1663 AlphaGotData ge_data;
1665 offset = (char *)code - (char *)cfg->native_code;
1667 ge_data.data.p = (void *)data;
1668 add_got_entry(cfg, GT_PTR, ge_data,
1669 offset, patch_type, data);
1671 // Load call address into PV
1672 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1675 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1677 offset = (char *)code - (char *)cfg->native_code;
1680 ALPHA_LOAD_GP(offset)
1681 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1682 alpha_lda(code, alpha_gp, alpha_gp, 0);
1687 /*------------------------------------------------------------------*/
1689 /* Name - arch_get_argument_info */
1691 /* Function - Gathers information on parameters such as size, */
1692 /* alignment, and padding. arg_info should be large */
1693 /* enough to hold param_count + 1 entries. */
1695 /* Parameters - @csig - Method signature */
1696 /* @param_count - No. of parameters to consider */
1697 /* @arg_info - An array to store the result info */
1699 /* Returns - Size of the activation frame */
1701 /*------------------------------------------------------------------*/
1704 mono_arch_get_argument_info (MonoMethodSignature *csig,
1706 MonoJitArgumentInfo *arg_info)
1709 CallInfo *cinfo = get_call_info (NULL, csig, FALSE);
1710 guint32 args_size = cinfo->stack_usage;
1712 ALPHA_DEBUG("mono_arch_get_argument_info");
1714 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1717 arg_info [0].offset = 0;
1720 for (k = 0; k < param_count; k++)
1722 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1726 // The size is checked only for valuetype in trace.c
1727 arg_info [k + 1].size = 8;
1735 /*------------------------------------------------------------------*/
1737 /* Name - mono_arch_emit_epilog */
1739 /* Function - Emit the instructions for a function epilog. */
1741 /*------------------------------------------------------------------*/
1744 mono_arch_emit_epilog (MonoCompile *cfg)
1746 MonoMethod *method = cfg->method;
1749 int max_epilog_size = 128;
1750 int stack_size = cfg->arch.stack_size;
1752 gint32 lmf_offset = cfg->arch.lmf_offset;
1754 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1756 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1758 cfg->code_size *= 2;
1759 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1760 mono_jit_stats.code_reallocs++;
1763 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1765 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1766 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1769 if (method->save_lmf)
1771 /* Restore previous lmf */
1772 alpha_ldq(code, alpha_at, alpha_fp,
1773 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1774 alpha_ldq(code, alpha_ra, alpha_fp,
1775 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1776 alpha_stq(code, alpha_at, alpha_ra, 0);
1780 alpha_mov1( code, alpha_fp, alpha_sp );
1782 // Restore saved regs
1783 offset = cfg->arch.reg_save_area_offset;
1785 for (i = 0; i < MONO_MAX_IREGS; ++i)
1786 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1787 (cfg->used_int_regs & (1 << i)) &&
1788 !( ALPHA_ARGS_REGS & (1 << i)) )
1790 alpha_ldq(code, i, alpha_sp, offset);
1791 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1796 /* restore fp, ra, sp */
1797 offset = cfg->arch.params_stack_size;
1799 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1800 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1801 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1804 alpha_ret( code, alpha_ra, 1 );
1806 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1808 g_assert (cfg->code_len < cfg->code_size);
1811 /*========================= End of Function ========================*/
1813 /*------------------------------------------------------------------*/
1815 /* Name - mono_arch_emit_exceptions */
1817 /* Function - Emit the blocks to handle exception conditions. */
1819 /*------------------------------------------------------------------*/
1822 mono_arch_emit_exceptions (MonoCompile *cfg)
1824 MonoJumpInfo *patch_info;
1826 unsigned int *code, *got_start;
1827 unsigned long *corlib_exc_adr;
1828 MonoClass *exc_classes [16];
1829 guint8 *exc_throw_start [16], *exc_throw_end [16];
1830 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1831 AlphaGotEntry *got_data;
1833 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1835 /* Compute needed space */
1836 for (patch_info = cfg->patch_info; patch_info;
1837 patch_info = patch_info->next)
1839 if (patch_info->type == MONO_PATCH_INFO_EXC)
1841 if (patch_info->type == MONO_PATCH_INFO_R8)
1842 code_size += 8 + 7; /* sizeof (double) + alignment */
1843 if (patch_info->type == MONO_PATCH_INFO_R4)
1844 code_size += 4 + 7; /* sizeof (float) + alignment */
1847 // Reserve space for GOT entries
1848 for (got_data = cfg->arch.got_data; got_data;
1849 got_data = got_data->next)
1851 // Reserve space for 8 byte const (for now)
1852 if (got_data->type != GT_LD_GTADDR)
1856 while (cfg->code_len + code_size > (cfg->code_size - 16))
1858 cfg->code_size *= 2;
1859 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1860 mono_jit_stats.code_reallocs++;
1863 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1865 // Set code alignment
1866 if (((unsigned long)code) % 8)
1871 /* Add code to store conts and modify patch into to store offset in got */
1872 for (got_data = cfg->arch.got_data; got_data;
1873 got_data = got_data->next)
1875 unsigned long data = got_data->value.data.l;
1876 MonoJumpInfo *got_ref = got_data->got_patch_info;
1878 // Modify loading of GP
1879 if (got_data->type == GT_LD_GTADDR)
1881 short high_off, low_off;
1882 unsigned int *ldgp_code =
1883 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1884 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1886 high_off = got_off / 0x10000;
1887 low_off = got_off % 0x10000;
1891 // Set offset from current point to GOT array
1892 // modify the following code sequence
1893 // ldah gp, 0(pv) or ldah gp, 0(ra)
1895 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1897 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1902 patch_info = got_data->patch_info;
1904 // Check code alignment
1905 if (((unsigned long)code) % 8)
1908 got_ref->data.offset = ((char *)code - (char *)got_start);
1911 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1913 *code = (unsigned int)(data & 0xFFFFFFFF);
1915 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1920 corlib_exc_adr = (unsigned long *)code;
1922 /* add code to raise exceptions */
1924 for (patch_info = cfg->patch_info; patch_info;
1925 patch_info = patch_info->next)
1927 switch (patch_info->type)
1929 case MONO_PATCH_INFO_EXC:
1931 MonoClass *exc_class;
1932 unsigned int *buf, *buf2;
1937 // Add patch info to call mono_arch_throw_corlib_exception
1938 // method to raise corlib exception
1939 // Will be added at the begining of the patch info list
1940 mono_add_patch_info(cfg,
1941 ((char *)code - (char *)cfg->native_code),
1942 MONO_PATCH_INFO_INTERNAL_METHOD,
1943 "mono_arch_throw_corlib_exception");
1945 // Skip longword before starting the code
1950 exc_class = mono_class_from_name (mono_defaults.corlib,
1951 "System", patch_info->data.name);
1953 g_assert (exc_class);
1954 throw_ip = patch_info->ip.i;
1956 //x86_breakpoint (code);
1957 /* Find a throw sequence for the same exception class */
1958 for (i = 0; i < nthrows; ++i)
1959 if (exc_classes [i] == exc_class)
1966 // Patch original branch (patch info) to jump here
1967 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1968 patch_info->data.target =
1969 (char *)code - (char *)cfg->native_code;
1971 alpha_lda(code, alpha_a1, alpha_zero,
1972 -((short)((((char *)exc_throw_end[i] -
1973 (char *)cfg->native_code)) - throw_ip) - 4) );
1975 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
1977 alpha_bsr(code, alpha_zero, br_offset);
1983 // Save exception token type as first 32bit word for new
1984 // exception handling jump code
1985 *code = exc_class->type_token;
1988 // Patch original branch (patch info) to jump here
1989 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1990 patch_info->data.target =
1991 (char *)code - (char *)cfg->native_code;
1994 alpha_lda(code, alpha_a1, alpha_zero, 0);
1998 exc_classes [nthrows] = exc_class;
1999 exc_throw_start [nthrows] = code;
2002 // Load exception token
2003 alpha_ldl(code, alpha_a0, alpha_gp,
2004 ((char *)buf - (char *)got_start /*cfg->native_code*/));
2005 // Load corlib exception raiser code address
2006 alpha_ldq(code, alpha_pv, alpha_gp,
2007 ((char *)corlib_exc_adr -
2008 (char *)got_start /*cfg->native_code*/));
2010 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
2011 //patch_info->data.name = "mono_arch_throw_corlib_exception";
2012 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
2013 //patch_info->type = MONO_PATCH_INFO_NONE;
2014 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
2016 if (cfg->compile_aot)
2018 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
2019 //amd64_call_reg (code, GP_SCRATCH_REG);
2021 /* The callee is in memory allocated using
2023 alpha_jsr(code, alpha_ra, alpha_pv, 0);
2026 alpha_lda(buf2, alpha_a1, alpha_zero,
2027 -((short)(((char *)code - (char *)cfg->native_code) -
2032 exc_throw_end [nthrows] = code;
2044 /* Handle relocations with RIP relative addressing */
2045 for (patch_info = cfg->patch_info; patch_info;
2046 patch_info = patch_info->next)
2048 gboolean remove = FALSE;
2050 switch (patch_info->type)
2052 case MONO_PATCH_INFO_R8:
2056 code = (guint8*)ALIGN_TO (code, 8);
2058 pos = cfg->native_code + patch_info->ip.i;
2060 *(double*)code = *(double*)patch_info->data.target;
2063 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2065 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2071 case MONO_PATCH_INFO_R4:
2075 code = (guint8*)ALIGN_TO (code, 8);
2077 pos = cfg->native_code + patch_info->ip.i;
2079 *(float*)code = *(float*)patch_info->data.target;
2082 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2084 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2096 if (patch_info == cfg->patch_info)
2097 cfg->patch_info = patch_info->next;
2102 for (tmp = cfg->patch_info; tmp->next != patch_info;
2105 tmp->next = patch_info->next;
2110 cfg->code_len = (char *)code - (char *)cfg->native_code;
2112 g_assert (cfg->code_len < cfg->code_size);
2116 /*========================= End of Function ========================*/
2118 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2119 offset = ((char *)code - \
2120 (char *)cfg->native_code); \
2121 if (Tins->flags & MONO_INST_BRLABEL) \
2123 if (Tins->inst_i0->inst_c0) \
2125 CFG_DEBUG(3) g_print("inst_c0: %0lX, data: %p]\n", \
2126 Tins->inst_i0->inst_c0, \
2127 cfg->native_code + Tins->inst_i0->inst_c0); \
2128 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2132 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n", \
2133 offset, Tins->inst_i0); \
2134 mono_add_patch_info (cfg, offset, \
2135 MONO_PATCH_INFO_LABEL, Tins->inst_i0); \
2136 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2141 if (Tins->inst_true_bb->native_offset) \
2143 long br_offset = (char *)cfg->native_code + \
2144 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2145 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2146 Tins->inst_target_bb->native_offset, \
2147 cfg->native_code + \
2148 Tins->inst_true_bb->native_offset); \
2149 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2153 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2154 offset, Tins->inst_target_bb); \
2155 mono_add_patch_info (cfg, offset, \
2156 MONO_PATCH_INFO_BB, \
2157 Tins->inst_true_bb); \
2158 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2163 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2166 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2171 mono_add_patch_info (cfg, \
2173 (char *)cfg->native_code), \
2174 MONO_PATCH_INFO_EXC, EXC_NAME); \
2175 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2179 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2184 /*------------------------------------------------------------------*/
2186 /* Name - mono_arch_output_basic_block */
2188 /* Function - Perform the "real" work of emitting instructions */
2189 /* that will do the work of in the basic block. */
2191 /*------------------------------------------------------------------*/
2194 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2199 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2200 MonoInst *last_ins = NULL;
2201 guint last_offset = 0;
2204 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2206 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2207 bb->block_num, bb, bb->native_offset);
2209 cpos = bb->max_offset;
2211 offset = ((char *)code) - ((char *)cfg->native_code);
2213 mono_debug_open_block (cfg, bb, offset);
2215 MONO_BB_FOR_EACH_INS (bb, ins) {
2216 offset = ((char *)code) - ((char *)cfg->native_code);
2218 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2220 if (offset > (cfg->code_size - max_len - 16))
2222 cfg->code_size *= 2;
2223 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2224 code = (unsigned int *)(cfg->native_code + offset);
2225 mono_jit_stats.code_reallocs++;
2228 mono_debug_record_line_number (cfg, ins, offset);
2230 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2231 mono_inst_name(ins->opcode));
2233 switch (ins->opcode)
2236 // Shift 64 bit value right
2237 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2238 ins->dreg, ins->sreg1, ins->sreg2);
2239 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2243 // Shift 64 bit value right
2244 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2245 ins->dreg, ins->sreg1, ins->sreg2);
2246 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2250 // Shift 64 bit value right by constant
2251 g_assert(alpha_is_imm(ins->inst_imm));
2252 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2253 ins->dreg, ins->sreg1, ins->inst_imm);
2254 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2258 // Shift 32 bit value left
2259 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2260 ins->dreg, ins->sreg1, ins->sreg2);
2261 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2262 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2266 // Shift 32 bit value left by constant
2267 g_assert(alpha_is_imm(ins->inst_imm));
2268 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2269 ins->dreg, ins->sreg1, ins->inst_imm);
2270 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2271 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2275 g_assert(alpha_is_imm(ins->inst_imm));
2276 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2277 ins->dreg, ins->sreg1, ins->inst_imm);
2278 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2282 g_assert(alpha_is_imm(ins->inst_imm));
2283 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2284 ins->dreg, ins->sreg1, ins->inst_imm);
2285 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2290 // Shift 32 bit value left
2291 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2292 ins->dreg, ins->sreg1, ins->sreg2);
2293 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2297 // Shift 64 bit value left
2298 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2299 ins->dreg, ins->sreg1, ins->sreg2);
2300 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2305 // Shift 32 bit value right
2306 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2307 ins->dreg, ins->sreg1, ins->sreg2);
2308 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2309 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2313 // Shift 32 bit value rigth by constant
2314 g_assert(alpha_is_imm(ins->inst_imm));
2315 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2316 ins->dreg, ins->sreg1, ins->inst_imm);
2317 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2318 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2322 // Shift 32 bit unsigned value right
2323 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2324 ins->dreg, ins->sreg1, ins->sreg2);
2325 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2326 alpha_srl(code, alpha_at /*ins->dreg*/, ins->sreg2, ins->dreg);
2329 case OP_ISHR_UN_IMM:
2330 // Shift 32 bit unassigned value rigth by constant
2331 g_assert(alpha_is_imm(ins->inst_imm));
2332 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2333 ins->dreg, ins->sreg1, ins->inst_imm);
2334 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2335 alpha_srl_(code, alpha_at /*ins->dreg*/, ins->inst_imm, ins->dreg);
2338 case OP_LSHR_UN_IMM:
2339 // Shift 64 bit unassigned value rigth by constant
2340 g_assert(alpha_is_imm(ins->inst_imm));
2341 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2342 ins->dreg, ins->sreg1, ins->inst_imm);
2343 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2347 // Sum two 64 bits regs
2348 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2349 ins->dreg, ins->sreg1, ins->sreg2);
2350 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2354 // Subtract two 64 bit regs
2355 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2356 ins->dreg, ins->sreg1, ins->sreg2);
2357 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2361 // Add imm value to 64 bits int
2362 g_assert(alpha_is_imm(ins->inst_imm));
2363 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2364 ins->dreg, ins->sreg1, ins->inst_imm);
2365 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2369 // Add two 32 bit ints
2370 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2371 ins->dreg, ins->sreg1, ins->sreg2);
2372 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2376 // Add two 32 bit ints with overflow detection
2377 // Use AT to hold flag of signed overflow
2378 // Use t12(PV) to hold unsigned overflow
2379 // Use RA to hold intermediate result
2380 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2381 ins->dreg, ins->sreg1, ins->sreg2);
2382 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2383 alpha_ble(code, ins->sreg2, 2);
2385 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2386 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2387 alpha_br(code, alpha_zero, 1);
2389 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2390 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2392 /* res <u sreg1 => unsigned overflow */
2393 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2395 alpha_mov1(code, alpha_ra, ins->dreg);
2399 // Add two 64 bit ints with overflow detection
2400 // Use AT to hold flag of signed overflow
2401 // Use t12(PV) to hold unsigned overflow
2402 // Use RA to hold intermediate result
2403 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2404 ins->dreg, ins->sreg1, ins->sreg2);
2405 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2406 alpha_ble(code, ins->sreg2, 2);
2408 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2409 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2410 alpha_br(code, alpha_zero, 1);
2412 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2413 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2415 /* res <u sreg1 => unsigned overflow */
2416 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2418 alpha_mov1(code, alpha_ra, ins->dreg);
2422 // Add imm value to 32 bits int
2423 g_assert(alpha_is_imm(ins->inst_imm));
2424 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2425 ins->dreg, ins->sreg1, ins->inst_imm);
2426 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2430 // Substract to 32 bit ints
2431 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2432 ins->dreg, ins->sreg1, ins->sreg2);
2433 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2437 // Sub imm value from 32 bits int
2438 g_assert(alpha_is_imm(ins->inst_imm));
2439 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2440 ins->dreg, ins->sreg1, ins->inst_imm);
2441 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2445 // Sub to 32 bit ints with overflow detection
2446 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2447 ins->dreg, ins->sreg1, ins->sreg2);
2448 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2449 alpha_ble(code, ins->sreg2, 2);
2451 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2452 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2453 alpha_br(code, alpha_zero, 1);
2455 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2456 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2458 /* sreg1 <u sreg2 => unsigned overflow */
2459 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2461 alpha_mov1(code, alpha_ra, ins->dreg);
2465 // Sub to 64 bit ints with overflow detection
2466 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2467 ins->dreg, ins->sreg1, ins->sreg2);
2469 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2470 alpha_ble(code, ins->sreg2, 2);
2472 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2473 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2474 alpha_br(code, alpha_zero, 1);
2476 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2477 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2479 /* sreg1 <u sreg2 => unsigned overflow */
2480 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2482 alpha_mov1(code, alpha_ra, ins->dreg);
2487 // AND to 32 bit ints
2488 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2489 ins->dreg, ins->sreg1, ins->sreg2);
2490 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2495 // AND imm value with 32 bit int
2496 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2497 ins->dreg, ins->sreg1, ins->inst_imm);
2499 g_assert(alpha_is_imm(ins->inst_imm));
2500 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2506 // OR two 32/64 bit ints
2507 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2508 ins->dreg, ins->sreg1, ins->sreg2);
2509 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2513 // OR imm value with 32 bit int
2514 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2515 ins->dreg, ins->sreg1, ins->inst_imm);
2517 g_assert(alpha_is_imm(ins->inst_imm));
2518 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2524 // XOR two 32/64 bit ints
2525 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2526 ins->dreg, ins->sreg1, ins->sreg2);
2527 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2531 // XOR imm value with 32 bit int
2532 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2533 ins->dreg, ins->sreg1, ins->inst_imm);
2535 g_assert(alpha_is_imm(ins->inst_imm));
2536 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2542 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2543 ins->dreg, ins->sreg1);
2544 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2549 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2550 ins->dreg, ins->sreg1);
2551 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2556 // NOT 32/64 bit reg
2557 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2558 ins->dreg, ins->sreg1);
2559 alpha_not(code, ins->sreg1, ins->dreg);
2567 case OP_IMUL_OVF_UN:
2570 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",
2571 ins->dreg, ins->sreg1, ins->sreg2);
2575 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2576 ins->dreg, ins->sreg1, ins->sreg2);
2577 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2581 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2582 ins->dreg, ins->sreg1, ins->inst_imm);
2586 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2588 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2592 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2593 ins->dreg, ins->sreg1);
2594 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2595 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2599 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2600 ins->dreg, ins->sreg1);
2601 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2602 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2606 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2607 ins->dreg, ins->sreg1);
2608 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2609 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2613 // Actually ICONST is 32 bits long
2614 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2615 ins->dreg, ins->inst_c0);
2618 if (ins->inst_c0 == 0)
2620 alpha_clr(code, ins->dreg);
2624 // if -32768 < const <= 32767
2625 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2627 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2628 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2629 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2633 int lo = (char *)code - (char *)cfg->native_code;
2634 AlphaGotData ge_data;
2636 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2637 ge_data.data.l = ins->inst_c0;
2639 add_got_entry(cfg, GT_LONG, ge_data,
2640 lo, MONO_PATCH_INFO_NONE, 0);
2641 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2643 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2644 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2652 // To load 64 bit values we will have to use ldah/lda combination
2653 // and temporary register. As temporary register use r28
2654 // Divide 64 bit value in two parts and load upper 32 bits into
2655 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2656 // dreg from temp reg
2657 // the 32 bit value could be loaded with ldah/lda
2658 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2659 ins->dreg, ins->inst_c0);
2662 if (ins->inst_c0 == 0)
2664 alpha_clr(code, ins->dreg);
2668 // if -32768 < const <= 32767
2669 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2670 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2673 AlphaGotData ge_data;
2675 lo = (char *)code - (char *)cfg->native_code;
2677 ge_data.data.l = ins->inst_c0;
2679 add_got_entry(cfg, GT_LONG, ge_data,
2680 lo, MONO_PATCH_INFO_NONE, 0);
2681 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2688 double d = *(double *)ins->inst_p0;
2689 AlphaGotData ge_data;
2691 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2695 add_got_entry(cfg, GT_DOUBLE, ge_data,
2696 (char *)code - (char *)cfg->native_code,
2697 MONO_PATCH_INFO_NONE, 0);
2698 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2705 float d = *(float *)ins->inst_p0;
2706 AlphaGotData ge_data;
2708 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2712 add_got_entry(cfg, GT_FLOAT, ge_data,
2713 (char *)code - (char *)cfg->native_code,
2714 MONO_PATCH_INFO_NONE, 0);
2715 alpha_lds(code, ins->dreg, alpha_gp, 0);
2720 case OP_LOADU4_MEMBASE:
2721 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2722 ins->dreg, ins->inst_basereg, ins->inst_offset);
2724 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2725 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2728 case OP_LOADU1_MEMBASE:
2729 // Load unassigned byte from REGOFFSET
2730 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2731 ins->dreg, ins->inst_basereg, ins->inst_offset);
2733 alpha_ldbu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2736 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2738 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2739 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2743 case OP_LOADU2_MEMBASE:
2744 // Load unassigned word from REGOFFSET
2745 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2746 ins->dreg, ins->inst_basereg, ins->inst_offset);
2749 alpha_ldwu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2752 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2754 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2755 (ins->inst_offset+1));
2756 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2757 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2758 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2759 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2763 case OP_LOAD_MEMBASE:
2764 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2765 ins->dreg, ins->inst_basereg, ins->inst_offset);
2766 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2769 case OP_LOADI8_MEMBASE:
2770 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2771 ins->dreg, ins->inst_basereg, ins->inst_offset);
2772 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2775 case OP_LOADI4_MEMBASE:
2776 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2777 ins->dreg, ins->inst_basereg, ins->inst_offset);
2778 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2781 case OP_LOADI1_MEMBASE:
2782 // Load sign-extended byte from REGOFFSET
2783 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2784 ins->dreg, ins->inst_basereg, ins->inst_offset);
2787 alpha_ldbu(code, ins->dreg, ins->inst_basereg,
2789 alpha_sextb(code, ins->dreg, ins->dreg);
2793 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2795 alpha_lda(code, alpha_at, ins->inst_basereg,
2796 (ins->inst_offset+1));
2797 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2798 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2802 case OP_LOADI2_MEMBASE:
2803 // Load sign-extended word from REGOFFSET
2804 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2805 ins->dreg, ins->inst_basereg, ins->inst_offset);
2808 alpha_ldwu(code, ins->dreg, ins->inst_basereg,
2810 alpha_sextw(code, ins->dreg, ins->dreg);
2814 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2816 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2817 (ins->inst_offset+1));
2818 alpha_lda(code, alpha_at, ins->inst_basereg,
2819 (ins->inst_offset+2));
2820 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2821 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2822 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2823 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2827 case OP_STOREI1_MEMBASE_IMM:
2828 // Store signed byte at REGOFFSET
2829 // Valid only for storing 0
2830 // storei1_membase_reg will do the rest
2832 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2833 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2834 g_assert(ins->inst_imm == 0);
2837 alpha_stb(code, alpha_zero, ins->inst_destbasereg,
2840 g_assert_not_reached();
2844 case OP_STOREI1_MEMBASE_REG:
2845 // Store byte at REGOFFSET
2846 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2847 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2850 alpha_stb(code, ins->sreg1, ins->inst_destbasereg,
2855 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2857 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2859 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2860 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2861 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2862 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2867 case OP_STOREI2_MEMBASE_IMM:
2868 // Store signed word at REGOFFSET
2869 // Now work only for storing 0
2870 // For now storei2_membase_reg will do the work
2872 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2873 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2875 g_assert(ins->inst_imm == 0);
2878 alpha_stw(code, alpha_zero, ins->inst_destbasereg,
2881 g_assert_not_reached();
2885 case OP_STOREI2_MEMBASE_REG:
2886 // Store signed word from reg to REGOFFSET
2887 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2888 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2892 alpha_stw(code, ins->sreg1, ins->inst_destbasereg,
2897 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2899 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2900 (ins->inst_offset+1));
2901 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2903 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2904 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2905 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2906 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2907 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2908 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2909 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2910 (ins->inst_offset+1));
2911 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2917 case OP_STOREI4_MEMBASE_IMM:
2918 // We will get here only with ins->inst_imm = 0
2919 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2920 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2922 g_assert(ins->inst_imm == 0);
2924 alpha_stl(code, alpha_zero,
2925 ins->inst_destbasereg, ins->inst_offset);
2928 case OP_STORER4_MEMBASE_REG:
2929 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2930 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2931 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2934 case OP_STORER8_MEMBASE_REG:
2935 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2936 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2937 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2941 case OP_LOADR4_MEMBASE:
2942 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2943 ins->dreg, ins->inst_basereg, ins->inst_offset);
2944 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2947 case OP_LOADR8_MEMBASE:
2948 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2949 ins->dreg, ins->inst_basereg, ins->inst_offset);
2950 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2954 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2955 ins->sreg1, ins->dreg);
2956 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
2960 // Later check different rounding and exc modes
2961 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2962 ins->sreg1, ins->sreg2, ins->dreg);
2963 alpha_addt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2968 // Later check different rounding and exc modes
2969 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2970 ins->sreg1, ins->sreg2, ins->dreg);
2971 alpha_subt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2976 // Later check different rounding and exc modes
2977 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2978 ins->sreg1, ins->sreg2, ins->dreg);
2979 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
2983 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2984 ins->sreg1, ins->dreg);
2985 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
2988 case OP_ALPHA_TRAPB:
2989 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2994 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2995 ins->sreg1, ins->dreg);
2996 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
2999 case OP_STORE_MEMBASE_IMM:
3000 case OP_STOREI8_MEMBASE_IMM:
3001 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
3002 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
3003 g_assert(ins->inst_imm == 0);
3005 alpha_stq(code, alpha_zero,
3006 ins->inst_destbasereg, ins->inst_offset);
3009 case OP_STORE_MEMBASE_REG:
3010 case OP_STOREI8_MEMBASE_REG:
3011 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3012 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3013 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3016 case OP_STOREI4_MEMBASE_REG:
3017 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3018 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3019 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3022 case OP_ICOMPARE_IMM:
3023 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3024 ins->sreg1, ins->dreg, ins->inst_imm);
3026 g_assert_not_reached();
3030 case OP_COMPARE_IMM:
3031 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3032 ins->sreg1, ins->dreg, ins->inst_imm);
3034 g_assert_not_reached();
3038 case OP_COMPARE: // compare two 32 bit regs
3039 case OP_LCOMPARE: // compare two 64 bit regs
3040 case OP_FCOMPARE: // compare two floats
3041 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3042 ins->sreg1, ins->sreg2, ins->dreg);
3044 g_assert_not_reached();
3048 case OP_ALPHA_CMPT_UN:
3049 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3050 ins->sreg1, ins->sreg2, ins->dreg);
3051 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3054 case OP_ALPHA_CMPT_UN_SU:
3055 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3056 ins->sreg1, ins->sreg2, ins->dreg);
3057 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3060 case OP_ALPHA_CMPT_EQ:
3061 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3062 ins->sreg1, ins->sreg2, ins->dreg);
3063 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
3066 case OP_ALPHA_CMPT_EQ_SU:
3067 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3068 ins->sreg1, ins->sreg2, ins->dreg);
3069 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
3073 case OP_ALPHA_CMPT_LT:
3074 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3075 ins->sreg1, ins->sreg2, ins->dreg);
3076 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3079 case OP_ALPHA_CMPT_LT_SU:
3080 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3081 ins->sreg1, ins->sreg2, ins->dreg);
3082 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3085 case OP_ALPHA_CMPT_LE:
3086 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3087 ins->sreg1, ins->sreg2, ins->dreg);
3088 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3091 case OP_ALPHA_CMPT_LE_SU:
3092 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3093 ins->sreg1, ins->sreg2, ins->dreg);
3094 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3097 case OP_ALPHA_CMP_EQ:
3098 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3099 ins->sreg1, ins->sreg2, ins->dreg);
3100 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3103 case OP_ALPHA_CMP_IMM_EQ:
3104 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3105 ins->sreg1, ins->inst_imm, ins->dreg);
3106 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3109 case OP_ALPHA_CMP_IMM_ULE:
3110 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%d\n",
3111 ins->sreg1, ins->inst_imm, ins->dreg);
3112 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3115 case OP_ALPHA_CMP_ULT:
3116 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3117 ins->sreg1, ins->sreg2, ins->dreg);
3118 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3121 case OP_ALPHA_CMP_IMM_ULT:
3122 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3123 ins->sreg1, ins->inst_imm, ins->dreg);
3124 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3127 case OP_ALPHA_CMP_LE:
3128 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3129 ins->sreg1, ins->sreg2, ins->dreg);
3130 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3133 case OP_ALPHA_CMP_ULE:
3134 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3135 ins->sreg1, ins->sreg2, ins->dreg);
3136 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3140 case OP_ALPHA_CMP_IMM_LE:
3141 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%d\n",
3142 ins->sreg1, ins->inst_imm, ins->dreg);
3143 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3146 case OP_ALPHA_CMP_LT:
3147 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3148 ins->sreg1, ins->sreg2, ins->dreg);
3149 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3152 case OP_ALPHA_CMP_IMM_LT:
3153 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3154 ins->sreg1, ins->inst_imm, ins->dreg);
3155 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3158 case OP_COND_EXC_GT:
3159 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3160 (char *)ins->inst_p1);
3162 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3165 case OP_COND_EXC_GT_UN:
3166 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3167 (char *)ins->inst_p1);
3169 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3172 case OP_COND_EXC_LT:
3173 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3174 (char *)ins->inst_p1);
3176 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3179 case OP_COND_EXC_LT_UN:
3180 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3181 (char *)ins->inst_p1);
3183 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3187 case OP_COND_EXC_LE_UN:
3188 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3189 (char *)ins->inst_p1);
3190 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3193 case OP_COND_EXC_NE_UN:
3194 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3195 (char *)ins->inst_p1);
3196 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3199 case OP_COND_EXC_EQ:
3200 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3201 (char *)ins->inst_p1);
3202 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3205 case OP_COND_EXC_IOV:
3206 case OP_COND_EXC_OV:
3207 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3210 case OP_COND_EXC_IC:
3212 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3215 case CEE_CONV_OVF_U4:
3216 // Convert unsigned 32 bit value to 64 bit reg
3218 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3219 ins->sreg1, ins->dreg);
3220 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3221 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3222 alpha_mov1(code, ins->sreg1, ins->dreg);
3225 case CEE_CONV_OVF_I4_UN:
3226 // Convert unsigned 32 bit value to 64 bit reg
3228 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3229 ins->sreg1, ins->dreg);
3230 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3232 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3233 alpha_mov1(code, ins->sreg1, ins->dreg);
3237 // Move I1 (byte) to dreg(64 bits) and sign extend it
3239 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3240 ins->sreg1, ins->dreg);
3242 alpha_sextb(code, ins->sreg1, ins->dreg);
3245 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3246 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3247 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3252 // Move I2 (word) to dreg(64 bits) and sign extend it
3253 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3254 ins->sreg1, ins->dreg);
3256 alpha_sextw(code, ins->sreg1, ins->dreg);
3259 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3260 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3261 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3266 // Move I4 (long) to dreg(64 bits) and sign extend it
3267 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3268 ins->sreg1, ins->dreg);
3269 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3274 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3275 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3276 ins->sreg1, ins->dreg);
3277 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3278 alpha_mov1(code, ins->sreg1, ins->dreg);
3282 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3283 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3284 ins->sreg1, ins->dreg);
3285 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3289 // Move U2 (word) to dreg(64 bits) don't sign extend it
3290 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3291 ins->sreg1, ins->dreg);
3292 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3296 // Move U4 (long) to dreg(64 bits) don't sign extend it
3297 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3298 ins->sreg1, ins->dreg);
3299 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3304 // Move U4 (long) to dreg(64 bits) don't sign extend it
3305 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3306 ins->sreg1, ins->dreg);
3307 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3310 case OP_FCONV_TO_I4:
3311 case OP_FCONV_TO_I8:
3312 // Move float to 32 bit reg
3313 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3314 ins->sreg1, ins->dreg);
3315 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3316 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3317 alpha_lda(code, alpha_sp, alpha_sp, -8);
3318 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3319 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3320 alpha_lda(code, alpha_sp, alpha_sp, 8);
3323 case OP_FCONV_TO_I2:
3324 // Move float to 16 bit reg
3325 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3326 ins->sreg1, ins->dreg);
3327 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3328 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3329 alpha_lda(code, alpha_sp, alpha_sp, -8);
3330 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3331 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3332 alpha_lda(code, alpha_sp, alpha_sp, 8);
3333 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3334 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3337 case OP_FCONV_TO_U2:
3338 // Move float to 16 bit reg as unsigned
3339 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3340 ins->sreg1, ins->dreg);
3341 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3342 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3343 alpha_lda(code, alpha_sp, alpha_sp, -8);
3344 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3345 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3346 alpha_lda(code, alpha_sp, alpha_sp, 8);
3347 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3350 case OP_FCONV_TO_U1:
3351 // Move float to 8 bit reg as unsigned
3352 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3353 ins->sreg1, ins->dreg);
3354 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3355 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3356 alpha_lda(code, alpha_sp, alpha_sp, -8);
3357 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3358 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3359 alpha_lda(code, alpha_sp, alpha_sp, 8);
3360 alpha_and_(code, ins->dreg, 0xff, ins->dreg);
3363 case OP_FCONV_TO_I1:
3364 // Move float to 8 bit reg
3365 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3366 ins->sreg1, ins->dreg);
3367 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3368 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3369 alpha_lda(code, alpha_sp, alpha_sp, -8);
3370 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3371 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3372 alpha_lda(code, alpha_sp, alpha_sp, 8);
3373 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3374 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3378 case OP_LCONV_TO_R4:
3379 // Move 32/64 bit int into float
3380 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3381 ins->sreg1, ins->dreg);
3382 alpha_lda(code, alpha_sp, alpha_sp, -8);
3383 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3384 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3385 alpha_lda(code, alpha_sp, alpha_sp, 8);
3386 alpha_cvtqs(code, ins->dreg, ins->dreg);
3391 case OP_LCONV_TO_R8:
3392 // Move 32/64 bit int into double
3393 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3394 ins->sreg1, ins->dreg);
3395 alpha_lda(code, alpha_sp, alpha_sp, -8);
3396 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3397 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3398 alpha_lda(code, alpha_sp, alpha_sp, 8);
3399 alpha_cvtqt(code, ins->dreg, ins->dreg);
3403 case OP_FCONV_TO_R4:
3404 // Convert 64 bit float to 32 bit float (T -> S)
3405 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3406 ins->sreg1, ins->dreg);
3407 alpha_cvtts_su(code, ins->sreg1, ins->dreg);
3412 // Allocate sreg1 bytes on stack, round bytes by 8,
3413 // modify SP, set dreg to end of current stack frame
3414 // top of stack is used for call params
3415 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3416 ins->sreg1, ins->dreg);
3418 alpha_addq_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3419 alpha_bic_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3420 if (ins->flags & MONO_INST_INIT)
3421 alpha_mov1(code, ins->sreg1, ins->sreg2);
3423 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3424 if (cfg->arch.params_stack_size > 0)
3426 alpha_lda(code, ins->dreg, alpha_zero,
3427 (cfg->arch.params_stack_size));
3428 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3431 alpha_mov1(code, alpha_sp, ins->dreg);
3433 if (ins->flags & MONO_INST_INIT)
3435 // TODO: Optimize it later
3436 alpha_lda(code, ins->sreg2, ins->sreg2,
3437 -(MONO_ARCH_LOCALLOC_ALIGNMENT));
3438 alpha_blt(code, ins->sreg2, 3);
3439 alpha_addq(code, ins->sreg2, ins->dreg, alpha_at);
3440 alpha_stq(code, alpha_zero, alpha_at, 0);
3441 alpha_br(code, alpha_zero, -5);
3447 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3448 ins->sreg1, ins->dreg);
3449 alpha_mov1(code, ins->sreg1, ins->dreg);
3456 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3458 alpha_clr(code, ins->dreg);
3459 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3466 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3468 alpha_clr(code, ins->dreg);
3469 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3474 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3476 alpha_clr(code, ins->dreg);
3477 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3481 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3483 alpha_clr(code, ins->dreg);
3484 alpha_fbeq(code, alpha_at, 1);
3485 alpha_lda(code, ins->dreg, alpha_zero, 1);
3488 alpha_cvttq_c(code, alpha_at, alpha_at);
3489 alpha_lda(code, alpha_sp, alpha_sp, -8);
3490 alpha_stt(code, alpha_at, alpha_sp, 0);
3491 alpha_ldq(code, alpha_at, alpha_sp, 0);
3492 alpha_lda(code, alpha_sp, alpha_sp, 8);
3494 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3499 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3501 alpha_clr(code, ins->dreg);
3502 alpha_fbne(code, alpha_at, 1);
3503 alpha_lda(code, ins->dreg, alpha_zero, 1);
3506 alpha_cvttq_c(code, alpha_at, alpha_at);
3507 alpha_lda(code, alpha_sp, alpha_sp, -8);
3508 alpha_stt(code, alpha_at, alpha_sp, 0);
3509 alpha_ldq(code, alpha_at, alpha_sp, 0);
3510 alpha_lda(code, alpha_sp, alpha_sp, 8);
3512 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3518 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3520 alpha_clr(code, ins->dreg);
3521 alpha_fbeq(code, alpha_at, 1);
3522 alpha_lda(code, ins->dreg, alpha_zero, 1);
3526 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3529 alpha_clr(code, ins->dreg);
3530 alpha_fbne(code, (alpha_at+1), 1);
3531 alpha_fbeq(code, alpha_at, 1);
3532 alpha_lda(code, ins->dreg, alpha_zero, 1);
3537 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3538 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3542 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3543 alpha_fbeq(code, (alpha_at+1), 1);
3544 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3545 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3549 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3550 alpha_fbeq(code, (alpha_at+1), 1);
3551 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3552 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3556 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge] [");
3557 alpha_fbne(code, (alpha_at+1), 1);
3558 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3562 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3563 alpha_fbeq(code, (alpha_at+1), 1);
3564 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3565 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3569 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble] [");
3570 alpha_fbne(code, (alpha_at+1), 1);
3571 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3575 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3576 alpha_fbeq(code, (alpha_at+1), 1);
3577 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3578 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3582 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt] [");
3583 alpha_fbne(code, (alpha_at+1), 1);
3584 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3588 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3589 alpha_fbeq(code, (alpha_at+1), 1);
3590 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3591 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3595 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt] [");
3596 alpha_fbne(code, (alpha_at+1), 1);
3597 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3601 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3602 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3606 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3607 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3611 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3612 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3616 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3617 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3621 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3622 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3626 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br] target: %p, next: %p, curr: %p, last: %p [",
3627 ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3629 if (ins->flags & MONO_INST_BRLABEL)
3631 if (ins->inst_i0->inst_c0)
3633 CFG_DEBUG(4) g_print("inst_c0: %0lX, data: %p]\n",
3634 ins->inst_i0->inst_c0,
3635 cfg->native_code + ins->inst_i0->inst_c0);
3636 alpha_br(code, alpha_zero, 0);
3640 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n",
3641 offset, ins->inst_i0);
3642 mono_add_patch_info (cfg, offset,
3643 MONO_PATCH_INFO_LABEL, ins->inst_i0);
3645 alpha_br(code, alpha_zero, 0);
3650 if (ins->inst_target_bb->native_offset)
3652 // Somehow native offset is offset from
3653 // start of the code. So convert it to
3655 long br_offset = (char *)cfg->native_code +
3656 ins->inst_target_bb->native_offset - 4 - (char *)code;
3658 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3659 ins->inst_target_bb->native_offset,
3661 ins->inst_target_bb->native_offset);
3662 alpha_br(code, alpha_zero, br_offset/4);
3666 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3667 offset, ins->inst_target_bb);
3669 mono_add_patch_info (cfg, offset,
3671 ins->inst_target_bb);
3672 alpha_br(code, alpha_zero, 0);
3679 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3682 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3690 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3691 call = (MonoCallInst*)ins;
3693 if (ins->flags & MONO_INST_HAS_METHOD)
3695 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3696 code = emit_call (cfg, code,
3697 MONO_PATCH_INFO_METHOD, call->method);
3701 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3702 code = emit_call (cfg, code,
3703 MONO_PATCH_INFO_ABS, call->fptr);
3706 //code = emit_move_return_value (cfg, ins, code);
3713 case OP_VOIDCALL_REG:
3718 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3719 call = (MonoCallInst*)ins;
3721 alpha_mov1(code, ins->sreg1, alpha_pv);
3723 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3725 offset = (char *)code - (char *)cfg->native_code;
3728 ALPHA_LOAD_GP(offset)
3729 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3730 alpha_lda(code, alpha_gp, alpha_gp, 0);
3734 case OP_FCALL_MEMBASE:
3735 case OP_CALL_MEMBASE:
3736 case OP_LCALL_MEMBASE:
3737 case OP_VCALL_MEMBASE:
3741 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3742 ins->inst_basereg, ins->inst_offset);
3743 call = (MonoCallInst*)ins;
3745 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3746 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3748 offset = (char *)code - (char *)cfg->native_code;
3751 ALPHA_LOAD_GP(offset)
3752 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3753 alpha_lda(code, alpha_gp, alpha_gp, 0);
3757 case OP_VOIDCALL_MEMBASE:
3761 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3762 ins->inst_basereg, ins->inst_offset);
3763 call = (MonoCallInst*)ins;
3765 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3766 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3768 offset = (char *)code - (char *)cfg->native_code;
3771 ALPHA_LOAD_GP(offset)
3772 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3773 alpha_lda(code, alpha_gp, alpha_gp, 0);
3777 case OP_START_HANDLER:
3779 // TODO - find out when we called by call_handler or resume_context
3780 // of by call_filter. There should be difference. For now just
3781 // handle - call_handler
3783 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3784 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3786 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3787 ins->inst_left->inst_offset);
3793 // Keep in sync with start_handler
3794 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3795 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3797 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3798 ins->inst_left->inst_offset);
3800 alpha_ret(code, alpha_ra, 1);
3806 // Keep in sync with start_handler
3807 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3808 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3810 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3811 ins->inst_left->inst_offset);
3813 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3814 alpha_mov1(code, ins->sreg1, alpha_r0);
3816 alpha_ret(code, alpha_ra, 1);
3820 case OP_CALL_HANDLER:
3824 offset = (char *)code - (char *)cfg->native_code;
3826 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3827 offset, ins->inst_target_bb);
3829 mono_add_patch_info (cfg, offset,
3831 ins->inst_target_bb);
3832 alpha_bsr(code, alpha_ra, 0);
3837 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3839 alpha_mov1(code, ins->sreg1, alpha_a0);
3840 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3841 (gpointer)"mono_arch_throw_exception");
3845 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3847 alpha_mov1(code, ins->sreg1, alpha_a0);
3848 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3849 (gpointer)"mono_arch_rethrow_exception");
3855 * Note: this 'frame destruction' logic is useful for tail calls,
3856 too. Keep in sync with the code in emit_epilog.
3859 AlphaGotData ge_data;
3861 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3863 /* FIXME: no tracing support... */
3864 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3865 code = mono_arch_instrument_epilog (cfg,
3866 mono_profiler_method_leave, code, FALSE);
3867 g_assert (!cfg->method->save_lmf);
3869 alpha_mov1( code, alpha_fp, alpha_sp );
3871 code = emit_load_volatile_arguments (cfg, code);
3873 offset = cfg->arch.params_stack_size;
3875 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3876 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3877 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3879 ge_data.data.p = ins->inst_p0;
3880 add_got_entry(cfg, GT_PTR, ge_data,
3881 (char *)code - (char *)cfg->native_code,
3882 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3883 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3885 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3890 mono_add_patch_info (cfg, offset,
3891 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3894 case OP_MEMORY_BARRIER:
3895 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3900 // Float register contains a value which we need to check
3902 double ni = -1.0 / 0.0;
3903 double pi = 1.0 / 0.0;
3904 AlphaGotData ge_data;
3906 CFG_DEBUG(4) g_print("ALPHA_TODO: [chfinite] sreg1=%d\n", ins->sreg1);
3907 alpha_cmptun_su(code, ins->sreg1, ins->sreg1, alpha_at);
3909 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3911 // Negative infinity
3912 ge_data.data.d = ni;
3913 add_got_entry(cfg, GT_DOUBLE, ge_data,
3914 (char *)code - (char *)cfg->native_code,
3915 MONO_PATCH_INFO_NONE, 0);
3916 alpha_ldt(code, alpha_at, alpha_gp, 0);
3918 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3921 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3923 // Positive infinity
3924 ge_data.data.d = pi;
3925 add_got_entry(cfg, GT_DOUBLE, ge_data,
3926 (char *)code - (char *)cfg->native_code,
3927 MONO_PATCH_INFO_NONE, 0);
3928 alpha_ldt(code, alpha_at, alpha_gp, 0);
3930 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3933 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3937 CFG_DEBUG(4) g_print("ALPHA_TODO: [fdiv] dest=%d, sreg1=%d, sreg2=%d\n",
3938 ins->dreg, ins->sreg1, ins->sreg2);
3939 alpha_divt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
3944 g_warning ("unknown opcode %s in %s()\n",
3945 mono_inst_name (ins->opcode), __FUNCTION__);
3947 // g_assert_not_reached ();
3951 if ( (((char *)code) -
3952 ((char *)cfg->native_code) -
3955 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3956 mono_inst_name (ins->opcode), max_len,
3957 ((char *)code) - ((char *)cfg->native_code) - offset );
3958 //g_assert_not_reached ();
3964 last_offset = offset;
3967 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3970 /*========================= End of Function ========================*/
3975 /*------------------------------------------------------------------*/
3977 /* Name - mono_arch_cpu_optimizazions */
3979 /* Function - Returns the optimizations supported on this CPU */
3981 /*------------------------------------------------------------------*/
3984 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3988 if (getenv("MONO_ALPHA_DEBUG"))
3989 mini_alpha_verbose_level = 1;
3991 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3993 /*----------------------------------------------------------*/
3994 /* no alpha-specific optimizations yet */
3995 /*----------------------------------------------------------*/
3996 *exclude_mask = MONO_OPT_LINEARS;
3997 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
4001 /*========================= End of Function ========================*/
4003 /*------------------------------------------------------------------*/
4005 /* Name - mono_arch_flush_icache */
4007 /* Function - Flush the CPU icache. */
4009 /*------------------------------------------------------------------*/
4012 mono_arch_flush_icache (guint8 *code, gint size)
4014 //ALPHA_DEBUG("mono_arch_flush_icache");
4016 /* flush instruction cache to see trampoline code */
4017 asm volatile("imb":::"memory");
4020 /*========================= End of Function ========================*/
4022 /*------------------------------------------------------------------*/
4024 /* Name - mono_arch_regname */
4026 /* Function - Returns the name of the register specified by */
4027 /* the input parameter. */
4029 /*------------------------------------------------------------------*/
4032 mono_arch_regname (int reg) {
4033 static const char * rnames[] = {
4034 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
4035 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
4036 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
4037 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
4038 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
4039 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
4040 "alpha_r30", "alpha_r31"
4043 if (reg >= 0 && reg < 32)
4044 return rnames [reg];
4048 /*========================= End of Function ========================*/
4050 /*------------------------------------------------------------------*/
4052 /* Name - mono_arch_fregname */
4054 /* Function - Returns the name of the register specified by */
4055 /* the input parameter. */
4057 /*------------------------------------------------------------------*/
4060 mono_arch_fregname (int reg) {
4061 static const char * rnames[] = {
4062 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4063 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4064 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4065 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4066 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4067 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4068 "alpha_f30", "alpha_f31"
4071 if (reg >= 0 && reg < 32)
4072 return rnames [reg];
4077 /*========================= End of Function ========================*/
4079 /*------------------------------------------------------------------*/
4081 /* Name - mono_arch_patch_code */
4083 /* Function - Process the patch data created during the */
4084 /* instruction build process. This resolves jumps, */
4085 /* calls, variables etc. */
4087 /*------------------------------------------------------------------*/
4090 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
4091 guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4093 MonoJumpInfo *patch_info;
4094 gboolean compile_aot = !run_cctors;
4096 ALPHA_DEBUG("mono_arch_patch_code");
4098 for (patch_info = ji; patch_info; patch_info = patch_info->next)
4100 unsigned char *ip = patch_info->ip.i + code;
4101 const unsigned char *target;
4103 target = mono_resolve_patch_target (method, domain,
4104 code, patch_info, run_cctors);
4108 switch (patch_info->type)
4111 case MONO_PATCH_INFO_BB:
4112 case MONO_PATCH_INFO_LABEL:
4115 /* No need to patch these */
4120 switch (patch_info->type)
4122 case MONO_PATCH_INFO_NONE:
4125 case MONO_PATCH_INFO_GOT_OFFSET:
4127 unsigned int *ip2 = (unsigned int *)ip;
4128 unsigned int inst = *ip2;
4129 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
4131 g_assert(!(off & 0xFFFF8000));
4139 case MONO_PATCH_INFO_CLASS_INIT:
4141 /* Might already been changed to a nop */
4142 unsigned int* ip2 = (unsigned int *)ip;
4143 unsigned long t_addr = (unsigned long)target;
4145 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
4146 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
4148 // amd64_call_code (ip2, 0);
4152 // case MONO_PATCH_INFO_METHOD_REL:
4153 case MONO_PATCH_INFO_R8:
4154 case MONO_PATCH_INFO_R4:
4155 g_assert_not_reached ();
4157 case MONO_PATCH_INFO_BB:
4160 case MONO_PATCH_INFO_METHOD:
4161 case MONO_PATCH_INFO_METHODCONST:
4162 case MONO_PATCH_INFO_INTERNAL_METHOD:
4163 case MONO_PATCH_INFO_METHOD_JUMP:
4165 volatile unsigned int *p = (unsigned int *)ip;
4166 unsigned long t_addr;
4173 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4175 if (target != ((void *)t_addr))
4177 t_addr = (unsigned long)target;
4178 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4179 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4184 case MONO_PATCH_INFO_ABS:
4186 volatile unsigned int *p = (unsigned int *)ip;
4187 unsigned long t_addr;
4193 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4198 case MONO_PATCH_INFO_SWITCH:
4200 unsigned int *pcode = (unsigned int *)ip;
4201 unsigned long t_addr;
4203 t_addr = (unsigned long)target;
4205 if (((unsigned long)ip) % 8)
4211 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4212 alpha_nop(pcode); // TODO optimize later
4213 alpha_bsr(pcode, alpha_at, 2);
4215 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4217 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4220 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4230 volatile unsigned int *p = (unsigned int *)ip;
4231 unsigned int alpha_ins = *p;
4232 unsigned int opcode;
4235 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4237 if (opcode >= 0x30 && opcode <= 0x3f)
4239 // This is branch with offset instruction
4240 br_offset = (target - ip - 4);
4242 g_assert(!(br_offset & 3));
4244 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4252 /*========================= End of Function ========================*/
4253 /*------------------------------------------------------------------*/
4255 /* Name - mono_arch_emit_this_vret_args */
4259 /*------------------------------------------------------------------*/
4262 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4263 int this_reg, int this_type, int vt_reg)
4265 MonoCallInst *call = (MonoCallInst*)inst;
4266 CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, inst->signature, FALSE);
4268 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4274 if (cinfo->ret.storage == ArgValuetypeInReg)
4277 * The valuetype is in RAX:RDX after the call, need to be copied to
4278 * the stack. Push the address here, so the call instruction can
4281 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4282 //vtarg->sreg1 = vt_reg;
4283 //mono_bblock_add_inst (cfg->cbb, vtarg);
4286 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4291 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4292 vtarg->sreg1 = vt_reg;
4293 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4294 mono_bblock_add_inst (cfg->cbb, vtarg);
4296 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4297 cinfo->ret.reg, FALSE);
4301 /* add the this argument */
4305 MONO_INST_NEW (cfg, this, OP_MOVE);
4306 this->type = this_type;
4307 this->sreg1 = this_reg;
4308 this->dreg = mono_regstate_next_int (cfg->rs);
4309 mono_bblock_add_inst (cfg->cbb, this);
4311 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4312 cinfo->args [0].reg, FALSE);
4318 /*========================= End of Function ========================*/
4320 /*------------------------------------------------------------------*/
4322 /* Name - mono_arch_is_inst_imm */
4324 /* Function - Determine if operand qualifies as an immediate */
4325 /* value. For Alpha this is a value 0 - 255 */
4327 /* Returns - True|False - is [not] immediate value. */
4329 /*------------------------------------------------------------------*/
4332 mono_arch_is_inst_imm (gint64 imm)
4334 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4336 return (imm & ~(0x0FFL)) ? 0 : 1;
4339 /*------------------------------------------------------------------*/
4341 /* Name - mono_arch_setup_jit_tls_data */
4343 /* Function - Setup the JIT's Thread Level Specific Data. */
4345 /*------------------------------------------------------------------*/
4348 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4350 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4352 if (!tls_offset_inited) {
4353 tls_offset_inited = TRUE;
4356 if (!lmf_addr_key_inited) {
4357 lmf_addr_key_inited = TRUE;
4358 pthread_key_create (&lmf_addr_key, NULL);
4361 pthread_setspecific (lmf_addr_key, &tls->lmf);
4364 /*------------------------------------------------------------------*/
4366 /* Name - mono_arch_cpu_init */
4368 /* Function - Perform CPU specific initialization to execute */
4371 /*------------------------------------------------------------------*/
4374 mono_arch_cpu_init (void)
4376 unsigned long amask, implver;
4377 register long v0 __asm__("$0") = -1;
4379 ALPHA_DEBUG("mono_arch_cpu_init");
4381 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
4383 __asm__ (".long 0x47e03d80" : "=r"(v0));
4389 //printf("amask: %x, implver: %x", amask, implver);
4393 * Initialize architecture specific code.
4396 mono_arch_init (void)
4401 * Cleanup architecture specific code.
4404 mono_arch_cleanup (void)
4411 * Obtain information about a call according to the calling convention.
4413 * For x86 ELF, see the "System V Application Binary Interface Intel386
4414 * Architecture Processor Supplment, Fourth Edition" document for more
4416 * For x86 win32, see ???.
4419 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
4421 guint32 i, gr, fr, *pgr, *pfr;
4423 int n = sig->hasthis + sig->param_count;
4424 guint32 stack_size = 0;
4427 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4442 ret_type = mono_type_get_underlying_type (sig->ret);
4443 switch (ret_type->type) {
4444 case MONO_TYPE_BOOLEAN:
4449 case MONO_TYPE_CHAR:
4455 case MONO_TYPE_FNPTR:
4456 case MONO_TYPE_CLASS:
4457 case MONO_TYPE_OBJECT:
4458 case MONO_TYPE_SZARRAY:
4459 case MONO_TYPE_ARRAY:
4460 case MONO_TYPE_STRING:
4461 cinfo->ret.storage = ArgInIReg;
4462 cinfo->ret.reg = alpha_r0;
4466 cinfo->ret.storage = ArgInIReg;
4467 cinfo->ret.reg = alpha_r0;
4470 cinfo->ret.storage = ArgInFloatReg;
4471 cinfo->ret.reg = alpha_f0;
4474 cinfo->ret.storage = ArgInDoubleReg;
4475 cinfo->ret.reg = alpha_f0;
4477 case MONO_TYPE_GENERICINST:
4478 if (!mono_type_generic_inst_is_valuetype (sig->ret))
4480 cinfo->ret.storage = ArgInIReg;
4481 cinfo->ret.reg = alpha_r0;
4485 case MONO_TYPE_VALUETYPE:
4487 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4489 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE,
4490 &tmp_gr, &tmp_fr, &tmp_stacksize);
4492 if (cinfo->ret.storage == ArgOnStack)
4493 /* The caller passes the address where the value
4495 add_general (pgr, &stack_size, &cinfo->ret);
4498 case MONO_TYPE_TYPEDBYREF:
4499 /* Same as a valuetype with size 24 */
4500 add_general (pgr, &stack_size, &cinfo->ret);
4503 case MONO_TYPE_VOID:
4506 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4512 add_general (pgr, &stack_size, cinfo->args + 0);
4514 if (!sig->pinvoke &&
4515 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4518 fr = FLOAT_PARAM_REGS;
4520 /* Emit the signature cookie just before the implicit arguments
4522 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4525 for (i = 0; i < sig->param_count; ++i)
4527 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4530 if (!sig->pinvoke &&
4531 (sig->call_convention == MONO_CALL_VARARG) &&
4532 (i == sig->sentinelpos))
4534 /* We allways pass the sig cookie on the stack for simpl
4537 * Prevent implicit arguments + the sig cookie from being passed
4541 fr = FLOAT_PARAM_REGS;
4543 /* Emit the signature cookie just before the implicit arguments */
4544 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4547 if (sig->params [i]->byref) {
4548 add_general (pgr, &stack_size, ainfo);
4552 ptype = mono_type_get_underlying_type (sig->params [i]);
4554 switch (ptype->type) {
4555 case MONO_TYPE_BOOLEAN:
4558 add_general (pgr, &stack_size, ainfo);
4562 case MONO_TYPE_CHAR:
4563 add_general (pgr, &stack_size, ainfo);
4567 add_general (pgr, &stack_size, ainfo);
4572 case MONO_TYPE_FNPTR:
4573 case MONO_TYPE_CLASS:
4574 case MONO_TYPE_OBJECT:
4575 case MONO_TYPE_STRING:
4576 case MONO_TYPE_SZARRAY:
4577 case MONO_TYPE_ARRAY:
4578 add_general (pgr, &stack_size, ainfo);
4580 case MONO_TYPE_GENERICINST:
4581 if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
4583 add_general (pgr, &stack_size, ainfo);
4587 case MONO_TYPE_VALUETYPE:
4589 /* We allways pass valuetypes on the stack */
4590 add_valuetype (gsctx, sig, ainfo, sig->params [i],
4591 FALSE, pgr, pfr, &stack_size);
4593 case MONO_TYPE_TYPEDBYREF:
4594 stack_size += sizeof (MonoTypedRef);
4595 ainfo->storage = ArgOnStack;
4599 add_general (pgr, &stack_size, ainfo);
4602 add_float (pfr, &stack_size, ainfo, FALSE);
4605 add_float (pfr, &stack_size, ainfo, TRUE);
4608 g_assert_not_reached ();
4612 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4613 (n > 0) && (sig->sentinelpos == sig->param_count))
4616 fr = FLOAT_PARAM_REGS;
4618 /* Emit the signature cookie just before the implicit arguments
4620 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4623 cinfo->stack_usage = stack_size;
4624 cinfo->reg_usage = gr;
4625 cinfo->freg_usage = fr;
4630 static const char *CvtMonoType(MonoTypeEnum t)
4635 return "MONO_TYPE_END";
4636 case MONO_TYPE_VOID:
4637 return "MONO_TYPE_VOID";
4638 case MONO_TYPE_BOOLEAN:
4639 return "MONO_TYPE_BOOLEAN";
4640 case MONO_TYPE_CHAR:
4641 return "MONO_TYPE_CHAR";
4643 return "MONO_TYPE_I1";
4645 return "MONO_TYPE_U1";
4647 return "MONO_TYPE_I2";
4649 return "MONO_TYPE_U2";
4651 return "MONO_TYPE_I4";
4653 return "MONO_TYPE_U4";
4655 return "MONO_TYPE_I8";
4657 return "MONO_TYPE_U8";
4659 return "MONO_TYPE_R4";
4661 return "MONO_TYPE_R8";
4662 case MONO_TYPE_STRING:
4663 return "MONO_TYPE_STRING";
4665 return "MONO_TYPE_PTR";
4666 case MONO_TYPE_BYREF:
4667 return "MONO_TYPE_BYREF";
4668 case MONO_TYPE_VALUETYPE:
4669 return "MONO_TYPE_VALUETYPE";
4670 case MONO_TYPE_CLASS:
4671 return "MONO_TYPE_CLASS";
4673 return "MONO_TYPE_VAR";
4674 case MONO_TYPE_ARRAY:
4675 return "MONO_TYPE_ARRAY";
4676 case MONO_TYPE_GENERICINST:
4677 return "MONO_TYPE_GENERICINST";
4678 case MONO_TYPE_TYPEDBYREF:
4679 return "MONO_TYPE_TYPEDBYREF";
4681 return "MONO_TYPE_I";
4683 return "MONO_TYPE_U";
4684 case MONO_TYPE_FNPTR:
4685 return "MONO_TYPE_FNPTR";
4686 case MONO_TYPE_OBJECT:
4687 return "MONO_TYPE_OBJECT";
4688 case MONO_TYPE_SZARRAY:
4689 return "MONO_TYPE_SZARRAY";
4690 case MONO_TYPE_MVAR:
4691 return "MONO_TYPE_MVAR";
4692 case MONO_TYPE_CMOD_REQD:
4693 return "MONO_TYPE_CMOD_REQD";
4694 case MONO_TYPE_CMOD_OPT:
4695 return "MONO_TYPE_CMOD_OPT";
4696 case MONO_TYPE_INTERNAL:
4697 return "MONO_TYPE_INTERNAL";
4698 case MONO_TYPE_MODIFIER:
4699 return "MONO_TYPE_MODIFIER";
4700 case MONO_TYPE_SENTINEL:
4701 return "MONO_TYPE_SENTINEL";
4702 case MONO_TYPE_PINNED:
4703 return "MONO_TYPE_PINNED";
4711 /*------------------------------------------------------------------*/
4713 /* Name - mono_arch_call_opcode */
4715 /* Function - Take the arguments and generate the arch-specific */
4716 /* instructions to properly call the function. This */
4717 /* includes pushing, moving argments to the correct */
4720 * This method is called during converting method to IR
4721 * We need to generate IR ints to follow calling convention
4722 * cfg - points to currently compiled unit
4724 * call - points to structure that describes what we are going to
4725 * call (at least number of parameters required for the call)
4728 * On return we need to pass back modified call structure
4730 /*------------------------------------------------------------------*/
4733 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4734 MonoCallInst *call, int is_virtual)
4737 MonoMethodSignature *sig;
4742 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4744 sig = call->signature;
4745 n = sig->param_count + sig->hasthis;
4747 // Collect info about method we age going to call
4748 cinfo = get_call_info (cfg->generic_sharing_context, sig, sig->pinvoke);
4750 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4751 sig->pinvoke ? "PInvoke" : "Managed",
4752 sig->param_count, sig->hasthis,
4753 CvtMonoType(sig->ret->type), sig->ret->type);
4755 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4756 cfg->arch.params_stack_size = cinfo->stack_usage;
4758 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4759 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4761 for (i = 0; i < n; ++i)
4763 ArgInfo *ainfo = cinfo->args + i;
4765 /* Emit the signature cookie just before the implicit arguments
4767 if (!sig->pinvoke &&
4768 (sig->call_convention == MONO_CALL_VARARG) &&
4771 MonoMethodSignature *tmp_sig;
4774 /* FIXME: Add support for signature tokens to AOT */
4775 cfg->disable_aot = TRUE;
4776 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4779 * mono_ArgIterator_Setup assumes the signature cookie is
4780 * passed first and all the arguments which were before it are
4781 * passed on the stack after the signature. So compensate by
4782 * passing a different signature.
4784 tmp_sig = mono_metadata_signature_dup (call->signature);
4785 tmp_sig->param_count -= call->signature->sentinelpos;
4786 tmp_sig->sentinelpos = 0;
4787 memcpy (tmp_sig->params,
4788 call->signature->params + call->signature->sentinelpos,
4789 tmp_sig->param_count * sizeof (MonoType*));
4791 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4792 sig_arg->inst_p0 = tmp_sig;
4794 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4795 arg->inst_left = sig_arg;
4796 arg->type = STACK_PTR;
4798 /* prepend, so they get reversed */
4799 arg->next = call->out_args;
4800 call->out_args = arg;
4803 if (is_virtual && i == 0) {
4804 /* the argument will be attached to the call instrucion
4806 in = call->args [i];
4810 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4811 in = call->args [i];
4812 arg->cil_code = in->cil_code;
4813 arg->inst_left = in;
4814 arg->type = in->type;
4815 /* prepend, so they get reversed */
4816 arg->next = call->out_args;
4817 call->out_args = arg;
4819 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4821 if (sig->hasthis && (i == 0))
4822 arg_type = &mono_defaults.object_class->byval_arg;
4824 arg_type = sig->params [i - sig->hasthis];
4826 if ((i >= sig->hasthis) &&
4827 (MONO_TYPE_ISSTRUCT(arg_type)))
4832 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4833 size = sizeof (MonoTypedRef);
4834 align = sizeof (gpointer);
4838 size = mono_type_native_stack_size (&in->klass->byval_arg,
4841 size = mini_type_stack_size (cfg->generic_sharing_context, &in->klass->byval_arg, &align);
4843 if (ainfo->storage == ArgAggregate)
4845 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4848 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4850 vtaddr = mono_compile_create_var (cfg,
4851 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4854 * Part of the structure is passed in registers.
4856 for (j = 0; j < ainfo->nregs; ++j)
4858 int offset, load_op, dest_reg, arg_storage;
4860 slot = ainfo->reg + j;
4861 load_op = CEE_LDIND_I;
4863 dest_reg = ainfo->reg + j;
4864 arg_storage = ArgInIReg;
4866 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4867 load->ssa_op = MONO_SSA_LOAD;
4868 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4870 NEW_ICONST (cfg, offset_ins, offset);
4871 MONO_INST_NEW (cfg, load2, CEE_ADD);
4872 load2->inst_left = load;
4873 load2->inst_right = offset_ins;
4875 MONO_INST_NEW (cfg, load, load_op);
4876 load->inst_left = load2;
4881 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4883 add_outarg_reg (cfg, call, set_reg, arg_storage,
4885 if (set_reg != call->out_args)
4887 set_reg->next = call->out_args;
4888 call->out_args = set_reg;
4893 * Part of the structure is passed on the stack.
4895 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4899 slot = ainfo->reg + j;
4901 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4902 load->ssa_op = MONO_SSA_LOAD;
4903 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4905 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4906 MONO_INST_NEW (cfg, load2, CEE_ADD);
4907 load2->inst_left = load;
4908 load2->inst_right = offset_ins;
4910 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4911 load->inst_left = load2;
4916 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4918 outarg->inst_left = load;
4919 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4920 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4922 if (outarg != call->out_args)
4924 outarg->next = call->out_args;
4925 call->out_args = outarg;
4929 /* Trees can't be shared so make a copy*/
4930 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4931 arg->cil_code = in->cil_code;
4932 arg->ssa_op = MONO_SSA_STORE;
4933 arg->inst_left = vtaddr;
4934 arg->inst_right = in;
4935 arg->type = in->type;
4937 /* prepend, so they get reversed */
4938 arg->next = call->out_args;
4939 call->out_args = arg;
4943 MonoInst *stack_addr;
4945 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4947 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4948 stack_addr->inst_basereg = alpha_sp;
4949 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4950 stack_addr->inst_offset = ainfo->offset;
4951 //stack_addr->inst_offset = 16 + ainfo->offset;
4952 stack_addr->inst_imm = size;
4954 arg->opcode = OP_OUTARG_VT;
4955 arg->inst_right = stack_addr;
4959 arg->opcode = OP_OUTARG_VT;
4960 arg->klass = in->klass;
4961 arg->backend.is_pinvoke = sig->pinvoke;
4962 arg->inst_imm = size; */
4966 CFG_DEBUG(3) g_print("simple\n");
4968 switch (ainfo->storage)
4971 add_outarg_reg (cfg, call, arg, ainfo->storage,
4975 arg->opcode = OP_OUTARG;
4976 //arg->dreg = -((n - i) * 8);
4977 arg->dreg = ainfo->offset;
4978 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4980 if (!sig->params[i-sig->hasthis]->byref) {
4981 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4982 arg->opcode = OP_OUTARG_R4;
4984 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4985 arg->opcode = OP_OUTARG_R8;
4989 case ArgInDoubleReg:
4990 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4993 g_assert_not_reached ();
4999 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
5001 if (cinfo->ret.storage == ArgValuetypeInReg) {
5002 MonoInst *zero_inst;
5004 * After the call, the struct is in registers, but needs to be saved
5005 to the memory pointed
5006 * to by vt_arg in this_vret_args. This means that vt_ar
5007 g needs to be saved somewhere
5008 * before calling the function. So we add a dummy instru
5009 ction to represent pushing the
5010 * struct return address to the stack. The return addres
5011 s will be saved to this stack slot
5012 * by the code emitted in this_vret_args.
5014 MONO_INST_NEW (cfg, arg, OP_OUTARG);
5015 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
5016 zero_inst->inst_p0 = 0;
5017 arg->inst_left = zero_inst;
5018 arg->type = STACK_PTR;
5019 /* prepend, so they get reversed */
5020 arg->next = call->out_args;
5021 call->out_args = arg;
5024 /* if the function returns a struct, the called method a
5025 lready does a ret $0x4 */
5026 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
5027 ; //cinfo->stack_usage -= 4;
5030 // stack_usage shows how much stack we would need to do the call
5031 // (for example for params that we pass on stack
5032 call->stack_usage = cinfo->stack_usage;
5034 // Save all used regs to do the call in compile unit structure
5035 cfg->used_int_regs |= call->used_iregs;
5042 /*========================= End of Function ========================*/
5044 /*------------------------------------------------------------------*/
5046 /* Name - mono_arch_register_lowlevel_calls */
5048 /* Function - Register routines to help with --trace operation. */
5050 /*------------------------------------------------------------------*/
5053 mono_arch_register_lowlevel_calls (void)
5055 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
5057 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
5061 /*========================= End of Function ========================*/
5063 /*------------------------------------------------------------------*/
5065 /* Name - mono_arch_global_int_regs */
5067 /* Function - Return a list of usable integer registers. */
5069 /*------------------------------------------------------------------*/
5072 mono_arch_get_global_int_regs (MonoCompile *cfg)
5076 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5078 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5079 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5080 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5081 regs = g_list_prepend (regs, (gpointer)alpha_r12);
5082 regs = g_list_prepend (regs, (gpointer)alpha_r13);
5083 regs = g_list_prepend (regs, (gpointer)alpha_r14);
5088 /*========================= End of Function ========================*/
5090 /*------------------------------------------------------------------*/
5092 /* Name - mono_arch_get_allocatable_int_vars */
5096 /*------------------------------------------------------------------*/
5099 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
5103 MonoMethodSignature *sig;
5104 MonoMethodHeader *header;
5107 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5109 header = mono_method_get_header (cfg->method);
5111 sig = mono_method_signature (cfg->method);
5113 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5115 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5117 MonoInst *ins = cfg->args [i];
5119 ArgInfo *ainfo = &cinfo->args [i];
5122 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5125 // if (ainfo->storage == ArgInIReg) {
5126 // /* The input registers are non-volatile */
5127 // ins->opcode = OP_REGVAR;
5128 //ins->dreg = 32 + ainfo->reg;
5132 for (i = 0; i < cfg->num_varinfo; i++)
5134 MonoInst *ins = cfg->varinfo [i];
5135 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
5138 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
5142 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
5143 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
5146 if (mono_is_regsize_var (ins->inst_vtype))
5148 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
5149 g_assert (i == vmv->idx);
5150 vars = g_list_prepend (vars, vmv);
5154 vars = mono_varlist_sort (cfg, vars, 0);
5159 /*========================= End of Function ========================*/
5161 /*------------------------------------------------------------------*/
5163 /* Name - mono_arch_get_domain_intrinsic */
5169 /*------------------------------------------------------------------*/
5172 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5176 if (appdomain_tls_offset == -1)
5179 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5180 ins->inst_offset = appdomain_tls_offset;
5184 /*========================= End of Function ========================*/
5186 /*------------------------------------------------------------------*/
5188 /* Name - mono_arch_get_thread_intrinsic */
5194 /*------------------------------------------------------------------*/
5197 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5201 if (thread_tls_offset == -1)
5204 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5205 ins->inst_offset = thread_tls_offset;
5209 /*========================= End of Function ========================*/
5211 /*------------------------------------------------------------------*/
5213 /* Name - mono_arch_get_inst_for_method */
5215 /* Function - Check for opcodes we can handle directly in */
5218 /*------------------------------------------------------------------*/
5221 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5222 MonoMethodSignature *fsig, MonoInst **args)
5224 MonoInst *ins = NULL;
5226 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5228 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5233 /*========================= End of Function ========================*/
5235 /*------------------------------------------------------------------*/
5237 /* Name - mono_arch_create_class_init_trampoline */
5239 /* Function - Creates a trampoline function to run a type init- */
5240 /* ializer. If the trampoline is called, it calls */
5241 /* mono_runtime_class_init with the given vtable, */
5242 /* then patches the caller code so it does not get */
5243 /* called any more. */
5245 /* Parameter - vtable - The type to initialize */
5247 /* Returns - A pointer to the newly created code */
5249 /*------------------------------------------------------------------*/
5252 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5254 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5261 /*------------------------------------------------------------------*/
5263 /* Name - mono_arch_instrument_prolog */
5265 /* Function - Create an "instrumented" prolog. */
5267 /*------------------------------------------------------------------*/
5270 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5271 gboolean enable_arguments)
5273 unsigned int *code = p;
5276 CallInfo *cinfo = NULL;
5277 MonoMethodSignature *sig;
5279 int i, n, stack_area = 0;
5280 AlphaGotData ge_data;
5282 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5284 /* Keep this in sync with mono_arch_get_argument_info */
5285 if (enable_arguments)
5287 /* Allocate a new area on the stack and save arguments there */
5288 sig = mono_method_signature (cfg->method);
5290 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5292 n = sig->param_count + sig->hasthis;
5294 stack_area = ALIGN_TO (n * 8, 8);
5296 // Correct stack by calculated value
5298 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5300 for (i = 0; i < n; ++i)
5302 inst = cfg->args [i];
5304 if (inst->opcode == OP_REGVAR)
5306 switch(cinfo->args[i].storage)
5308 case ArgInDoubleReg:
5309 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5312 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5315 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5320 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5321 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5326 offset = (char *)code - (char *)cfg->native_code;
5328 ge_data.data.p = cfg->method;
5330 add_got_entry(cfg, GT_PTR, ge_data,
5331 (char *)code - (char *)cfg->native_code,
5332 MONO_PATCH_INFO_METHODCONST, cfg->method);
5333 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5335 alpha_mov1(code, alpha_sp, alpha_a1);
5337 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5339 if (enable_arguments)
5341 // Correct stack back by calculated value
5343 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5351 /*========================= End of Function ========================*/
5361 /*------------------------------------------------------------------*/
5363 /* Name - mono_arch_instrument_epilog */
5365 /* Function - Create an epilog that will handle the returned */
5366 /* values used in instrumentation. */
5368 /*------------------------------------------------------------------*/
5371 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p,
5372 gboolean enable_arguments)
5374 unsigned int *code = p;
5375 int save_mode = SAVE_NONE;
5377 MonoMethod *method = cfg->method;
5378 AlphaGotData ge_data;
5379 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5381 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5385 case MONO_TYPE_VOID:
5386 /* special case string .ctor icall */
5387 if (strcmp (".ctor", method->name) &&
5388 method->klass == mono_defaults.string_class)
5389 save_mode = SAVE_R0;
5391 save_mode = SAVE_NONE;
5395 save_mode = SAVE_R0;
5399 save_mode = SAVE_XMM;
5401 case MONO_TYPE_VALUETYPE:
5402 save_mode = SAVE_STRUCT;
5405 save_mode = SAVE_R0;
5409 /* Save the result and copy it into the proper argument register */
5413 alpha_lda(code, alpha_sp, alpha_sp, -8);
5414 alpha_stq(code, alpha_r0, alpha_sp, 0);
5416 if (enable_arguments)
5417 alpha_mov1(code, alpha_r0, alpha_a1);
5422 if (enable_arguments)
5423 alpha_lda(code, alpha_a1, alpha_zero, 0);
5427 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5428 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5430 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5432 * The result is already in the proper argument register so no copying
5439 g_assert_not_reached ();
5442 offset = (char *)code - (char *)cfg->native_code;
5444 ge_data.data.p = cfg->method;
5446 add_got_entry(cfg, GT_PTR, ge_data,
5447 (char *)code - (char *)cfg->native_code,
5448 MONO_PATCH_INFO_METHODCONST, cfg->method);
5450 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5452 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5454 /* Restore result */
5458 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5459 alpha_lda(code, alpha_sp, alpha_sp, 8);
5465 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5466 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5467 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5472 g_assert_not_reached ();
5478 /*========================= End of Function ========================*/
5480 /*------------------------------------------------------------------*/
5482 /* Name - mono_arch_allocate_vars */
5484 /* Function - Set var information according to the calling */
5485 /* convention for Alpha. The local var stuff should */
5486 /* most likely be split in another method. */
5488 /* Parameter - @m - Compile unit. */
5490 * This method is called right before working with BBs. Conversion to
5491 * IR was done and some analises what registers would be used.
5492 * Collect info about registers we used - if we want to use a register
5493 * we need to allocate space for it and save on the stack in method
5496 * Alpha calling convertion:
5497 * FP -> Stack top <- SP
5498 * 0: Stack params to call others
5500 * RA <- arch.params_stack_size
5503 * [LMF info] <- arch.lmf_offset
5505 * [possible return values allocated on stack]
5509 * . caller saved regs <- arch.reg_save_area_offset
5510 * . a0 <- arch.args_save_area_offset
5516 * ------------------------
5517 * . a6 - passed args on stack
5520 /*------------------------------------------------------------------*/
5523 mono_arch_allocate_vars (MonoCompile *cfg)
5525 MonoMethodSignature *sig;
5526 MonoMethodHeader *header;
5528 int i, offset = 0, a_off = 0;
5529 guint32 locals_stack_size, locals_stack_align = 0;
5533 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5535 header = mono_method_get_header (cfg->method);
5537 sig = mono_method_signature (cfg->method);
5539 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5541 /* if (cfg->arch.omit_fp) {
5542 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5543 cfg->frame_reg = AMD64_RSP;
5548 /* Locals are allocated forwards from FP. After
5549 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5550 * (starting from offset 16).
5551 * FIXME: Check there Arg6...Argn are supposed to be
5553 cfg->frame_reg = alpha_fp;
5554 // offset = MONO_ALPHA_VARS_OFFSET;
5557 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5558 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5559 offset += cfg->arch.params_stack_size;
5561 offset += 16; // Size to save RA & FP
5563 if (cfg->method->save_lmf)
5565 /* Reserve stack space for saving LMF + argument regs */
5566 guint32 size = sizeof (MonoLMF);
5568 //if (lmf_tls_offset == -1)
5569 // /* Need to save argument regs too */
5570 // size += (AMD64_NREG * 8) + (8 * 8);
5572 cfg->arch.lmf_offset = offset;
5575 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5576 cfg->method->name, cfg->arch.lmf_offset, size);
5579 if (sig->ret->type != MONO_TYPE_VOID)
5581 switch (cinfo->ret.storage)
5585 case ArgInDoubleReg:
5586 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5587 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5588 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5590 /* The register is volatile */
5591 cfg->ret->opcode = OP_REGOFFSET;
5592 cfg->ret->inst_basereg = cfg->frame_reg;
5594 /*if (cfg->arch.omit_fp) {
5595 cfg->ret->inst_offset = offset;
5599 cfg->ret->inst_offset = offset;
5600 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5606 cfg->ret->opcode = OP_REGVAR;
5607 cfg->ret->inst_c0 = cinfo->ret.reg;
5610 case ArgValuetypeInReg:
5611 /* Allocate a local to hold the result, the epilog will
5612 copy it to the correct place */
5613 // g_assert (!cfg->arch.omit_fp);
5615 cfg->ret->opcode = OP_REGOFFSET;
5616 cfg->ret->inst_basereg = cfg->frame_reg;
5617 cfg->ret->inst_offset = offset;
5620 g_assert_not_reached ();
5622 cfg->ret->dreg = cfg->ret->inst_c0;
5625 /* Allocate locals */
5626 offsets = mono_allocate_stack_slots_full (cfg,
5627 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5629 &locals_stack_align);
5631 //g_assert((locals_stack_size % 8) == 0);
5632 if (locals_stack_size % 8)
5634 locals_stack_size += 8 - (locals_stack_size % 8);
5637 /* if (locals_stack_align)
5639 offset += (locals_stack_align - 1);
5640 offset &= ~(locals_stack_align - 1);
5644 cfg->arch.localloc_offset = offset;
5646 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5647 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5648 locals_stack_size, locals_stack_size);
5650 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5652 if (offsets [i] != -1) {
5653 MonoInst *inst = cfg->varinfo [i];
5654 inst->opcode = OP_REGOFFSET;
5655 inst->inst_basereg = cfg->frame_reg;
5656 //if (cfg->arch.omit_fp)
5657 // inst->inst_offset = (offset + offsets [i]);
5659 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5661 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5662 CFG_DEBUG(3) mono_print_tree_nl (inst);
5666 // TODO check how offsets[i] are calculated
5667 // it seems they are points to the end on data. Like 8, but it actually - 0
5669 offset += locals_stack_size; //+8;
5671 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5672 // g_assert (!cfg->arch.omit_fp);
5673 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5674 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5677 // Save offset for caller saved regs
5678 cfg->arch.reg_save_area_offset = offset;
5680 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5682 // Reserve space for caller saved registers
5683 for (i = 0; i < MONO_MAX_IREGS; ++i)
5684 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5685 (cfg->used_int_regs & (1 << i)))
5687 offset += sizeof (gpointer);
5690 // Save offset to args regs
5691 cfg->arch.args_save_area_offset = offset;
5693 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5695 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5697 ArgInfo *ainfo = &cinfo->args [i];
5699 switch(ainfo->storage)
5703 case ArgInDoubleReg:
5704 offset += sizeof (gpointer);
5707 offset += ainfo->nregs * sizeof (gpointer);
5714 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5717 // Reserve space for method params
5718 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5720 inst = cfg->args [i];
5722 if (inst->opcode != OP_REGVAR)
5724 ArgInfo *ainfo = &cinfo->args [i];
5725 gboolean inreg = TRUE;
5728 if (sig->hasthis && (i == 0))
5729 arg_type = &mono_defaults.object_class->byval_arg;
5731 arg_type = sig->params [i - sig->hasthis];
5733 /* FIXME: Allocate volatile arguments to registers */
5734 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5738 * Under AMD64, all registers used to pass arguments to functions
5739 * are volatile across calls. For Alpha too.
5740 * FIXME: Optimize this.
5744 if (inreg && (ainfo->storage == ArgInIReg)
5745 //&& cfg->used_int_regs & (1 << ainfo->reg)
5749 if (//(ainfo->storage == ArgInIReg) ||
5750 (ainfo->storage == ArgInFloatReg) ||
5751 (ainfo->storage == ArgInDoubleReg) ||
5752 (ainfo->storage == ArgValuetypeInReg))
5755 inst->opcode = OP_REGOFFSET;
5757 switch (ainfo->storage)
5761 case ArgInDoubleReg:
5762 inst->opcode = OP_REGVAR;
5763 inst->dreg = ainfo->reg;
5766 // g_assert (!cfg->arch.omit_fp);
5767 inst->opcode = OP_REGOFFSET;
5768 inst->inst_basereg = cfg->frame_reg;
5770 // "offset" here will point to the end of
5771 // array of saved ret,locals, args
5772 // Ideally it would point to "a7"
5773 inst->inst_offset = ainfo->offset + offset;
5775 case ArgValuetypeInReg:
5785 if (!inreg && (ainfo->storage != ArgOnStack))
5787 inst->opcode = OP_REGOFFSET;
5788 inst->inst_basereg = cfg->frame_reg;
5790 /* These arguments are saved to the stack in the prolog */
5791 /*if (cfg->arch.omit_fp) {
5792 inst->inst_offset = offset;
5793 offset += (ainfo->storage == ArgValuetypeInReg) ?
5794 2 * sizeof (gpointer) : sizeof (gpointer);
5797 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5798 // 2 * sizeof (gpointer) : sizeof (gpointer);
5800 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5801 switch(ainfo->storage)
5804 a_off += ainfo->nslots * 8;
5807 a_off += sizeof (gpointer);
5809 // (/*(ainfo->reg - 16)*/ i * 8);
5815 cfg->stack_offset = offset;
5820 /*========================= End of Function ========================*/
5822 /*------------------------------------------------------------------*/
5824 /* Name - mono_arch_print_tree */
5826 /* Function - Print platform-specific opcode details. */
5828 /* Returns - 1 - opcode details have been printed */
5829 /* 0 - opcode details have not been printed */
5831 /*------------------------------------------------------------------*/
5834 mono_arch_print_tree (MonoInst *tree, int arity)
5838 ALPHA_DEBUG("mono_arch_print_tree");
5840 switch (tree->opcode) {
5847 /*========================= End of Function ========================*/
5851 ** mono_arch_get_vcall_slot_addr
5852 ** is called by mono_magic_trampoline to determine that the JIT compiled
5853 ** method is called via vtable slot. We need to analyze call sequence
5854 ** and determine that. In case it is true - we need to return address
5857 ** code - points to the next instruction after call
5858 ** reg - points to saved regs before the call (this is done
5859 ** by mono_magic_trampoline function
5863 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
5865 unsigned int *pc = (unsigned int *)code;
5867 int start_index = -2;
5869 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5872 // Check if we have parameters on stack
5873 if ((pc[-2] & 0xFFFF0000) == 0x23DE0000) // lda sp,-n(sp)
5876 // Check for (call_membase):
5877 // -4: mov v0,a0 - load this ???
5878 // -3: ldq v0,0(v0) - load vtable
5879 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5880 if ((pc[start_index-1] & 0xFC00FFFF) == 0xA4000000 &&
5881 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5884 disp = pc[start_index] & 0xFFFF;
5885 reg = (pc[start_index-1] >> AXP_REG1_SHIFT) & AXP_REG_MASK;
5886 //reg = 0; // For now
5888 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5890 return (gpointer)(((guint64)(regs [reg])) + disp);
5893 // Check for interface call
5896 // -3: ldq v0,-n(v0)
5897 // -2: ldq t12,0(v0)
5898 if ((pc[start_index-2] & 0xFC00FFFF) == 0xA4000000 &&
5899 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5900 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5903 disp = pc[start_index] & 0xFFFF;;
5906 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5908 return (gpointer)(((guint64)(regs [reg])) + disp);
5915 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
5917 unsigned int *pc = (unsigned int *)code;
5919 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_this_arg_from_call] code: %p regs: %p",
5922 if (MONO_TYPE_ISSTRUCT (sig->ret))
5923 return (gpointer)regs [alpha_a1];
5925 return (gpointer)regs [alpha_a0];
5929 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5931 unsigned int *code, *start;
5932 MonoDomain *domain = mono_domain_get ();
5935 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_delegate_invoke_impl]");
5937 /* FIXME: Support more cases */
5938 if (MONO_TYPE_ISSTRUCT (sig->ret))
5945 mono_arch_get_patch_offset (guint8 *code)
5951 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5953 /* FIXME: implement */
5954 g_assert_not_reached ();