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)); \
34 #define DEBUG(a) if (cfg->verbose_level > 1) a
36 #define CFG_DEBUG(LVL) if (cfg->verbose_level > LVL)
38 //#define ALPHA_IS_CALLEE_SAVED_REG(reg) (MONO_ARCH_CALLEE_SAVED_REGS & (1 << (reg)))
39 #define ALPHA_ARGS_REGS ((regmask_t)0x03F0000)
40 #define ARGS_OFFSET 16
42 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
43 #define alpha_is_imm(X) ((X >= 0 && X <= 255))
44 #define ALPHA_LOAD_GP(IP) { AlphaGotData ge_data; add_got_entry(cfg, GT_LD_GTADDR, ge_data, IP, MONO_PATCH_INFO_NONE, 0); }
46 /*========================= End of Defines =========================*/
48 /*------------------------------------------------------------------*/
50 /*------------------------------------------------------------------*/
55 #include <mono/metadata/appdomain.h>
56 #include <mono/metadata/debug-helpers.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/utils/mono-math.h>
61 #include "mini-alpha.h"
62 #include "cpu-alpha.h"
63 #include "jit-icalls.h"
65 /*========================= End of Includes ========================*/
67 /*------------------------------------------------------------------*/
68 /* G l o b a l V a r i a b l e s */
69 /*------------------------------------------------------------------*/
70 static int indent_level = 0;
72 int mini_alpha_verbose_level = 0;
73 static int bwx_supported = 0;
75 static int appdomain_tls_offset = -1,
77 thread_tls_offset = -1;
79 pthread_key_t lmf_addr_key;
81 gboolean lmf_addr_key_inited = FALSE;
84 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
86 /*====================== End of Global Variables ===================*/
88 gpointer mono_arch_get_lmf_addr (void);
95 ArgValuetypeInReg, // ??
106 /* Only if storage == ArgAggregate */
108 //AggregateType atype; // So far use only AggregateNormal
114 // guint32 struct_ret; /// ???
118 gboolean need_stack_align;
125 static CallInfo* get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke);
126 static unsigned int *emit_call(MonoCompile *cfg, unsigned int *code,
127 guint32 patch_type, gconstpointer data);
130 static int param_regs [] =
137 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
140 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
142 ainfo->offset = *stack_size;
144 if (*gr >= PARAM_REGS)
146 ainfo->storage = ArgOnStack;
147 (*stack_size) += sizeof (gpointer);
151 ainfo->storage = ArgInIReg;
152 ainfo->reg = param_regs [*gr];
157 #define FLOAT_PARAM_REGS 6
158 static int fparam_regs [] = { alpha_fa0, alpha_fa1, alpha_fa2, alpha_fa3,
159 alpha_fa4, alpha_fa5 };
162 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo,
165 ainfo->offset = *stack_size;
167 if (*gr >= FLOAT_PARAM_REGS)
169 ainfo->storage = ArgOnStack;
170 (*stack_size) += sizeof (gpointer);
174 /* A double register */
176 ainfo->storage = ArgInDoubleReg;
178 ainfo->storage = ArgInFloatReg;
180 ainfo->reg = fparam_regs [*gr];
186 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
188 guint32 *gr, guint32 *fr, guint32 *stack_size)
192 MonoMarshalType *info;
193 //gboolean is_hfa = TRUE;
194 //guint32 hfa_type = 0;
196 klass = mono_class_from_mono_type (type);
197 if (type->type == MONO_TYPE_TYPEDBYREF)
198 size = 3 * sizeof (gpointer);
199 else if (sig->pinvoke)
200 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
202 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
204 if (!sig->pinvoke || (size == 0) || is_return) {
205 /* Allways pass in memory */
206 ainfo->offset = *stack_size;
207 *stack_size += ALIGN_TO (size, 8);
208 ainfo->storage = ArgOnStack;
213 info = mono_marshal_load_type_info (klass);
216 ainfo->storage = ArgAggregate;
217 //ainfo->atype = AggregateNormal;
220 /* This also handles returning of TypedByRef used by some icalls */
223 ainfo->reg = IA64_R8;
224 ainfo->nregs = (size + 7) / 8;
225 ainfo->nslots = ainfo->nregs;
232 ainfo->reg = param_regs [*gr];
233 ainfo->offset = *stack_size;
234 ainfo->nslots = (size + 7) / 8;
236 if (((*gr) + ainfo->nslots) <= 6) {
237 /* Fits entirely in registers */
238 ainfo->nregs = ainfo->nslots;
239 (*gr) += ainfo->nregs;
243 ainfo->nregs = 6 - (*gr);
245 (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
249 // This function is called from mono_arch_call_opcode and
250 // should determine which registers will be used to do the call
251 // For Alpha we could calculate number of parameter used for each
252 // call and allocate space in stack only for whose "a0-a5" registers
253 // that will be used in calls
255 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
256 ArgStorage storage, int reg, MonoInst *tree)
261 arg->opcode = OP_OUTARG_REG;
262 arg->inst_left = tree;
263 arg->inst_right = (MonoInst*)call;
264 arg->backend.reg3 = reg;
265 call->used_iregs |= 1 << reg;
268 arg->opcode = OP_OUTARG_FREG;
269 arg->inst_left = tree;
270 arg->inst_right = (MonoInst*)call;
271 arg->backend.reg3 = reg;
272 call->used_fregs |= 1 << reg;
275 arg->opcode = OP_OUTARG_FREG;
276 arg->inst_left = tree;
277 arg->inst_right = (MonoInst*)call;
278 arg->backend.reg3 = reg;
279 call->used_fregs |= 1 << reg;
282 g_assert_not_reached ();
287 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
292 bb->code = to_insert;
293 to_insert->next = ins;
297 to_insert->next = ins->next;
298 ins->next = to_insert;
302 static void add_got_entry(MonoCompile *cfg, AlphaGotType ge_type,
303 AlphaGotData ge_data,
304 int ip, MonoJumpInfoType type, gconstpointer target)
306 AlphaGotEntry *AGE = mono_mempool_alloc (cfg->mempool,
307 sizeof (AlphaGotEntry));
314 AGE->value.data.i = ge_data.data.i;
317 AGE->value.data.l = ge_data.data.l;
320 AGE->value.data.p = ge_data.data.p;
323 AGE->value.data.f = ge_data.data.f;
326 AGE->value.data.d = ge_data.data.d;
329 AGE->value.data.l = ip;
335 if (type != MONO_PATCH_INFO_NONE)
337 mono_add_patch_info(cfg, ip, type, target);
338 AGE->patch_info = cfg->patch_info;
343 if (AGE->type != GT_LD_GTADDR)
345 mono_add_patch_info(cfg, ip, MONO_PATCH_INFO_GOT_OFFSET, 0);
346 AGE->got_patch_info = cfg->patch_info;
349 AGE->next = cfg->arch.got_data;
351 cfg->arch.got_data = AGE;
354 /*------------------------------------------------------------------*/
356 /* Name - mono_arch_create_vars */
363 * cfg - pointer to compile unit
366 * This method is called right before starting converting compiled
367 * method to IR. I guess we could find out how many arguments we
368 * should expect, what type and what return value would be.
369 * After that we could correct "cfg" structure, or "arch" part of
373 /*------------------------------------------------------------------*/
376 mono_arch_create_vars (MonoCompile *cfg)
378 MonoMethodSignature *sig;
381 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
383 sig = mono_method_signature (cfg->method);
385 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
387 if (cinfo->ret.storage == ArgValuetypeInReg)
388 cfg->ret_var_is_local = TRUE;
394 /*------------------------------------------------------------------*/
396 /* Name - mono_arch_get_lmf_addr */
402 /*------------------------------------------------------------------*/
405 mono_arch_get_lmf_addr (void)
407 ALPHA_DEBUG("mono_arch_get_lmf_addr");
409 return pthread_getspecific (lmf_addr_key);
412 /*========================= End of Function ========================*/
414 /*------------------------------------------------------------------*/
416 /* Name - mono_arch_free_jit_tls_data */
418 /* Function - Free tls data. */
420 /*------------------------------------------------------------------*/
423 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
425 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
428 /*========================= End of Function ========================*/
430 // This peephole function is called before "local_regalloc" method
431 // TSV_TODO - Check what we need to move here
433 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
435 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_1 pass\n");
438 // This peephole function is called after "local_regalloc" method
440 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
442 MonoInst *ins, *n, *last_ins = NULL;
445 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_2 pass\n");
447 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
455 * OP_MOVE reg, reg except special case (mov at, at)
457 if (ins->dreg == ins->sreg1 &&
458 ins->dreg != alpha_at)
460 MONO_DELETE_INS (bb, ins);
470 if (last_ins && last_ins->opcode == OP_MOVE &&
471 ins->sreg1 == last_ins->dreg &&
472 last_ins->dreg != alpha_at &&
473 ins->dreg == last_ins->sreg1)
475 MONO_DELETE_INS (bb, ins);
482 /* remove unnecessary multiplication with 1 */
483 if (ins->inst_imm == 1)
485 if (ins->dreg != ins->sreg1)
487 ins->opcode = OP_MOVE;
491 MONO_DELETE_INS (bb, ins);
498 case OP_LOADI8_MEMBASE:
499 case OP_LOAD_MEMBASE:
501 * Note: if reg1 = reg2 the load op is removed
503 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
504 * OP_LOADI8_MEMBASE offset(basereg), reg2
506 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
510 (last_ins->opcode == OP_STOREI8_MEMBASE_REG ||
511 last_ins->opcode == OP_STORE_MEMBASE_REG) &&
512 ins->inst_basereg == last_ins->inst_destbasereg &&
513 ins->inst_offset == last_ins->inst_offset)
515 if (ins->dreg == last_ins->sreg1)
517 MONO_DELETE_INS (bb, ins);
522 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
523 ins->opcode = OP_MOVE;
524 ins->sreg1 = last_ins->sreg1;
530 case OP_LOAD_MEMBASE:
531 case OP_LOADI4_MEMBASE:
533 * Note: if reg1 = reg2 the load op is removed
535 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
536 * OP_LOAD_MEMBASE offset(basereg), reg2
538 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
541 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
542 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
543 ins->inst_basereg == last_ins->inst_destbasereg &&
544 ins->inst_offset == last_ins->inst_offset)
546 if (ins->dreg == last_ins->sreg1)
548 MONO_DELETE_INS (bb, ins);
553 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
554 ins->opcode = OP_MOVE;
555 ins->sreg1 = last_ins->sreg1;
559 * Note: reg1 must be different from the basereg in the second load
560 * Note: if reg1 = reg2 is equal then second load is removed
562 * OP_LOAD_MEMBASE offset(basereg), reg1
563 * OP_LOAD_MEMBASE offset(basereg), reg2
565 * OP_LOAD_MEMBASE offset(basereg), reg1
569 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
570 || last_ins->opcode == OP_LOAD_MEMBASE) &&
571 ins->inst_basereg != last_ins->dreg &&
572 ins->inst_basereg == last_ins->inst_basereg &&
573 ins->inst_offset == last_ins->inst_offset)
575 if (ins->dreg == last_ins->dreg)
577 MONO_DELETE_INS (bb, ins);
582 ins->opcode = OP_MOVE;
583 ins->sreg1 = last_ins->dreg;
586 //g_assert_not_reached ();
596 bb->last_ins = last_ins;
599 // Convert to opposite branch opcode
600 static guint16 cvt_branch_opcode(guint16 opcode)
605 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
610 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
614 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
618 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
622 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
626 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
630 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
634 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
638 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
642 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
646 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
650 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
654 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
658 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
662 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
666 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
670 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
674 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
678 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
682 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
686 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
690 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
694 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
698 ALPHA_PRINT g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
702 ALPHA_PRINT g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
709 ALPHA_PRINT g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode);
714 typedef enum { EQ, ULE, LE, LT, ULT } ALPHA_CMP_OPS;
716 static guint16 cvt_cmp_opcode(guint16 opcode, ALPHA_CMP_OPS cond)
722 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
733 return OP_ALPHA_CMP_EQ;
735 return OP_ALPHA_CMP_ULE;
737 return OP_ALPHA_CMP_LE;
739 return OP_ALPHA_CMP_LT;
741 return OP_ALPHA_CMP_ULT;
746 case OP_ICOMPARE_IMM:
752 return OP_ALPHA_CMP_IMM_EQ;
754 return OP_ALPHA_CMP_IMM_ULE;
756 return OP_ALPHA_CMP_IMM_LE;
758 return OP_ALPHA_CMP_IMM_LT;
760 return OP_ALPHA_CMP_IMM_ULT;
765 g_assert_not_reached();
770 static void cvt_cmp_branch(MonoInst *curr, MonoInst *next)
772 // Instead of compare+b<cond>,
773 // Alpha has compare<cond>+br<cond>
774 // we need to convert
775 // Handle floating compare here too
781 // Convert cmp + beq -> cmpeq + bne
782 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
783 next->opcode = cvt_branch_opcode(next->opcode);
788 // cmp + ibne_un -> cmpeq + beq
789 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
790 next->opcode = cvt_branch_opcode(next->opcode);
795 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
796 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
797 next->opcode = cvt_branch_opcode(next->opcode);
802 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
803 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
804 next->opcode = cvt_branch_opcode(next->opcode);
809 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
810 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
811 next->opcode = cvt_branch_opcode(next->opcode);
816 // lcmp + blt.un -> cmpult + bne
817 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
818 next->opcode = cvt_branch_opcode(next->opcode);
823 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
824 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
825 next->opcode = cvt_branch_opcode(next->opcode);
830 //lcmp + bge.un -> cmpult + beq
831 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
832 next->opcode = cvt_branch_opcode(next->opcode);
837 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
838 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
839 next->opcode = cvt_branch_opcode(next->opcode);
844 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
845 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
846 next->opcode = cvt_branch_opcode(next->opcode);
852 // cmp + cgt_un -> cmpule + beq
853 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
858 // cmp + iceq -> cmpeq + bne
859 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
864 // cmp + int_cgt -> cmple + beq
865 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
870 // cmp + int_clt -> cmplt + bne
871 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
876 // cmp + int_clt_un -> cmpult + bne
877 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
881 // The conditional exceptions will be handled in
882 // output_basic_blocks. Here we just determine correct
885 curr->opcode = cvt_cmp_opcode(curr->opcode, LE);
888 case OP_COND_EXC_GT_UN:
889 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
893 curr->opcode = cvt_cmp_opcode(curr->opcode, LT);
896 case OP_COND_EXC_LT_UN:
897 curr->opcode = cvt_cmp_opcode(curr->opcode, ULT);
900 case OP_COND_EXC_LE_UN:
901 curr->opcode = cvt_cmp_opcode(curr->opcode, ULE);
904 case OP_COND_EXC_NE_UN:
905 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
909 curr->opcode = cvt_cmp_opcode(curr->opcode, EQ);
914 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
915 mono_inst_name(next->opcode), next->opcode);
917 // g_assert_not_reached();
925 * mono_arch_lowering_pass:
927 * Converts complex opcodes into simpler ones so that each IR instruction
928 * corresponds to one machine instruction.
931 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
933 MonoInst *ins, *n, *temp, *last_ins = NULL;
939 * FIXME: Need to add more instructions, but the current machine
940 * description can't model some parts of the composite instructions like
944 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
952 NEW_INS (cfg, temp, OP_I8CONST);
953 temp->inst_c0 = ins->inst_imm;
954 temp->dreg = mono_alloc_ireg (cfg);
959 ins->opcode = CEE_MUL;
962 ins->opcode = OP_LDIV;
965 ins->opcode = OP_LREM;
968 ins->opcode = OP_IDIV;
971 ins->opcode = OP_IREM;
975 ins->sreg2 = temp->dreg;
983 // Instead of compare+b<cond>/fcompare+b<cond>,
984 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
985 // we need to convert
988 cvt_cmp_branch(ins, next);
993 if (!alpha_is_imm (ins->inst_imm))
995 NEW_INS (cfg, temp, OP_I8CONST);
996 temp->inst_c0 = ins->inst_imm;
997 temp->dreg = mono_alloc_ireg (cfg);
998 ins->opcode = OP_COMPARE;
999 ins->sreg2 = temp->dreg;
1001 // We should try to reevaluate new IR opcode
1007 cvt_cmp_branch(ins, next);
1011 case OP_ICOMPARE_IMM:
1012 if (!alpha_is_imm (ins->inst_imm))
1014 NEW_INS (cfg, temp, OP_ICONST);
1015 temp->inst_c0 = ins->inst_imm;
1016 temp->dreg = mono_alloc_ireg (cfg);
1017 ins->opcode = OP_ICOMPARE;
1018 ins->sreg2 = temp->dreg;
1020 // We should try to reevaluate new IR opcode
1026 cvt_cmp_branch(ins, next);
1030 case OP_STORE_MEMBASE_IMM:
1031 case OP_STOREI8_MEMBASE_IMM:
1032 if (ins->inst_imm != 0)
1034 NEW_INS (cfg, temp, OP_I8CONST);
1035 temp->inst_c0 = ins->inst_imm;
1036 temp->dreg = mono_alloc_ireg (cfg);
1037 ins->opcode = OP_STOREI8_MEMBASE_REG;
1038 ins->sreg1 = temp->dreg;
1042 case OP_STOREI4_MEMBASE_IMM:
1043 if (ins->inst_imm != 0)
1046 NEW_INS (cfg, temp, OP_ICONST);
1047 temp->inst_c0 = ins->inst_imm;
1048 temp->dreg = mono_alloc_ireg (cfg);
1049 ins->opcode = OP_STOREI4_MEMBASE_REG;
1050 ins->sreg1 = temp->dreg;
1054 case OP_STOREI1_MEMBASE_IMM:
1055 if (ins->inst_imm != 0 || !bwx_supported)
1058 NEW_INS (cfg, temp, OP_ICONST);
1059 temp->inst_c0 = ins->inst_imm;
1060 temp->dreg = mono_alloc_ireg (cfg);
1061 ins->opcode = OP_STOREI1_MEMBASE_REG;
1062 ins->sreg1 = temp->dreg;
1066 case OP_STOREI2_MEMBASE_IMM:
1067 if (ins->inst_imm != 0 || !bwx_supported)
1070 NEW_INS (cfg, temp, OP_ICONST);
1071 temp->inst_c0 = ins->inst_imm;
1072 temp->dreg = mono_alloc_ireg (cfg);
1073 ins->opcode = OP_STOREI2_MEMBASE_REG;
1074 ins->sreg1 = temp->dreg;
1085 case OP_ISHR_UN_IMM:
1086 if (!alpha_is_imm(ins->inst_imm))
1089 NEW_INS (cfg, temp, OP_ICONST);
1090 temp->inst_c0 = ins->inst_imm;
1091 temp->dreg = mono_alloc_ireg (cfg);
1096 ins->opcode = OP_IADD;
1099 ins->opcode = OP_ISUB;
1102 ins->opcode = OP_IAND;
1105 ins->opcode = OP_IOR;
1108 ins->opcode = OP_IXOR;
1111 ins->opcode = OP_ISHL;
1114 ins->opcode = OP_ISHR;
1116 case OP_ISHR_UN_IMM:
1117 ins->opcode = OP_ISHR_UN;
1123 ins->sreg2 = temp->dreg;
1129 if (!alpha_is_imm(ins->inst_imm))
1132 NEW_INS (cfg, temp, OP_ICONST);
1133 temp->inst_c0 = ins->inst_imm;
1134 temp->dreg = mono_alloc_ireg (cfg);
1139 ins->opcode = CEE_ADD;
1142 ins->opcode = CEE_SUB;
1145 ins->opcode = CEE_AND;
1148 ins->opcode = CEE_SHL;
1154 ins->sreg2 = temp->dreg;
1158 if (!alpha_is_imm(ins->inst_imm))
1161 NEW_INS(cfg, temp, OP_ICONST);
1162 temp->inst_c0 = ins->inst_imm;
1163 temp->dreg = mono_alloc_ireg (cfg);
1164 ins->sreg2 = temp->dreg;
1165 ins->opcode = OP_LSHR;
1169 if (!alpha_is_imm(ins->inst_imm))
1172 NEW_INS(cfg, temp, OP_ICONST);
1173 temp->inst_c0 = ins->inst_imm;
1174 temp->dreg = mono_alloc_ireg (cfg);
1175 ins->sreg2 = temp->dreg;
1176 ins->opcode = OP_LSHL;
1188 bb->last_ins = last_ins;
1190 bb->max_vreg = cfg->next_vreg;
1193 /*========================= End of Function ========================*/
1195 #define AXP_GENERAL_REGS 6
1196 #define AXP_MIN_STACK_SIZE 24
1198 /* A typical Alpha stack frame looks like this */
1200 fun: // called from outside the module.
1201 ldgp gp,0(pv) // load the global pointer
1202 fun..ng: // called from inside the module.
1203 lda sp, -SIZE( sp ) // grow the stack downwards.
1205 stq ra, 0(sp) // save the return address.
1207 stq s0, 8(sp) // callee-saved registers.
1208 stq s1, 16(sp) // ...
1210 // Move the arguments to the argument registers...
1212 mov addr, pv // Load the callee address
1213 jsr ra, (pv) // call the method.
1214 ldgp gp, 0(ra) // restore gp
1216 // return value is in v0
1218 ldq ra, 0(sp) // free stack frame
1219 ldq s0, 8(sp) // restore callee-saved registers.
1221 ldq sp, 32(sp) // restore stack pointer
1223 ret zero, (ra), 1 // return.
1226 // our call must look like this.
1232 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1233 stq ra, SIZE-48(sp) // store ra
1234 stq fp, SIZE-40(sp) // store fp (frame pointer)
1235 stq a0, SIZE-32(sp) // store args. a0 = func
1236 stq a1, SIZE-24(sp) // a1 = retval
1237 stq a2, SIZE-16(sp) // a2 = this
1238 stq a3, SIZE-8(sp) // a3 = args
1239 mov sp, fp // set frame pointer
1259 jsr ra, (pv) // call func
1260 ldgp gp, 0(ra) // restore gp.
1261 mov v0, t1 // move return value into t1
1264 ldq t0, SIZE-24(fp) // load retval into t2
1265 stl t1, 0(t0) // store value.
1276 * emit_load_volatile_arguments:
1278 * Load volatile arguments from the stack to the original input registers.
1279 * Required before a tail call.
1281 static unsigned int*
1282 emit_load_volatile_arguments (MonoCompile *cfg, unsigned int *code)
1284 MonoMethod *method = cfg->method;
1285 MonoMethodSignature *sig;
1290 /* FIXME: Generate intermediate code instead */
1292 sig = mono_method_signature (method);
1294 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1296 if (sig->ret->type != MONO_TYPE_VOID) {
1297 if ((cinfo->ret.storage == ArgInIReg) &&
1298 (cfg->ret->opcode != OP_REGVAR))
1300 alpha_ldq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1301 cfg->ret->inst_offset);
1305 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1307 ArgInfo *ainfo = &cinfo->args [i];
1308 MonoInst *inst = cfg->args [i];
1310 switch(ainfo->storage)
1313 // We need to save all used a0-a5 params
1314 //for (i=0; i<PARAM_REGS; i++)
1316 // if (i < cinfo->reg_usage)
1318 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1319 alpha_ldq(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1321 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1322 ainfo->reg, inst->inst_offset/*offset*/);
1326 case ArgInDoubleReg:
1328 // We need to save all used af0-af5 params
1329 //for (i=0; i<PARAM_REGS; i++)
1331 // if (i < cinfo->freg_usage)
1333 switch(cinfo->args[i].storage)
1336 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1337 alpha_lds(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1339 case ArgInDoubleReg:
1340 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1341 alpha_ldt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1347 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1348 ainfo->reg, /*offset*/inst->inst_offset);
1357 /*------------------------------------------------------------------*/
1359 /* Name - mono_arch_emit_prolog */
1361 /* Function - Create the instruction sequence for a function */
1364 * How to handle consts and method addreses:
1365 * For method we will allocate array of qword after method epiloge.
1366 * These qword will hold readonly info to method to properly to run.
1367 * For example: qword constants, method addreses
1368 * GP will point to start of data. Offsets to the data will be equal
1369 * to "address" of data - start of GP. (GP = 0 during method jiting).
1370 * GP is easily calculated from passed PV (method start address).
1371 * The patch will update GP loadings.
1372 * The GOT section should be more than 32Kb.
1373 * The patch code should put proper offset since the real position of
1374 * qword array will be known after the function epiloge.
1376 /*------------------------------------------------------------------*/
1379 mono_arch_emit_prolog (MonoCompile *cfg)
1381 MonoMethod *method = cfg->method;
1382 MonoMethodSignature *sig = mono_method_signature (method);
1383 //int alloc_size, code_size, max_offset, quad;
1386 int i, stack_size, offset;
1387 gint32 lmf_offset = cfg->arch.lmf_offset;
1389 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1391 // FIXME: Use just one field to hold calculated stack size
1392 cfg->arch.stack_size = stack_size = cfg->stack_offset;
1393 cfg->arch.got_data = 0;
1395 cfg->code_size = 512;
1397 code = (unsigned int *)g_malloc(cfg->code_size);
1398 cfg->native_code = (void *)code;
1400 // Emit method prolog
1401 // Calculate GP from passed PV, allocate stack
1403 alpha_ldah( code, alpha_gp, alpha_pv, 0 );
1404 alpha_lda( code, alpha_gp, alpha_gp, 0 ); // ldgp gp, 0(pv)
1405 alpha_lda( code, alpha_sp, alpha_sp, -(stack_size) );
1407 offset = cfg->arch.params_stack_size;
1409 /* store call convention parameters on stack */
1410 alpha_stq( code, alpha_ra, alpha_sp, (offset + 0) ); // RA
1411 alpha_stq( code, alpha_fp, alpha_sp, (offset + 8) ); // FP
1413 /* set the frame pointer */
1414 alpha_mov1( code, alpha_sp, alpha_fp );
1417 if (method->save_lmf)
1420 alpha_stq(code, alpha_pv, alpha_fp,
1421 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip)));
1423 alpha_stq(code, alpha_sp, alpha_fp,
1424 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rsp)));
1426 alpha_stq(code, alpha_fp, alpha_fp,
1427 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
1429 alpha_stq(code, alpha_gp, alpha_fp,
1430 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, rgp)));
1433 alpha_stq(code, alpha_pv, alpha_fp,
1434 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
1437 /* Save (global) regs */
1438 offset = cfg->arch.reg_save_area_offset;
1440 for (i = 0; i < MONO_MAX_IREGS; ++i)
1441 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1442 (cfg->used_int_regs & (1 << i)) &&
1443 !( ALPHA_ARGS_REGS & (1 << i)) )
1445 alpha_stq(code, i, alpha_fp, offset);
1446 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1451 offset = cfg->arch.args_save_area_offset;
1453 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
1455 if (sig->ret->type != MONO_TYPE_VOID)
1457 if ((cinfo->ret.storage == ArgInIReg) &&
1458 (cfg->ret->opcode != OP_REGVAR))
1460 /* Save volatile arguments to the stack */
1461 alpha_stq(code, cinfo->ret.reg, cfg->ret->inst_basereg,
1462 cfg->ret->inst_offset);
1466 /* Keep this in sync with emit_load_volatile_arguments */
1467 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
1469 ArgInfo *ainfo = &cinfo->args [i];
1470 MonoInst *inst = cfg->args [i];
1473 switch(ainfo->storage)
1476 // We need to save all used a0-a5 params
1478 if (inst->opcode == OP_REGVAR)
1480 alpha_mov1(code, ainfo->reg, inst->dreg);
1481 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1482 ainfo->reg, inst->dreg);
1486 alpha_stq(code, ainfo->reg, inst->inst_basereg,
1489 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1490 ainfo->reg, inst->inst_offset);
1498 for(j=0; j<ainfo->nregs; j++)
1500 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1501 ainfo->reg + j, inst->inst_offset + (8*j));
1502 alpha_stq(code, (ainfo->reg+j), inst->inst_basereg,
1503 (inst->inst_offset + (8*j)));
1508 case ArgInDoubleReg:
1510 // We need to save all used af0-af5 params
1512 switch(cinfo->args[i].storage)
1515 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1516 alpha_sts(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1518 case ArgInDoubleReg:
1519 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1520 alpha_stt(code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1526 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1527 ainfo->reg, /*offset*/inst->inst_offset);
1534 offset = cfg->arch.reg_save_area_offset;
1537 for (i = 0; i < MONO_MAX_VREGS; ++i)
1538 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1539 (cfg->used_int_regs & (1 << i)) &&
1540 !( ALPHA_ARGS_REGS & (1 << i)) )
1542 alpha_stq(code, i, alpha_fp, offset);
1543 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1548 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1550 if (method->save_lmf)
1553 * The call might clobber argument registers, but they are already
1554 * saved to the stack/global regs.
1557 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
1558 (gpointer)"mono_get_lmf_addr");
1561 alpha_stq(code, alpha_r0, alpha_fp,
1562 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
1563 // Load "previous_lmf" member of MonoLMF struct
1564 alpha_ldq(code, alpha_r1, alpha_r0, 0);
1566 // Save it to MonoLMF struct
1567 alpha_stq(code, alpha_r1, alpha_fp,
1568 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
1571 alpha_lda(code, alpha_r1, alpha_fp, lmf_offset);
1572 alpha_stq(code, alpha_r1, alpha_r0, 0);
1577 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1578 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method,
1581 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1583 g_assert (cfg->code_len < cfg->code_size);
1585 return (gint8 *)code;
1588 /*========================= End of Function ========================*/
1590 /*------------------------------------------------------------------*/
1592 /* Name - mono_arch_flush_register_windows */
1598 /*------------------------------------------------------------------*/
1601 mono_arch_flush_register_windows (void)
1603 ALPHA_DEBUG("mono_arch_flush_register_windows");
1605 /*========================= End of Function ========================*/
1607 /*------------------------------------------------------------------*/
1609 /* Name - mono_arch_regalloc_cost */
1611 /* Function - Determine the cost, in the number of memory */
1612 /* references, of the action of allocating the var- */
1613 /* iable VMV into a register during global register */
1616 /* Returns - Cost */
1618 /*------------------------------------------------------------------*/
1621 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1623 MonoInst *ins = cfg->varinfo [vmv->idx];
1626 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1628 if (cfg->method->save_lmf)
1629 /* The register is already saved */
1630 /* substract 1 for the invisible store in the prolog */
1631 return (ins->opcode == OP_ARG) ? 1 : 0;
1634 return (ins->opcode == OP_ARG) ? 2 : 1;
1637 /*========================= End of Function ========================*/
1641 ** This method emits call sequience
1644 static unsigned int *
1645 emit_call(MonoCompile *cfg, unsigned int *code,
1646 guint32 patch_type, gconstpointer data)
1649 AlphaGotData ge_data;
1651 offset = (char *)code - (char *)cfg->native_code;
1653 ge_data.data.p = (void *)data;
1654 add_got_entry(cfg, GT_PTR, ge_data,
1655 offset, patch_type, data);
1657 // Load call address into PV
1658 alpha_ldq(code, alpha_pv, alpha_gp, 0);
1661 alpha_jsr(code, alpha_ra, alpha_pv, 0);
1663 offset = (char *)code - (char *)cfg->native_code;
1666 ALPHA_LOAD_GP(offset)
1667 alpha_ldah(code, alpha_gp, alpha_ra, 0);
1668 alpha_lda(code, alpha_gp, alpha_gp, 0);
1673 /*------------------------------------------------------------------*/
1675 /* Name - arch_get_argument_info */
1677 /* Function - Gathers information on parameters such as size, */
1678 /* alignment, and padding. arg_info should be large */
1679 /* enough to hold param_count + 1 entries. */
1681 /* Parameters - @csig - Method signature */
1682 /* @param_count - No. of parameters to consider */
1683 /* @arg_info - An array to store the result info */
1685 /* Returns - Size of the activation frame */
1687 /*------------------------------------------------------------------*/
1690 mono_arch_get_argument_info (MonoMethodSignature *csig,
1692 MonoJitArgumentInfo *arg_info)
1695 CallInfo *cinfo = get_call_info (NULL, csig, FALSE);
1696 guint32 args_size = cinfo->stack_usage;
1698 ALPHA_DEBUG("mono_arch_get_argument_info");
1700 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1703 arg_info [0].offset = 0;
1706 for (k = 0; k < param_count; k++)
1708 arg_info [k + 1].offset = ((k + csig->hasthis) * 8);
1712 // The size is checked only for valuetype in trace.c
1713 arg_info [k + 1].size = 8;
1721 /*------------------------------------------------------------------*/
1723 /* Name - mono_arch_emit_epilog */
1725 /* Function - Emit the instructions for a function epilog. */
1727 /*------------------------------------------------------------------*/
1730 mono_arch_emit_epilog (MonoCompile *cfg)
1732 MonoMethod *method = cfg->method;
1735 int max_epilog_size = 128;
1736 int stack_size = cfg->arch.stack_size;
1738 gint32 lmf_offset = cfg->arch.lmf_offset;
1740 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1742 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16))
1744 cfg->code_size *= 2;
1745 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1746 cfg->stat_code_reallocs++;
1749 code = (unsigned int *)(cfg->native_code + cfg->code_len);
1751 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
1752 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method,
1755 if (method->save_lmf)
1757 /* Restore previous lmf */
1758 alpha_ldq(code, alpha_at, alpha_fp,
1759 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
1760 alpha_ldq(code, alpha_ra, alpha_fp,
1761 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
1762 alpha_stq(code, alpha_at, alpha_ra, 0);
1766 alpha_mov1( code, alpha_fp, alpha_sp );
1768 // Restore saved regs
1769 offset = cfg->arch.reg_save_area_offset;
1771 for (i = 0; i < MONO_MAX_IREGS; ++i)
1772 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1773 (cfg->used_int_regs & (1 << i)) &&
1774 !( ALPHA_ARGS_REGS & (1 << i)) )
1776 alpha_ldq(code, i, alpha_sp, offset);
1777 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1782 /* restore fp, ra, sp */
1783 offset = cfg->arch.params_stack_size;
1785 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
1786 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
1787 alpha_lda( code, alpha_sp, alpha_sp, stack_size );
1790 alpha_ret( code, alpha_ra, 1 );
1792 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
1794 g_assert (cfg->code_len < cfg->code_size);
1797 /*========================= End of Function ========================*/
1799 /*------------------------------------------------------------------*/
1801 /* Name - mono_arch_emit_exceptions */
1803 /* Function - Emit the blocks to handle exception conditions. */
1805 /*------------------------------------------------------------------*/
1808 mono_arch_emit_exceptions (MonoCompile *cfg)
1810 MonoJumpInfo *patch_info;
1812 unsigned int *code, *got_start;
1813 unsigned long *corlib_exc_adr;
1814 MonoClass *exc_classes [16];
1815 guint8 *exc_throw_start [16], *exc_throw_end [16];
1816 guint32 code_size = 8; // Reserve space for address to mono_arch_throw_corlib_exception
1817 AlphaGotEntry *got_data;
1819 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1821 /* Compute needed space */
1822 for (patch_info = cfg->patch_info; patch_info;
1823 patch_info = patch_info->next)
1825 if (patch_info->type == MONO_PATCH_INFO_EXC)
1827 if (patch_info->type == MONO_PATCH_INFO_R8)
1828 code_size += 8 + 7; /* sizeof (double) + alignment */
1829 if (patch_info->type == MONO_PATCH_INFO_R4)
1830 code_size += 4 + 7; /* sizeof (float) + alignment */
1833 // Reserve space for GOT entries
1834 for (got_data = cfg->arch.got_data; got_data;
1835 got_data = got_data->next)
1837 // Reserve space for 8 byte const (for now)
1838 if (got_data->type != GT_LD_GTADDR)
1842 while (cfg->code_len + code_size > (cfg->code_size - 16))
1844 cfg->code_size *= 2;
1845 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1846 cfg->stat_code_reallocs++;
1849 code = (unsigned int *)((char *)cfg->native_code + cfg->code_len);
1851 // Set code alignment
1852 if (((unsigned long)code) % 8)
1857 /* Add code to store conts and modify patch into to store offset in got */
1858 for (got_data = cfg->arch.got_data; got_data;
1859 got_data = got_data->next)
1861 unsigned long data = got_data->value.data.l;
1862 MonoJumpInfo *got_ref = got_data->got_patch_info;
1864 // Modify loading of GP
1865 if (got_data->type == GT_LD_GTADDR)
1867 short high_off, low_off;
1868 unsigned int *ldgp_code =
1869 (unsigned int *)(cfg->native_code + got_data->value.data.l);
1870 unsigned int got_off = (char *)got_start - (char *)ldgp_code;
1872 high_off = got_off / 0x10000;
1873 low_off = got_off % 0x10000;
1877 // Set offset from current point to GOT array
1878 // modify the following code sequence
1879 // ldah gp, 0(pv) or ldah gp, 0(ra)
1881 *ldgp_code = (*ldgp_code | (high_off & 0xFFFF));
1883 *ldgp_code = (*ldgp_code | (low_off & 0xFFFF));
1888 patch_info = got_data->patch_info;
1890 // Check code alignment
1891 if (((unsigned long)code) % 8)
1894 got_ref->data.offset = ((char *)code - (char *)got_start);
1897 patch_info->ip.i = ((char *)code - (char *)cfg->native_code);
1899 *code = (unsigned int)(data & 0xFFFFFFFF);
1901 *code = (unsigned int)((data >> 32) & 0xFFFFFFFF);
1906 corlib_exc_adr = (unsigned long *)code;
1908 /* add code to raise exceptions */
1910 for (patch_info = cfg->patch_info; patch_info;
1911 patch_info = patch_info->next)
1913 switch (patch_info->type)
1915 case MONO_PATCH_INFO_EXC:
1917 MonoClass *exc_class;
1918 unsigned int *buf, *buf2;
1923 // Add patch info to call mono_arch_throw_corlib_exception
1924 // method to raise corlib exception
1925 // Will be added at the begining of the patch info list
1926 mono_add_patch_info(cfg,
1927 ((char *)code - (char *)cfg->native_code),
1928 MONO_PATCH_INFO_INTERNAL_METHOD,
1929 "mono_arch_throw_corlib_exception");
1931 // Skip longword before starting the code
1936 exc_class = mono_class_from_name (mono_defaults.corlib,
1937 "System", patch_info->data.name);
1939 g_assert (exc_class);
1940 throw_ip = patch_info->ip.i;
1942 //x86_breakpoint (code);
1943 /* Find a throw sequence for the same exception class */
1944 for (i = 0; i < nthrows; ++i)
1945 if (exc_classes [i] == exc_class)
1952 // Patch original branch (patch info) to jump here
1953 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1954 patch_info->data.target =
1955 (char *)code - (char *)cfg->native_code;
1957 alpha_lda(code, alpha_a1, alpha_zero,
1958 -((short)((((char *)exc_throw_end[i] -
1959 (char *)cfg->native_code)) - throw_ip) - 4) );
1961 br_offset = ((char *)exc_throw_start[i] - (char *)code - 4)/4;
1963 alpha_bsr(code, alpha_zero, br_offset);
1969 // Save exception token type as first 32bit word for new
1970 // exception handling jump code
1971 *code = exc_class->type_token;
1974 // Patch original branch (patch info) to jump here
1975 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
1976 patch_info->data.target =
1977 (char *)code - (char *)cfg->native_code;
1980 alpha_lda(code, alpha_a1, alpha_zero, 0);
1984 exc_classes [nthrows] = exc_class;
1985 exc_throw_start [nthrows] = code;
1988 // Load exception token
1989 alpha_ldl(code, alpha_a0, alpha_gp,
1990 ((char *)buf - (char *)got_start /*cfg->native_code*/));
1991 // Load corlib exception raiser code address
1992 alpha_ldq(code, alpha_pv, alpha_gp,
1993 ((char *)corlib_exc_adr -
1994 (char *)got_start /*cfg->native_code*/));
1996 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
1997 //patch_info->data.name = "mono_arch_throw_corlib_exception";
1998 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
1999 //patch_info->type = MONO_PATCH_INFO_NONE;
2000 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
2002 if (cfg->compile_aot)
2004 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
2005 //amd64_call_reg (code, GP_SCRATCH_REG);
2007 /* The callee is in memory allocated using
2009 alpha_jsr(code, alpha_ra, alpha_pv, 0);
2012 alpha_lda(buf2, alpha_a1, alpha_zero,
2013 -((short)(((char *)code - (char *)cfg->native_code) -
2018 exc_throw_end [nthrows] = code;
2030 /* Handle relocations with RIP relative addressing */
2031 for (patch_info = cfg->patch_info; patch_info;
2032 patch_info = patch_info->next)
2034 gboolean remove = FALSE;
2036 switch (patch_info->type)
2038 case MONO_PATCH_INFO_R8:
2042 code = (guint8*)ALIGN_TO (code, 8);
2044 pos = cfg->native_code + patch_info->ip.i;
2046 *(double*)code = *(double*)patch_info->data.target;
2049 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2051 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2057 case MONO_PATCH_INFO_R4:
2061 code = (guint8*)ALIGN_TO (code, 8);
2063 pos = cfg->native_code + patch_info->ip.i;
2065 *(float*)code = *(float*)patch_info->data.target;
2068 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2070 *(guint32*)(pos + 3) = (guint8*)code - pos - 7;
2082 if (patch_info == cfg->patch_info)
2083 cfg->patch_info = patch_info->next;
2088 for (tmp = cfg->patch_info; tmp->next != patch_info;
2091 tmp->next = patch_info->next;
2096 cfg->code_len = (char *)code - (char *)cfg->native_code;
2098 g_assert (cfg->code_len < cfg->code_size);
2102 /*========================= End of Function ========================*/
2104 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2105 offset = ((char *)code - \
2106 (char *)cfg->native_code); \
2107 if (Tins->inst_true_bb->native_offset) \
2109 long br_offset = (char *)cfg->native_code + \
2110 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2111 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2112 Tins->inst_target_bb->native_offset, \
2113 cfg->native_code + \
2114 Tins->inst_true_bb->native_offset); \
2115 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2119 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2120 offset, Tins->inst_target_bb); \
2121 mono_add_patch_info (cfg, offset, \
2122 MONO_PATCH_INFO_BB, \
2123 Tins->inst_true_bb); \
2124 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2128 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2131 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2136 mono_add_patch_info (cfg, \
2138 (char *)cfg->native_code), \
2139 MONO_PATCH_INFO_EXC, EXC_NAME); \
2140 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2144 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2149 /*------------------------------------------------------------------*/
2151 /* Name - mono_arch_output_basic_block */
2153 /* Function - Perform the "real" work of emitting instructions */
2154 /* that will do the work of in the basic block. */
2156 /*------------------------------------------------------------------*/
2159 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2164 unsigned int *code = (unsigned int *)(cfg->native_code + cfg->code_len);
2165 MonoInst *last_ins = NULL;
2166 guint last_offset = 0;
2169 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2171 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2172 bb->block_num, bb, bb->native_offset);
2174 cpos = bb->max_offset;
2176 offset = ((char *)code) - ((char *)cfg->native_code);
2178 mono_debug_open_block (cfg, bb, offset);
2180 MONO_BB_FOR_EACH_INS (bb, ins) {
2181 offset = ((char *)code) - ((char *)cfg->native_code);
2183 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2185 if (offset > (cfg->code_size - max_len - 16))
2187 cfg->code_size *= 2;
2188 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2189 code = (unsigned int *)(cfg->native_code + offset);
2190 cfg->stat_code_reallocs++;
2193 mono_debug_record_line_number (cfg, ins, offset);
2195 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2196 mono_inst_name(ins->opcode));
2198 switch (ins->opcode)
2200 case OP_RELAXED_NOP:
2203 // Shift 64 bit value right
2204 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2205 ins->dreg, ins->sreg1, ins->sreg2);
2206 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2210 // Shift 64 bit value right
2211 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2212 ins->dreg, ins->sreg1, ins->sreg2);
2213 alpha_srl(code, ins->sreg1, ins->sreg2, ins->dreg);
2217 // Shift 64 bit value right by constant
2218 g_assert(alpha_is_imm(ins->inst_imm));
2219 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2220 ins->dreg, ins->sreg1, ins->inst_imm);
2221 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2225 // Shift 32 bit value left
2226 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2227 ins->dreg, ins->sreg1, ins->sreg2);
2228 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2229 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2233 // Shift 32 bit value left by constant
2234 g_assert(alpha_is_imm(ins->inst_imm));
2235 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2236 ins->dreg, ins->sreg1, ins->inst_imm);
2237 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2238 alpha_addl_(code, ins->dreg, 0, ins->dreg);
2242 g_assert(alpha_is_imm(ins->inst_imm));
2243 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2244 ins->dreg, ins->sreg1, ins->inst_imm);
2245 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2249 g_assert(alpha_is_imm(ins->inst_imm));
2250 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2251 ins->dreg, ins->sreg1, ins->inst_imm);
2252 alpha_sll_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2257 // Shift 32 bit value left
2258 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2259 ins->dreg, ins->sreg1, ins->sreg2);
2260 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2264 // Shift 64 bit value left
2265 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2266 ins->dreg, ins->sreg1, ins->sreg2);
2267 alpha_sll(code, ins->sreg1, ins->sreg2, ins->dreg);
2272 // Shift 32 bit value right
2273 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2274 ins->dreg, ins->sreg1, ins->sreg2);
2275 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2276 alpha_sra(code, ins->sreg1, ins->sreg2, ins->dreg);
2280 // Shift 32 bit value rigth by constant
2281 g_assert(alpha_is_imm(ins->inst_imm));
2282 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2283 ins->dreg, ins->sreg1, ins->inst_imm);
2284 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2285 alpha_sra_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2289 // Shift 32 bit unsigned value right
2290 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2291 ins->dreg, ins->sreg1, ins->sreg2);
2292 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2293 alpha_srl(code, alpha_at /*ins->dreg*/, ins->sreg2, ins->dreg);
2296 case OP_ISHR_UN_IMM:
2297 // Shift 32 bit unassigned value rigth by constant
2298 g_assert(alpha_is_imm(ins->inst_imm));
2299 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2300 ins->dreg, ins->sreg1, ins->inst_imm);
2301 alpha_zap_(code, ins->sreg1, 0xF0, alpha_at /*ins->dreg*/);
2302 alpha_srl_(code, alpha_at /*ins->dreg*/, ins->inst_imm, ins->dreg);
2305 case OP_LSHR_UN_IMM:
2306 // Shift 64 bit unassigned value rigth by constant
2307 g_assert(alpha_is_imm(ins->inst_imm));
2308 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2309 ins->dreg, ins->sreg1, ins->inst_imm);
2310 alpha_srl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2314 // Sum two 64 bits regs
2315 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2316 ins->dreg, ins->sreg1, ins->sreg2);
2317 alpha_addq(code, ins->sreg1, ins->sreg2, ins->dreg);
2321 // Subtract two 64 bit regs
2322 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2323 ins->dreg, ins->sreg1, ins->sreg2);
2324 alpha_subq(code, ins->sreg1, ins->sreg2, ins->dreg);
2328 // Add imm value to 64 bits int
2329 g_assert(alpha_is_imm(ins->inst_imm));
2330 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2331 ins->dreg, ins->sreg1, ins->inst_imm);
2332 alpha_addq_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2336 // Add two 32 bit ints
2337 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2338 ins->dreg, ins->sreg1, ins->sreg2);
2339 alpha_addl(code, ins->sreg1, ins->sreg2, ins->dreg);
2343 // Add two 32 bit ints with overflow detection
2344 // Use AT to hold flag of signed overflow
2345 // Use t12(PV) to hold unsigned overflow
2346 // Use RA to hold intermediate result
2347 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2348 ins->dreg, ins->sreg1, ins->sreg2);
2349 alpha_addl(code, ins->sreg1, ins->sreg2, alpha_ra);
2350 alpha_ble(code, ins->sreg2, 2);
2352 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2353 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2354 alpha_br(code, alpha_zero, 1);
2356 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2357 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2359 /* res <u sreg1 => unsigned overflow */
2360 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2362 alpha_mov1(code, alpha_ra, ins->dreg);
2366 // Add two 64 bit ints with overflow detection
2367 // Use AT to hold flag of signed overflow
2368 // Use t12(PV) to hold unsigned overflow
2369 // Use RA to hold intermediate result
2370 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2371 ins->dreg, ins->sreg1, ins->sreg2);
2372 alpha_addq(code, ins->sreg1, ins->sreg2, alpha_ra);
2373 alpha_ble(code, ins->sreg2, 2);
2375 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2376 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2377 alpha_br(code, alpha_zero, 1);
2379 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2380 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2382 /* res <u sreg1 => unsigned overflow */
2383 alpha_cmpult(code, alpha_ra, ins->sreg1, alpha_pv);
2385 alpha_mov1(code, alpha_ra, ins->dreg);
2389 // Add imm value to 32 bits int
2390 g_assert(alpha_is_imm(ins->inst_imm));
2391 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2392 ins->dreg, ins->sreg1, ins->inst_imm);
2393 alpha_addl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2397 // Substract to 32 bit ints
2398 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2399 ins->dreg, ins->sreg1, ins->sreg2);
2400 alpha_subl(code, ins->sreg1, ins->sreg2, ins->dreg);
2404 // Sub imm value from 32 bits int
2405 g_assert(alpha_is_imm(ins->inst_imm));
2406 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2407 ins->dreg, ins->sreg1, ins->inst_imm);
2408 alpha_subl_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2412 // Sub to 32 bit ints with overflow detection
2413 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2414 ins->dreg, ins->sreg1, ins->sreg2);
2415 alpha_subl(code, ins->sreg1, ins->sreg2, alpha_ra);
2416 alpha_ble(code, ins->sreg2, 2);
2418 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2419 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2420 alpha_br(code, alpha_zero, 1);
2422 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2423 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2425 /* sreg1 <u sreg2 => unsigned overflow */
2426 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2428 alpha_mov1(code, alpha_ra, ins->dreg);
2432 // Sub to 64 bit ints with overflow detection
2433 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2434 ins->dreg, ins->sreg1, ins->sreg2);
2436 alpha_subq(code, ins->sreg1, ins->sreg2, alpha_ra);
2437 alpha_ble(code, ins->sreg2, 2);
2439 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2440 alpha_cmplt(code, ins->sreg1, alpha_ra, alpha_at);
2441 alpha_br(code, alpha_zero, 1);
2443 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2444 alpha_cmplt(code, alpha_ra, ins->sreg1, alpha_at);
2446 /* sreg1 <u sreg2 => unsigned overflow */
2447 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_pv);
2449 alpha_mov1(code, alpha_ra, ins->dreg);
2454 // AND to 32 bit ints
2455 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2456 ins->dreg, ins->sreg1, ins->sreg2);
2457 alpha_and(code, ins->sreg1, ins->sreg2, ins->dreg);
2462 // AND imm value with 32 bit int
2463 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2464 ins->dreg, ins->sreg1, ins->inst_imm);
2466 g_assert(alpha_is_imm(ins->inst_imm));
2467 alpha_and_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2473 // OR two 32/64 bit ints
2474 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2475 ins->dreg, ins->sreg1, ins->sreg2);
2476 alpha_bis(code, ins->sreg1, ins->sreg2, ins->dreg);
2480 // OR imm value with 32 bit int
2481 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2482 ins->dreg, ins->sreg1, ins->inst_imm);
2484 g_assert(alpha_is_imm(ins->inst_imm));
2485 alpha_bis_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2491 // XOR two 32/64 bit ints
2492 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2493 ins->dreg, ins->sreg1, ins->sreg2);
2494 alpha_xor(code, ins->sreg1, ins->sreg2, ins->dreg);
2498 // XOR imm value with 32 bit int
2499 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2500 ins->dreg, ins->sreg1, ins->inst_imm);
2502 g_assert(alpha_is_imm(ins->inst_imm));
2503 alpha_xor_(code, ins->sreg1, ins->inst_imm, ins->dreg);
2509 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2510 ins->dreg, ins->sreg1);
2511 alpha_subl(code, alpha_zero, ins->sreg1, ins->dreg);
2516 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2517 ins->dreg, ins->sreg1);
2518 alpha_subq(code, alpha_zero, ins->sreg1, ins->dreg);
2523 // NOT 32/64 bit reg
2524 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2525 ins->dreg, ins->sreg1);
2526 alpha_not(code, ins->sreg1, ins->dreg);
2534 case OP_IMUL_OVF_UN:
2537 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",
2538 ins->dreg, ins->sreg1, ins->sreg2);
2542 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2543 ins->dreg, ins->sreg1, ins->sreg2);
2544 alpha_mull(code, ins->sreg1, ins->sreg2, ins->dreg);
2548 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2549 ins->dreg, ins->sreg1, ins->inst_imm);
2553 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2555 alpha_ldl(code, alpha_at, ins->sreg1, 0);
2559 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2560 ins->dreg, ins->sreg1);
2561 alpha_sll_(code, ins->sreg1, 56, ins->dreg);
2562 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2566 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2567 ins->dreg, ins->sreg1);
2568 alpha_sll_(code, ins->sreg1, 48, ins->dreg);
2569 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2573 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2574 ins->dreg, ins->sreg1);
2575 alpha_sll_(code, ins->sreg1, 32, ins->dreg);
2576 alpha_sra_(code, ins->dreg, 32, ins->dreg);
2580 // Actually ICONST is 32 bits long
2581 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2582 ins->dreg, ins->inst_c0);
2585 if (ins->inst_c0 == 0)
2587 alpha_clr(code, ins->dreg);
2591 // if -32768 < const <= 32767
2592 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2594 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2595 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2596 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2600 int lo = (char *)code - (char *)cfg->native_code;
2601 AlphaGotData ge_data;
2603 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2604 ge_data.data.l = ins->inst_c0;
2606 add_got_entry(cfg, GT_LONG, ge_data,
2607 lo, MONO_PATCH_INFO_NONE, 0);
2608 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2610 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2611 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2619 // To load 64 bit values we will have to use ldah/lda combination
2620 // and temporary register. As temporary register use r28
2621 // Divide 64 bit value in two parts and load upper 32 bits into
2622 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2623 // dreg from temp reg
2624 // the 32 bit value could be loaded with ldah/lda
2625 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2626 ins->dreg, ins->inst_c0);
2629 if (ins->inst_c0 == 0)
2631 alpha_clr(code, ins->dreg);
2635 // if -32768 < const <= 32767
2636 if (ins->inst_c0 > -32768 && ins->inst_c0 <= 32767)
2637 alpha_lda( code, ins->dreg, alpha_zero, ins->inst_c0);
2640 AlphaGotData ge_data;
2642 lo = (char *)code - (char *)cfg->native_code;
2644 ge_data.data.l = ins->inst_c0;
2646 add_got_entry(cfg, GT_LONG, ge_data,
2647 lo, MONO_PATCH_INFO_NONE, 0);
2648 alpha_ldq(code, ins->dreg, alpha_gp, 0);
2655 double d = *(double *)ins->inst_p0;
2656 AlphaGotData ge_data;
2658 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2662 add_got_entry(cfg, GT_DOUBLE, ge_data,
2663 (char *)code - (char *)cfg->native_code,
2664 MONO_PATCH_INFO_NONE, 0);
2665 alpha_ldt(code, ins->dreg, alpha_gp, 0);
2672 float d = *(float *)ins->inst_p0;
2673 AlphaGotData ge_data;
2675 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2679 add_got_entry(cfg, GT_FLOAT, ge_data,
2680 (char *)code - (char *)cfg->native_code,
2681 MONO_PATCH_INFO_NONE, 0);
2682 alpha_lds(code, ins->dreg, alpha_gp, 0);
2687 case OP_LOADU4_MEMBASE:
2688 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2689 ins->dreg, ins->inst_basereg, ins->inst_offset);
2691 alpha_ldl(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2692 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2695 case OP_LOADU1_MEMBASE:
2696 // Load unassigned byte from REGOFFSET
2697 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2698 ins->dreg, ins->inst_basereg, ins->inst_offset);
2700 alpha_ldbu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2703 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2705 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2706 alpha_extbl(code, alpha_r25, alpha_at, ins->dreg);
2710 case OP_LOADU2_MEMBASE:
2711 // Load unassigned word from REGOFFSET
2712 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2713 ins->dreg, ins->inst_basereg, ins->inst_offset);
2716 alpha_ldwu(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2719 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2721 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2722 (ins->inst_offset+1));
2723 alpha_lda(code, alpha_at, ins->inst_basereg, ins->inst_offset);
2724 alpha_extwl(code, alpha_r24, alpha_at, ins->dreg);
2725 alpha_extwh(code, alpha_r25, alpha_at, alpha_r25);
2726 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2730 case OP_LOAD_MEMBASE:
2731 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2732 ins->dreg, ins->inst_basereg, ins->inst_offset);
2733 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2736 case OP_LOADI8_MEMBASE:
2737 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2738 ins->dreg, ins->inst_basereg, ins->inst_offset);
2739 alpha_ldq( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2742 case OP_LOADI4_MEMBASE:
2743 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2744 ins->dreg, ins->inst_basereg, ins->inst_offset);
2745 alpha_ldl( code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2748 case OP_LOADI1_MEMBASE:
2749 // Load sign-extended byte from REGOFFSET
2750 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2751 ins->dreg, ins->inst_basereg, ins->inst_offset);
2754 alpha_ldbu(code, ins->dreg, ins->inst_basereg,
2756 alpha_sextb(code, ins->dreg, ins->dreg);
2760 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2762 alpha_lda(code, alpha_at, ins->inst_basereg,
2763 (ins->inst_offset+1));
2764 alpha_extqh(code, alpha_r25, alpha_at, ins->dreg);
2765 alpha_sra_(code, ins->dreg, 56, ins->dreg);
2769 case OP_LOADI2_MEMBASE:
2770 // Load sign-extended word from REGOFFSET
2771 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2772 ins->dreg, ins->inst_basereg, ins->inst_offset);
2775 alpha_ldwu(code, ins->dreg, ins->inst_basereg,
2777 alpha_sextw(code, ins->dreg, ins->dreg);
2781 alpha_ldq_u(code, alpha_r24, ins->inst_basereg,
2783 alpha_ldq_u(code, alpha_r25, ins->inst_basereg,
2784 (ins->inst_offset+1));
2785 alpha_lda(code, alpha_at, ins->inst_basereg,
2786 (ins->inst_offset+2));
2787 alpha_extql(code, alpha_r24, alpha_at, ins->dreg);
2788 alpha_extqh(code, alpha_r25, alpha_at, alpha_r25);
2789 alpha_bis(code, alpha_r25, ins->dreg, ins->dreg);
2790 alpha_sra_(code, ins->dreg, 48, ins->dreg);
2794 case OP_STOREI1_MEMBASE_IMM:
2795 // Store signed byte at REGOFFSET
2796 // Valid only for storing 0
2797 // storei1_membase_reg will do the rest
2799 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2800 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2801 g_assert(ins->inst_imm == 0);
2804 alpha_stb(code, alpha_zero, ins->inst_destbasereg,
2807 g_assert_not_reached();
2811 case OP_STOREI1_MEMBASE_REG:
2812 // Store byte at REGOFFSET
2813 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2814 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2817 alpha_stb(code, ins->sreg1, ins->inst_destbasereg,
2822 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2824 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2826 alpha_insbl(code, ins->sreg1, alpha_at, alpha_r24);
2827 alpha_mskbl(code, alpha_r25, alpha_at, alpha_r25);
2828 alpha_bis(code, alpha_r25, alpha_r24, alpha_r25);
2829 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2834 case OP_STOREI2_MEMBASE_IMM:
2835 // Store signed word at REGOFFSET
2836 // Now work only for storing 0
2837 // For now storei2_membase_reg will do the work
2839 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2840 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2842 g_assert(ins->inst_imm == 0);
2845 alpha_stw(code, alpha_zero, ins->inst_destbasereg,
2848 g_assert_not_reached();
2852 case OP_STOREI2_MEMBASE_REG:
2853 // Store signed word from reg to REGOFFSET
2854 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2855 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2859 alpha_stw(code, ins->sreg1, ins->inst_destbasereg,
2864 alpha_lda(code, alpha_at, ins->inst_destbasereg,
2866 alpha_ldq_u(code, alpha_r25, ins->inst_destbasereg,
2867 (ins->inst_offset+1));
2868 alpha_ldq_u(code, alpha_r24, ins->inst_destbasereg,
2870 alpha_inswh(code, ins->sreg1, alpha_at, alpha_r23);
2871 alpha_inswl(code, ins->sreg1, alpha_at, alpha_r22);
2872 alpha_mskwh(code, alpha_r25, alpha_at, alpha_r25);
2873 alpha_mskwl(code, alpha_r24, alpha_at, alpha_r24);
2874 alpha_bis(code, alpha_r25, alpha_r23, alpha_r25);
2875 alpha_bis(code, alpha_r24, alpha_r22, alpha_r24);
2876 alpha_stq_u(code, alpha_r25, ins->inst_destbasereg,
2877 (ins->inst_offset+1));
2878 alpha_stq_u(code, alpha_r24, ins->inst_destbasereg,
2884 case OP_STOREI4_MEMBASE_IMM:
2885 // We will get here only with ins->inst_imm = 0
2886 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2887 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2889 g_assert(ins->inst_imm == 0);
2891 alpha_stl(code, alpha_zero,
2892 ins->inst_destbasereg, ins->inst_offset);
2895 case OP_STORER4_MEMBASE_REG:
2896 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2897 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2898 alpha_sts(code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2901 case OP_STORER8_MEMBASE_REG:
2902 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2903 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2904 alpha_stt(code, ins->sreg1, ins->inst_destbasereg,
2908 case OP_LOADR4_MEMBASE:
2909 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2910 ins->dreg, ins->inst_basereg, ins->inst_offset);
2911 alpha_lds(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2914 case OP_LOADR8_MEMBASE:
2915 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2916 ins->dreg, ins->inst_basereg, ins->inst_offset);
2917 alpha_ldt(code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2921 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2922 ins->sreg1, ins->dreg);
2923 alpha_cpys(code, ins->sreg1, ins->sreg1, ins->dreg);
2927 // Later check different rounding and exc modes
2928 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2929 ins->sreg1, ins->sreg2, ins->dreg);
2930 alpha_addt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2935 // Later check different rounding and exc modes
2936 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2937 ins->sreg1, ins->sreg2, ins->dreg);
2938 alpha_subt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
2943 // Later check different rounding and exc modes
2944 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2945 ins->sreg1, ins->sreg2, ins->dreg);
2946 alpha_mult(code, ins->sreg1, ins->sreg2, ins->dreg);
2950 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2951 ins->sreg1, ins->dreg);
2952 alpha_cpysn(code, ins->sreg1, ins->sreg1, ins->dreg);
2955 case OP_ALPHA_TRAPB:
2956 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2961 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2962 ins->sreg1, ins->dreg);
2963 alpha_cpys(code, alpha_f31, ins->sreg1, ins->dreg);
2966 case OP_STORE_MEMBASE_IMM:
2967 case OP_STOREI8_MEMBASE_IMM:
2968 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2969 ins->inst_imm, ins->inst_destbasereg, ins->inst_offset);
2970 g_assert(ins->inst_imm == 0);
2972 alpha_stq(code, alpha_zero,
2973 ins->inst_destbasereg, ins->inst_offset);
2976 case OP_STORE_MEMBASE_REG:
2977 case OP_STOREI8_MEMBASE_REG:
2978 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2979 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2980 alpha_stq( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2983 case OP_STOREI4_MEMBASE_REG:
2984 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2985 ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2986 alpha_stl( code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2989 case OP_ICOMPARE_IMM:
2990 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2991 ins->sreg1, ins->dreg, ins->inst_imm);
2993 g_assert_not_reached();
2997 case OP_COMPARE_IMM:
2998 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
2999 ins->sreg1, ins->dreg, ins->inst_imm);
3001 g_assert_not_reached();
3005 case OP_COMPARE: // compare two 32 bit regs
3006 case OP_LCOMPARE: // compare two 64 bit regs
3007 case OP_FCOMPARE: // compare two floats
3008 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3009 ins->sreg1, ins->sreg2, ins->dreg);
3011 g_assert_not_reached();
3015 case OP_ALPHA_CMPT_UN:
3016 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3017 ins->sreg1, ins->sreg2, ins->dreg);
3018 alpha_cmptun(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3021 case OP_ALPHA_CMPT_UN_SU:
3022 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3023 ins->sreg1, ins->sreg2, ins->dreg);
3024 alpha_cmptun_su(code, ins->sreg1, ins->sreg2, (alpha_at+1));
3027 case OP_ALPHA_CMPT_EQ:
3028 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3029 ins->sreg1, ins->sreg2, ins->dreg);
3030 alpha_cmpteq(code, ins->sreg1, ins->sreg2, alpha_at);
3033 case OP_ALPHA_CMPT_EQ_SU:
3034 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3035 ins->sreg1, ins->sreg2, ins->dreg);
3036 alpha_cmpteq_su(code, ins->sreg1, ins->sreg2, alpha_at);
3040 case OP_ALPHA_CMPT_LT:
3041 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3042 ins->sreg1, ins->sreg2, ins->dreg);
3043 alpha_cmptlt(code, ins->sreg1, ins->sreg2, alpha_at);
3046 case OP_ALPHA_CMPT_LT_SU:
3047 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3048 ins->sreg1, ins->sreg2, ins->dreg);
3049 alpha_cmptlt_su(code, ins->sreg1, ins->sreg2, alpha_at);
3052 case OP_ALPHA_CMPT_LE:
3053 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3054 ins->sreg1, ins->sreg2, ins->dreg);
3055 alpha_cmptle(code, ins->sreg1, ins->sreg2, alpha_at);
3058 case OP_ALPHA_CMPT_LE_SU:
3059 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3060 ins->sreg1, ins->sreg2, ins->dreg);
3061 alpha_cmptle_su(code, ins->sreg1, ins->sreg2, alpha_at);
3064 case OP_ALPHA_CMP_EQ:
3065 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3066 ins->sreg1, ins->sreg2, ins->dreg);
3067 alpha_cmpeq(code, ins->sreg1, ins->sreg2, alpha_at);
3070 case OP_ALPHA_CMP_IMM_EQ:
3071 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3072 ins->sreg1, ins->inst_imm, ins->dreg);
3073 alpha_cmpeq_(code, ins->sreg1, ins->inst_imm, alpha_at);
3076 case OP_ALPHA_CMP_IMM_ULE:
3077 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%d\n",
3078 ins->sreg1, ins->inst_imm, ins->dreg);
3079 alpha_cmpule_(code, ins->sreg1, ins->inst_imm, alpha_at);
3082 case OP_ALPHA_CMP_ULT:
3083 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3084 ins->sreg1, ins->sreg2, ins->dreg);
3085 alpha_cmpult(code, ins->sreg1, ins->sreg2, alpha_at);
3088 case OP_ALPHA_CMP_IMM_ULT:
3089 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3090 ins->sreg1, ins->inst_imm, ins->dreg);
3091 alpha_cmpult_(code, ins->sreg1, ins->inst_imm, alpha_at);
3094 case OP_ALPHA_CMP_LE:
3095 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3096 ins->sreg1, ins->sreg2, ins->dreg);
3097 alpha_cmple(code, ins->sreg1, ins->sreg2, alpha_at);
3100 case OP_ALPHA_CMP_ULE:
3101 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3102 ins->sreg1, ins->sreg2, ins->dreg);
3103 alpha_cmpule(code, ins->sreg1, ins->sreg2, alpha_at);
3107 case OP_ALPHA_CMP_IMM_LE:
3108 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%d\n",
3109 ins->sreg1, ins->inst_imm, ins->dreg);
3110 alpha_cmple_(code, ins->sreg1, ins->inst_imm, alpha_at);
3113 case OP_ALPHA_CMP_LT:
3114 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3115 ins->sreg1, ins->sreg2, ins->dreg);
3116 alpha_cmplt(code, ins->sreg1, ins->sreg2, alpha_at);
3119 case OP_ALPHA_CMP_IMM_LT:
3120 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3121 ins->sreg1, ins->inst_imm, ins->dreg);
3122 alpha_cmplt_(code, ins->sreg1, ins->inst_imm, alpha_at);
3125 case OP_COND_EXC_GT:
3126 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3127 (char *)ins->inst_p1);
3129 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3132 case OP_COND_EXC_GT_UN:
3133 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3134 (char *)ins->inst_p1);
3136 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3139 case OP_COND_EXC_LT:
3140 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3141 (char *)ins->inst_p1);
3143 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3146 case OP_COND_EXC_LT_UN:
3147 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3148 (char *)ins->inst_p1);
3150 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3154 case OP_COND_EXC_LE_UN:
3155 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3156 (char *)ins->inst_p1);
3157 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3160 case OP_COND_EXC_NE_UN:
3161 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3162 (char *)ins->inst_p1);
3163 EMIT_COND_EXC_BRANCH(beq, alpha_at, ins->inst_p1);
3166 case OP_COND_EXC_EQ:
3167 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3168 (char *)ins->inst_p1);
3169 EMIT_COND_EXC_BRANCH(bne, alpha_at, ins->inst_p1);
3172 case OP_COND_EXC_IOV:
3173 case OP_COND_EXC_OV:
3174 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3177 case OP_COND_EXC_IC:
3179 EMIT_COND_EXC_BRANCH(bne, alpha_pv, "OverflowException");
3182 case CEE_CONV_OVF_U4:
3183 // Convert unsigned 32 bit value to 64 bit reg
3185 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3186 ins->sreg1, ins->dreg);
3187 alpha_cmplt_(code, ins->sreg1, 0, alpha_at);
3188 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3189 alpha_mov1(code, ins->sreg1, ins->dreg);
3192 case CEE_CONV_OVF_I4_UN:
3193 // Convert unsigned 32 bit value to 64 bit reg
3195 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3196 ins->sreg1, ins->dreg);
3197 alpha_zap_(code, ins->sreg1, 0x0F, alpha_at);
3199 EMIT_COND_EXC_BRANCH(bne, alpha_at, "OverflowException");
3200 alpha_mov1(code, ins->sreg1, ins->dreg);
3204 // Move I1 (byte) to dreg(64 bits) and sign extend it
3206 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3207 ins->sreg1, ins->dreg);
3209 alpha_sextb(code, ins->sreg1, ins->dreg);
3212 alpha_sll_(code, ins->sreg1, 24, alpha_at);
3213 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3214 alpha_sra_(code, ins->dreg, 24, ins->dreg);
3219 // Move I2 (word) to dreg(64 bits) and sign extend it
3220 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3221 ins->sreg1, ins->dreg);
3223 alpha_sextw(code, ins->sreg1, ins->dreg);
3226 alpha_sll_(code, ins->sreg1, 16, alpha_at);
3227 alpha_addl(code, alpha_at, alpha_zero, ins->dreg);
3228 alpha_sra_(code, ins->dreg, 16, ins->dreg);
3233 // Move I4 (long) to dreg(64 bits) and sign extend it
3234 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3235 ins->sreg1, ins->dreg);
3236 alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3241 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3242 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3243 ins->sreg1, ins->dreg);
3244 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3245 alpha_mov1(code, ins->sreg1, ins->dreg);
3249 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3250 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3251 ins->sreg1, ins->dreg);
3252 alpha_extbl_(code, ins->sreg1, 0, ins->dreg);
3256 // Move U2 (word) to dreg(64 bits) don't sign extend it
3257 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3258 ins->sreg1, ins->dreg);
3259 alpha_extwl_(code, ins->sreg1, 0, ins->dreg);
3263 // Move U4 (long) to dreg(64 bits) don't sign extend it
3264 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3265 ins->sreg1, ins->dreg);
3266 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3271 // Move U4 (long) to dreg(64 bits) don't sign extend it
3272 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3273 ins->sreg1, ins->dreg);
3274 alpha_extll_(code, ins->sreg1, 0, ins->dreg);
3277 case OP_FCONV_TO_I4:
3278 case OP_FCONV_TO_I8:
3279 // Move float to 32 bit reg
3280 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3281 ins->sreg1, ins->dreg);
3282 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3283 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3284 alpha_lda(code, alpha_sp, alpha_sp, -8);
3285 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3286 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3287 alpha_lda(code, alpha_sp, alpha_sp, 8);
3290 case OP_FCONV_TO_I2:
3291 // Move float to 16 bit reg
3292 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3293 ins->sreg1, ins->dreg);
3294 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3295 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3296 alpha_lda(code, alpha_sp, alpha_sp, -8);
3297 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3298 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3299 alpha_lda(code, alpha_sp, alpha_sp, 8);
3300 alpha_sll_(code, ins->dreg, 48, ins->dreg);
3301 alpha_sra_(code, ins->dreg, 48, ins->dreg);
3304 case OP_FCONV_TO_U2:
3305 // Move float to 16 bit reg as unsigned
3306 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3307 ins->sreg1, ins->dreg);
3308 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3309 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3310 alpha_lda(code, alpha_sp, alpha_sp, -8);
3311 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3312 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3313 alpha_lda(code, alpha_sp, alpha_sp, 8);
3314 alpha_zapnot_(code, ins->dreg, 3, ins->dreg);
3317 case OP_FCONV_TO_U1:
3318 // Move float to 8 bit reg as unsigned
3319 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3320 ins->sreg1, ins->dreg);
3321 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3322 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3323 alpha_lda(code, alpha_sp, alpha_sp, -8);
3324 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3325 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3326 alpha_lda(code, alpha_sp, alpha_sp, 8);
3327 alpha_and_(code, ins->dreg, 0xff, ins->dreg);
3330 case OP_FCONV_TO_I1:
3331 // Move float to 8 bit reg
3332 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3333 ins->sreg1, ins->dreg);
3334 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3335 alpha_cvttq_c(code, ins->sreg1, ins->sreg1);
3336 alpha_lda(code, alpha_sp, alpha_sp, -8);
3337 alpha_stt(code, ins->sreg1, alpha_sp, 0);
3338 alpha_ldq(code, ins->dreg, alpha_sp, 0);
3339 alpha_lda(code, alpha_sp, alpha_sp, 8);
3340 alpha_sll_(code, ins->dreg, 56, ins->dreg);
3341 alpha_sra_(code, ins->dreg, 56, ins->dreg);
3345 case OP_LCONV_TO_R4:
3346 // Move 32/64 bit int into float
3347 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3348 ins->sreg1, ins->dreg);
3349 alpha_lda(code, alpha_sp, alpha_sp, -8);
3350 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3351 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3352 alpha_lda(code, alpha_sp, alpha_sp, 8);
3353 alpha_cvtqs(code, ins->dreg, ins->dreg);
3358 case OP_LCONV_TO_R8:
3359 // Move 32/64 bit int into double
3360 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3361 ins->sreg1, ins->dreg);
3362 alpha_lda(code, alpha_sp, alpha_sp, -8);
3363 alpha_stq(code, ins->sreg1, alpha_sp, 0);
3364 alpha_ldt(code, ins->dreg, alpha_sp, 0);
3365 alpha_lda(code, alpha_sp, alpha_sp, 8);
3366 alpha_cvtqt(code, ins->dreg, ins->dreg);
3370 case OP_FCONV_TO_R4:
3371 // Convert 64 bit float to 32 bit float (T -> S)
3372 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3373 ins->sreg1, ins->dreg);
3374 alpha_cvtts_su(code, ins->sreg1, ins->dreg);
3379 // Allocate sreg1 bytes on stack, round bytes by 8,
3380 // modify SP, set dreg to end of current stack frame
3381 // top of stack is used for call params
3382 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3383 ins->sreg1, ins->dreg);
3385 alpha_addq_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3386 alpha_bic_(code, ins->sreg1, (MONO_ARCH_LOCALLOC_ALIGNMENT - 1), ins->sreg1);
3387 if (ins->flags & MONO_INST_INIT)
3388 alpha_mov1(code, ins->sreg1, ins->sreg2);
3390 alpha_subq(code, alpha_sp, ins->sreg1, alpha_sp);
3391 if (cfg->arch.params_stack_size > 0)
3393 alpha_lda(code, ins->dreg, alpha_zero,
3394 (cfg->arch.params_stack_size));
3395 alpha_addq(code, alpha_sp, ins->dreg, ins->dreg);
3398 alpha_mov1(code, alpha_sp, ins->dreg);
3400 if (ins->flags & MONO_INST_INIT)
3402 // TODO: Optimize it later
3403 alpha_lda(code, ins->sreg2, ins->sreg2,
3404 -(MONO_ARCH_LOCALLOC_ALIGNMENT));
3405 alpha_blt(code, ins->sreg2, 3);
3406 alpha_addq(code, ins->sreg2, ins->dreg, alpha_at);
3407 alpha_stq(code, alpha_zero, alpha_at, 0);
3408 alpha_br(code, alpha_zero, -5);
3414 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3415 ins->sreg1, ins->dreg);
3416 alpha_mov1(code, ins->sreg1, ins->dreg);
3423 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3425 alpha_clr(code, ins->dreg);
3426 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3433 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3435 alpha_clr(code, ins->dreg);
3436 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3441 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3443 alpha_clr(code, ins->dreg);
3444 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3448 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3450 alpha_clr(code, ins->dreg);
3451 alpha_fbeq(code, alpha_at, 1);
3452 alpha_lda(code, ins->dreg, alpha_zero, 1);
3455 alpha_cvttq_c(code, alpha_at, alpha_at);
3456 alpha_lda(code, alpha_sp, alpha_sp, -8);
3457 alpha_stt(code, alpha_at, alpha_sp, 0);
3458 alpha_ldq(code, alpha_at, alpha_sp, 0);
3459 alpha_lda(code, alpha_sp, alpha_sp, 8);
3461 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3466 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3468 alpha_clr(code, ins->dreg);
3469 alpha_fbne(code, alpha_at, 1);
3470 alpha_lda(code, ins->dreg, alpha_zero, 1);
3473 alpha_cvttq_c(code, alpha_at, alpha_at);
3474 alpha_lda(code, alpha_sp, alpha_sp, -8);
3475 alpha_stt(code, alpha_at, alpha_sp, 0);
3476 alpha_ldq(code, alpha_at, alpha_sp, 0);
3477 alpha_lda(code, alpha_sp, alpha_sp, 8);
3479 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3485 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3487 alpha_clr(code, ins->dreg);
3488 alpha_fbeq(code, alpha_at, 1);
3489 alpha_lda(code, ins->dreg, alpha_zero, 1);
3493 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3496 alpha_clr(code, ins->dreg);
3497 alpha_fbne(code, (alpha_at+1), 1);
3498 alpha_fbeq(code, alpha_at, 1);
3499 alpha_lda(code, ins->dreg, alpha_zero, 1);
3504 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3505 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3509 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3510 alpha_fbeq(code, (alpha_at+1), 1);
3511 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3512 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3516 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3517 alpha_fbeq(code, (alpha_at+1), 1);
3518 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3519 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3523 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge] [");
3524 alpha_fbne(code, (alpha_at+1), 1);
3525 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3529 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3530 alpha_fbeq(code, (alpha_at+1), 1);
3531 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3532 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3536 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble] [");
3537 alpha_fbne(code, (alpha_at+1), 1);
3538 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3542 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3543 alpha_fbeq(code, (alpha_at+1), 1);
3544 alpha_cpys(code, (alpha_at+1), (alpha_at+1), alpha_at);
3545 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3549 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt] [");
3550 alpha_fbne(code, (alpha_at+1), 1);
3551 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3555 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3556 alpha_fbeq(code, (alpha_at+1), 1);
3557 alpha_cpys(code, alpha_zero, alpha_zero, alpha_at);
3558 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3562 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt] [");
3563 alpha_fbne(code, (alpha_at+1), 1);
3564 EMIT_ALPHA_BRANCH(ins, alpha_at, fbeq);
3568 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3569 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3573 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3574 EMIT_ALPHA_BRANCH(ins, alpha_at, fbne);
3578 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3579 EMIT_ALPHA_BRANCH(ins, alpha_at, beq);
3583 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3584 EMIT_ALPHA_BRANCH(ins, alpha_at, bne);
3588 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3589 ins->inst_c0 = (char *)code - (char *)cfg->native_code;
3593 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br] target: %p, next: %p, curr: %p, last: %p [",
3594 ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3596 if (ins->inst_target_bb->native_offset)
3598 // Somehow native offset is offset from
3599 // start of the code. So convert it to
3601 long br_offset = (char *)cfg->native_code +
3602 ins->inst_target_bb->native_offset - 4 - (char *)code;
3604 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3605 ins->inst_target_bb->native_offset,
3607 ins->inst_target_bb->native_offset);
3608 alpha_br(code, alpha_zero, br_offset/4);
3612 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3613 offset, ins->inst_target_bb);
3615 mono_add_patch_info (cfg, offset,
3617 ins->inst_target_bb);
3618 alpha_br(code, alpha_zero, 0);
3624 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3627 alpha_jmp(code, alpha_zero, ins->sreg1, 0);
3635 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3636 call = (MonoCallInst*)ins;
3638 if (ins->flags & MONO_INST_HAS_METHOD)
3640 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call->method);
3641 code = emit_call (cfg, code,
3642 MONO_PATCH_INFO_METHOD, call->method);
3646 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call->fptr);
3647 code = emit_call (cfg, code,
3648 MONO_PATCH_INFO_ABS, call->fptr);
3651 //code = emit_move_return_value (cfg, ins, code);
3658 case OP_VOIDCALL_REG:
3663 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins->sreg1);
3664 call = (MonoCallInst*)ins;
3666 alpha_mov1(code, ins->sreg1, alpha_pv);
3668 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3670 offset = (char *)code - (char *)cfg->native_code;
3673 ALPHA_LOAD_GP(offset)
3674 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3675 alpha_lda(code, alpha_gp, alpha_gp, 0);
3679 case OP_FCALL_MEMBASE:
3680 case OP_CALL_MEMBASE:
3681 case OP_LCALL_MEMBASE:
3682 case OP_VCALL_MEMBASE:
3686 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3687 ins->inst_basereg, ins->inst_offset);
3688 call = (MonoCallInst*)ins;
3690 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3691 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3693 offset = (char *)code - (char *)cfg->native_code;
3696 ALPHA_LOAD_GP(offset)
3697 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3698 alpha_lda(code, alpha_gp, alpha_gp, 0);
3702 case OP_VOIDCALL_MEMBASE:
3706 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3707 ins->inst_basereg, ins->inst_offset);
3708 call = (MonoCallInst*)ins;
3710 alpha_ldq(code, alpha_pv, ins->inst_basereg, ins->inst_offset);
3711 alpha_jsr(code, alpha_ra, alpha_pv, 0);
3713 offset = (char *)code - (char *)cfg->native_code;
3716 ALPHA_LOAD_GP(offset)
3717 alpha_ldah(code, alpha_gp, alpha_ra, 0);
3718 alpha_lda(code, alpha_gp, alpha_gp, 0);
3722 case OP_START_HANDLER:
3724 // TODO - find out when we called by call_handler or resume_context
3725 // of by call_filter. There should be difference. For now just
3726 // handle - call_handler
3728 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3729 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3731 alpha_stq(code, alpha_ra, ins->inst_left->inst_basereg,
3732 ins->inst_left->inst_offset);
3738 // Keep in sync with start_handler
3739 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3740 ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3742 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3743 ins->inst_left->inst_offset);
3745 alpha_ret(code, alpha_ra, 1);
3751 // Keep in sync with start_handler
3752 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3753 ins->sreg1, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
3755 alpha_ldq(code, alpha_ra, ins->inst_left->inst_basereg,
3756 ins->inst_left->inst_offset);
3758 if (ins->sreg1 != -1 && ins->sreg1 != alpha_r0)
3759 alpha_mov1(code, ins->sreg1, alpha_r0);
3761 alpha_ret(code, alpha_ra, 1);
3765 case OP_CALL_HANDLER:
3769 offset = (char *)code - (char *)cfg->native_code;
3771 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3772 offset, ins->inst_target_bb);
3774 mono_add_patch_info (cfg, offset,
3776 ins->inst_target_bb);
3777 alpha_bsr(code, alpha_ra, 0);
3782 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3784 alpha_mov1(code, ins->sreg1, alpha_a0);
3785 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3786 (gpointer)"mono_arch_throw_exception");
3790 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3792 alpha_mov1(code, ins->sreg1, alpha_a0);
3793 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
3794 (gpointer)"mono_arch_rethrow_exception");
3800 * Note: this 'frame destruction' logic is useful for tail calls,
3801 too. Keep in sync with the code in emit_epilog.
3804 AlphaGotData ge_data;
3806 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins->inst_p0);
3808 /* FIXME: no tracing support... */
3809 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3810 code = mono_arch_instrument_epilog (cfg,
3811 mono_profiler_method_leave, code, FALSE);
3812 g_assert (!cfg->method->save_lmf);
3814 alpha_mov1( code, alpha_fp, alpha_sp );
3816 code = emit_load_volatile_arguments (cfg, code);
3818 offset = cfg->arch.params_stack_size;
3820 alpha_ldq( code, alpha_ra, alpha_sp, (offset + 0) );
3821 alpha_ldq( code, alpha_fp, alpha_sp, (offset + 8) );
3822 alpha_lda( code, alpha_sp, alpha_sp, cfg->arch.stack_size );
3824 ge_data.data.p = ins->inst_p0;
3825 add_got_entry(cfg, GT_PTR, ge_data,
3826 (char *)code - (char *)cfg->native_code,
3827 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3828 alpha_ldq( code, alpha_pv, alpha_gp, 0);
3830 alpha_jsr( code, alpha_zero, alpha_pv, 0);
3835 mono_add_patch_info (cfg, offset,
3836 (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3839 case OP_MEMORY_BARRIER:
3840 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3845 // Float register contains a value which we need to check
3847 double ni = -1.0 / 0.0;
3848 double pi = 1.0 / 0.0;
3849 AlphaGotData ge_data;
3851 CFG_DEBUG(4) g_print("ALPHA_TODO: [chfinite] sreg1=%d\n", ins->sreg1);
3852 alpha_cmptun_su(code, ins->sreg1, ins->sreg1, alpha_at);
3854 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3856 // Negative infinity
3857 ge_data.data.d = ni;
3858 add_got_entry(cfg, GT_DOUBLE, ge_data,
3859 (char *)code - (char *)cfg->native_code,
3860 MONO_PATCH_INFO_NONE, 0);
3861 alpha_ldt(code, alpha_at, alpha_gp, 0);
3863 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3866 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3868 // Positive infinity
3869 ge_data.data.d = pi;
3870 add_got_entry(cfg, GT_DOUBLE, ge_data,
3871 (char *)code - (char *)cfg->native_code,
3872 MONO_PATCH_INFO_NONE, 0);
3873 alpha_ldt(code, alpha_at, alpha_gp, 0);
3875 alpha_cmpteq_su(code, ins->sreg1, alpha_at, alpha_at);
3878 EMIT_COND_EXC_BRANCH(fbne, alpha_at, "ArithmeticException");
3882 CFG_DEBUG(4) g_print("ALPHA_TODO: [fdiv] dest=%d, sreg1=%d, sreg2=%d\n",
3883 ins->dreg, ins->sreg1, ins->sreg2);
3884 alpha_divt_su(code, ins->sreg1, ins->sreg2, ins->dreg);
3889 g_warning ("unknown opcode %s in %s()\n",
3890 mono_inst_name (ins->opcode), __FUNCTION__);
3892 // g_assert_not_reached ();
3896 if ( (((char *)code) -
3897 ((char *)cfg->native_code) -
3900 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3901 mono_inst_name (ins->opcode), max_len,
3902 ((char *)code) - ((char *)cfg->native_code) - offset );
3903 //g_assert_not_reached ();
3909 last_offset = offset;
3912 cfg->code_len = ((char *)code) - ((char *)cfg->native_code);
3915 /*========================= End of Function ========================*/
3920 /*------------------------------------------------------------------*/
3922 /* Name - mono_arch_cpu_optimizazions */
3924 /* Function - Returns the optimizations supported on this CPU */
3926 /*------------------------------------------------------------------*/
3929 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
3933 if (getenv("MONO_ALPHA_DEBUG"))
3934 mini_alpha_verbose_level = 1;
3936 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3938 /*----------------------------------------------------------*/
3939 /* no alpha-specific optimizations yet */
3940 /*----------------------------------------------------------*/
3941 *exclude_mask = MONO_OPT_LINEARS;
3942 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3946 /*========================= End of Function ========================*/
3948 /*------------------------------------------------------------------*/
3950 /* Name - mono_arch_flush_icache */
3952 /* Function - Flush the CPU icache. */
3954 /*------------------------------------------------------------------*/
3957 mono_arch_flush_icache (guint8 *code, gint size)
3959 //ALPHA_DEBUG("mono_arch_flush_icache");
3961 /* flush instruction cache to see trampoline code */
3962 asm volatile("imb":::"memory");
3965 /*========================= End of Function ========================*/
3967 /*------------------------------------------------------------------*/
3969 /* Name - mono_arch_regname */
3971 /* Function - Returns the name of the register specified by */
3972 /* the input parameter. */
3974 /*------------------------------------------------------------------*/
3977 mono_arch_regname (int reg) {
3978 static const char * rnames[] = {
3979 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
3980 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
3981 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
3982 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
3983 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
3984 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
3985 "alpha_r30", "alpha_r31"
3988 if (reg >= 0 && reg < 32)
3989 return rnames [reg];
3993 /*========================= End of Function ========================*/
3995 /*------------------------------------------------------------------*/
3997 /* Name - mono_arch_fregname */
3999 /* Function - Returns the name of the register specified by */
4000 /* the input parameter. */
4002 /*------------------------------------------------------------------*/
4005 mono_arch_fregname (int reg) {
4006 static const char * rnames[] = {
4007 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4008 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4009 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4010 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4011 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4012 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4013 "alpha_f30", "alpha_f31"
4016 if (reg >= 0 && reg < 32)
4017 return rnames [reg];
4022 /*========================= End of Function ========================*/
4024 /*------------------------------------------------------------------*/
4026 /* Name - mono_arch_patch_code */
4028 /* Function - Process the patch data created during the */
4029 /* instruction build process. This resolves jumps, */
4030 /* calls, variables etc. */
4032 /*------------------------------------------------------------------*/
4035 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
4036 guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4038 MonoJumpInfo *patch_info;
4039 gboolean compile_aot = !run_cctors;
4041 ALPHA_DEBUG("mono_arch_patch_code");
4043 for (patch_info = ji; patch_info; patch_info = patch_info->next)
4045 unsigned char *ip = patch_info->ip.i + code;
4046 const unsigned char *target;
4048 target = mono_resolve_patch_target (method, domain,
4049 code, patch_info, run_cctors);
4053 switch (patch_info->type)
4056 case MONO_PATCH_INFO_BB:
4057 case MONO_PATCH_INFO_LABEL:
4060 /* No need to patch these */
4065 switch (patch_info->type)
4067 case MONO_PATCH_INFO_NONE:
4070 case MONO_PATCH_INFO_GOT_OFFSET:
4072 unsigned int *ip2 = (unsigned int *)ip;
4073 unsigned int inst = *ip2;
4074 unsigned int off = patch_info->data.offset & 0xFFFFFFFF;
4076 g_assert(!(off & 0xFFFF8000));
4084 case MONO_PATCH_INFO_CLASS_INIT:
4086 /* Might already been changed to a nop */
4087 unsigned int* ip2 = (unsigned int *)ip;
4088 unsigned long t_addr = (unsigned long)target;
4090 if (*ip2 != (t_addr & 0xFFFFFFFF) ||
4091 *(ip2+1) != ((t_addr>>32) & 0xFFFFFFFF))
4093 // amd64_call_code (ip2, 0);
4097 // case MONO_PATCH_INFO_METHOD_REL:
4098 case MONO_PATCH_INFO_R8:
4099 case MONO_PATCH_INFO_R4:
4100 g_assert_not_reached ();
4102 case MONO_PATCH_INFO_BB:
4105 case MONO_PATCH_INFO_METHOD:
4106 case MONO_PATCH_INFO_METHODCONST:
4107 case MONO_PATCH_INFO_INTERNAL_METHOD:
4108 case MONO_PATCH_INFO_METHOD_JUMP:
4110 volatile unsigned int *p = (unsigned int *)ip;
4111 unsigned long t_addr;
4118 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4120 if (target != ((void *)t_addr))
4122 t_addr = (unsigned long)target;
4123 *p = (unsigned int)(t_addr & 0xFFFFFFFF);
4124 *(p+1) = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4129 case MONO_PATCH_INFO_ABS:
4131 volatile unsigned int *p = (unsigned int *)ip;
4132 unsigned long t_addr;
4138 ALPHA_PRINT g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4143 case MONO_PATCH_INFO_SWITCH:
4145 unsigned int *pcode = (unsigned int *)ip;
4146 unsigned long t_addr;
4148 t_addr = (unsigned long)target;
4150 if (((unsigned long)ip) % 8)
4156 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4157 alpha_nop(pcode); // TODO optimize later
4158 alpha_bsr(pcode, alpha_at, 2);
4160 *pcode = (unsigned int)(t_addr & 0xFFFFFFFF);
4162 *pcode = (unsigned int)((t_addr >> 32) & 0xFFFFFFFF);
4165 alpha_ldq(pcode, alpha_at, alpha_at, 0);
4175 volatile unsigned int *p = (unsigned int *)ip;
4176 unsigned int alpha_ins = *p;
4177 unsigned int opcode;
4180 opcode = (alpha_ins >> AXP_OP_SHIFT) & AXP_OFF6_MASK;
4182 if (opcode >= 0x30 && opcode <= 0x3f)
4184 // This is branch with offset instruction
4185 br_offset = (target - ip - 4);
4187 g_assert(!(br_offset & 3));
4189 alpha_ins |= (br_offset/4) & AXP_OFF21_MASK;
4197 /*========================= End of Function ========================*/
4198 /*------------------------------------------------------------------*/
4200 /* Name - mono_arch_emit_this_vret_args */
4204 /*------------------------------------------------------------------*/
4207 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst,
4208 int this_reg, int this_type, int vt_reg)
4210 MonoCallInst *call = (MonoCallInst*)inst;
4211 CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, inst->signature, FALSE);
4213 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4219 if (cinfo->ret.storage == ArgValuetypeInReg)
4222 * The valuetype is in RAX:RDX after the call, need to be copied to
4223 * the stack. Push the address here, so the call instruction can
4226 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4227 //vtarg->sreg1 = vt_reg;
4228 //mono_bblock_add_inst (cfg->cbb, vtarg);
4231 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4236 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4237 vtarg->sreg1 = vt_reg;
4238 vtarg->dreg = mono_alloc_ireg (cfg);
4239 mono_bblock_add_inst (cfg->cbb, vtarg);
4241 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg,
4242 cinfo->ret.reg, FALSE);
4246 /* add the this argument */
4250 MONO_INST_NEW (cfg, this, OP_MOVE);
4251 this->type = this_type;
4252 this->sreg1 = this_reg;
4253 this->dreg = mono_alloc_ireg (cfg);
4254 mono_bblock_add_inst (cfg->cbb, this);
4256 mono_call_inst_add_outarg_reg (cfg, call, this->dreg,
4257 cinfo->args [0].reg, FALSE);
4263 /*========================= End of Function ========================*/
4265 /*------------------------------------------------------------------*/
4267 /* Name - mono_arch_is_inst_imm */
4269 /* Function - Determine if operand qualifies as an immediate */
4270 /* value. For Alpha this is a value 0 - 255 */
4272 /* Returns - True|False - is [not] immediate value. */
4274 /*------------------------------------------------------------------*/
4277 mono_arch_is_inst_imm (gint64 imm)
4279 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4281 return (imm & ~(0x0FFL)) ? 0 : 1;
4284 /*------------------------------------------------------------------*/
4286 /* Name - mono_arch_finish_init */
4288 /* Function - Setup the JIT's Thread Level Specific Data. */
4290 /*------------------------------------------------------------------*/
4293 mono_arch_finish_init (void)
4295 ALPHA_DEBUG("mono_arch_finish_init");
4297 if (!lmf_addr_key_inited) {
4298 lmf_addr_key_inited = TRUE;
4299 pthread_key_create (&lmf_addr_key, NULL);
4302 pthread_setspecific (lmf_addr_key, &tls->lmf);
4305 /*------------------------------------------------------------------*/
4307 /* Name - mono_arch_cpu_init */
4309 /* Function - Perform CPU specific initialization to execute */
4312 /*------------------------------------------------------------------*/
4315 mono_arch_cpu_init (void)
4317 unsigned long amask, implver;
4318 register long v0 __asm__("$0") = -1;
4320 ALPHA_DEBUG("mono_arch_cpu_init");
4322 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
4324 __asm__ (".long 0x47e03d80" : "=r"(v0));
4330 //printf("amask: %x, implver: %x", amask, implver);
4334 * Initialize architecture specific code.
4337 mono_arch_init (void)
4342 * Cleanup architecture specific code.
4345 mono_arch_cleanup (void)
4352 * Obtain information about a call according to the calling convention.
4354 * For x86 ELF, see the "System V Application Binary Interface Intel386
4355 * Architecture Processor Supplment, Fourth Edition" document for more
4357 * For x86 win32, see ???.
4360 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
4362 guint32 i, gr, fr, *pgr, *pfr;
4364 int n = sig->hasthis + sig->param_count;
4365 guint32 stack_size = 0;
4368 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
4383 ret_type = mono_type_get_underlying_type (sig->ret);
4384 switch (ret_type->type) {
4385 case MONO_TYPE_BOOLEAN:
4390 case MONO_TYPE_CHAR:
4396 case MONO_TYPE_FNPTR:
4397 case MONO_TYPE_CLASS:
4398 case MONO_TYPE_OBJECT:
4399 case MONO_TYPE_SZARRAY:
4400 case MONO_TYPE_ARRAY:
4401 case MONO_TYPE_STRING:
4402 cinfo->ret.storage = ArgInIReg;
4403 cinfo->ret.reg = alpha_r0;
4407 cinfo->ret.storage = ArgInIReg;
4408 cinfo->ret.reg = alpha_r0;
4411 cinfo->ret.storage = ArgInFloatReg;
4412 cinfo->ret.reg = alpha_f0;
4415 cinfo->ret.storage = ArgInDoubleReg;
4416 cinfo->ret.reg = alpha_f0;
4418 case MONO_TYPE_GENERICINST:
4419 if (!mono_type_generic_inst_is_valuetype (ret_type))
4421 cinfo->ret.storage = ArgInIReg;
4422 cinfo->ret.reg = alpha_r0;
4426 case MONO_TYPE_VALUETYPE:
4428 guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
4430 add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE,
4431 &tmp_gr, &tmp_fr, &tmp_stacksize);
4433 if (cinfo->ret.storage == ArgOnStack)
4434 /* The caller passes the address where the value
4436 add_general (pgr, &stack_size, &cinfo->ret);
4439 case MONO_TYPE_TYPEDBYREF:
4440 /* Same as a valuetype with size 24 */
4441 add_general (pgr, &stack_size, &cinfo->ret);
4444 case MONO_TYPE_VOID:
4447 g_error ("Can't handle as return value 0x%x", sig->ret->type);
4453 add_general (pgr, &stack_size, cinfo->args + 0);
4455 if (!sig->pinvoke &&
4456 (sig->call_convention == MONO_CALL_VARARG) && (n == 0))
4459 fr = FLOAT_PARAM_REGS;
4461 /* Emit the signature cookie just before the implicit arguments
4463 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4466 for (i = 0; i < sig->param_count; ++i)
4468 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
4471 if (!sig->pinvoke &&
4472 (sig->call_convention == MONO_CALL_VARARG) &&
4473 (i == sig->sentinelpos))
4475 /* We allways pass the sig cookie on the stack for simpl
4478 * Prevent implicit arguments + the sig cookie from being passed
4482 fr = FLOAT_PARAM_REGS;
4484 /* Emit the signature cookie just before the implicit arguments */
4485 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4488 if (sig->params [i]->byref) {
4489 add_general (pgr, &stack_size, ainfo);
4493 ptype = mono_type_get_underlying_type (sig->params [i]);
4495 switch (ptype->type) {
4496 case MONO_TYPE_BOOLEAN:
4499 add_general (pgr, &stack_size, ainfo);
4503 case MONO_TYPE_CHAR:
4504 add_general (pgr, &stack_size, ainfo);
4508 add_general (pgr, &stack_size, ainfo);
4513 case MONO_TYPE_FNPTR:
4514 case MONO_TYPE_CLASS:
4515 case MONO_TYPE_OBJECT:
4516 case MONO_TYPE_STRING:
4517 case MONO_TYPE_SZARRAY:
4518 case MONO_TYPE_ARRAY:
4519 add_general (pgr, &stack_size, ainfo);
4521 case MONO_TYPE_GENERICINST:
4522 if (!mono_type_generic_inst_is_valuetype (ptype))
4524 add_general (pgr, &stack_size, ainfo);
4528 case MONO_TYPE_VALUETYPE:
4530 /* We allways pass valuetypes on the stack */
4531 add_valuetype (gsctx, sig, ainfo, sig->params [i],
4532 FALSE, pgr, pfr, &stack_size);
4534 case MONO_TYPE_TYPEDBYREF:
4535 stack_size += sizeof (MonoTypedRef);
4536 ainfo->storage = ArgOnStack;
4540 add_general (pgr, &stack_size, ainfo);
4543 add_float (pfr, &stack_size, ainfo, FALSE);
4546 add_float (pfr, &stack_size, ainfo, TRUE);
4549 g_assert_not_reached ();
4553 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) &&
4554 (n > 0) && (sig->sentinelpos == sig->param_count))
4557 fr = FLOAT_PARAM_REGS;
4559 /* Emit the signature cookie just before the implicit arguments
4561 add_general (pgr, &stack_size, &cinfo->sig_cookie);
4564 cinfo->stack_usage = stack_size;
4565 cinfo->reg_usage = gr;
4566 cinfo->freg_usage = fr;
4571 static const char *CvtMonoType(MonoTypeEnum t)
4576 return "MONO_TYPE_END";
4577 case MONO_TYPE_VOID:
4578 return "MONO_TYPE_VOID";
4579 case MONO_TYPE_BOOLEAN:
4580 return "MONO_TYPE_BOOLEAN";
4581 case MONO_TYPE_CHAR:
4582 return "MONO_TYPE_CHAR";
4584 return "MONO_TYPE_I1";
4586 return "MONO_TYPE_U1";
4588 return "MONO_TYPE_I2";
4590 return "MONO_TYPE_U2";
4592 return "MONO_TYPE_I4";
4594 return "MONO_TYPE_U4";
4596 return "MONO_TYPE_I8";
4598 return "MONO_TYPE_U8";
4600 return "MONO_TYPE_R4";
4602 return "MONO_TYPE_R8";
4603 case MONO_TYPE_STRING:
4604 return "MONO_TYPE_STRING";
4606 return "MONO_TYPE_PTR";
4607 case MONO_TYPE_BYREF:
4608 return "MONO_TYPE_BYREF";
4609 case MONO_TYPE_VALUETYPE:
4610 return "MONO_TYPE_VALUETYPE";
4611 case MONO_TYPE_CLASS:
4612 return "MONO_TYPE_CLASS";
4614 return "MONO_TYPE_VAR";
4615 case MONO_TYPE_ARRAY:
4616 return "MONO_TYPE_ARRAY";
4617 case MONO_TYPE_GENERICINST:
4618 return "MONO_TYPE_GENERICINST";
4619 case MONO_TYPE_TYPEDBYREF:
4620 return "MONO_TYPE_TYPEDBYREF";
4622 return "MONO_TYPE_I";
4624 return "MONO_TYPE_U";
4625 case MONO_TYPE_FNPTR:
4626 return "MONO_TYPE_FNPTR";
4627 case MONO_TYPE_OBJECT:
4628 return "MONO_TYPE_OBJECT";
4629 case MONO_TYPE_SZARRAY:
4630 return "MONO_TYPE_SZARRAY";
4631 case MONO_TYPE_MVAR:
4632 return "MONO_TYPE_MVAR";
4633 case MONO_TYPE_CMOD_REQD:
4634 return "MONO_TYPE_CMOD_REQD";
4635 case MONO_TYPE_CMOD_OPT:
4636 return "MONO_TYPE_CMOD_OPT";
4637 case MONO_TYPE_INTERNAL:
4638 return "MONO_TYPE_INTERNAL";
4639 case MONO_TYPE_MODIFIER:
4640 return "MONO_TYPE_MODIFIER";
4641 case MONO_TYPE_SENTINEL:
4642 return "MONO_TYPE_SENTINEL";
4643 case MONO_TYPE_PINNED:
4644 return "MONO_TYPE_PINNED";
4652 /*------------------------------------------------------------------*/
4654 /* Name - mono_arch_call_opcode */
4656 /* Function - Take the arguments and generate the arch-specific */
4657 /* instructions to properly call the function. This */
4658 /* includes pushing, moving argments to the correct */
4661 * This method is called during converting method to IR
4662 * We need to generate IR ints to follow calling convention
4663 * cfg - points to currently compiled unit
4665 * call - points to structure that describes what we are going to
4666 * call (at least number of parameters required for the call)
4669 * On return we need to pass back modified call structure
4671 /*------------------------------------------------------------------*/
4674 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb,
4675 MonoCallInst *call, int is_virtual)
4678 MonoMethodSignature *sig;
4683 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4685 sig = call->signature;
4686 n = sig->param_count + sig->hasthis;
4688 // Collect info about method we age going to call
4689 cinfo = get_call_info (cfg->generic_sharing_context, sig, sig->pinvoke);
4691 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4692 sig->pinvoke ? "PInvoke" : "Managed",
4693 sig->param_count, sig->hasthis,
4694 CvtMonoType(sig->ret->type), sig->ret->type);
4696 if (cinfo->stack_usage > cfg->arch.params_stack_size)
4697 cfg->arch.params_stack_size = cinfo->stack_usage;
4699 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
4700 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
4702 for (i = 0; i < n; ++i)
4704 ArgInfo *ainfo = cinfo->args + i;
4706 /* Emit the signature cookie just before the implicit arguments
4708 if (!sig->pinvoke &&
4709 (sig->call_convention == MONO_CALL_VARARG) &&
4712 MonoMethodSignature *tmp_sig;
4715 /* FIXME: Add support for signature tokens to AOT */
4716 cfg->disable_aot = TRUE;
4717 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4720 * mono_ArgIterator_Setup assumes the signature cookie is
4721 * passed first and all the arguments which were before it are
4722 * passed on the stack after the signature. So compensate by
4723 * passing a different signature.
4725 tmp_sig = mono_metadata_signature_dup (call->signature);
4726 tmp_sig->param_count -= call->signature->sentinelpos;
4727 tmp_sig->sentinelpos = 0;
4728 memcpy (tmp_sig->params,
4729 call->signature->params + call->signature->sentinelpos,
4730 tmp_sig->param_count * sizeof (MonoType*));
4732 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
4733 sig_arg->inst_p0 = tmp_sig;
4735 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4736 arg->inst_left = sig_arg;
4737 arg->type = STACK_PTR;
4739 /* prepend, so they get reversed */
4740 arg->next = call->out_args;
4741 call->out_args = arg;
4744 if (is_virtual && i == 0) {
4745 /* the argument will be attached to the call instrucion
4747 in = call->args [i];
4751 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4752 in = call->args [i];
4753 arg->cil_code = in->cil_code;
4754 arg->inst_left = in;
4755 arg->type = in->type;
4756 /* prepend, so they get reversed */
4757 arg->next = call->out_args;
4758 call->out_args = arg;
4760 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i);
4762 if (sig->hasthis && (i == 0))
4763 arg_type = &mono_defaults.object_class->byval_arg;
4765 arg_type = sig->params [i - sig->hasthis];
4767 if ((i >= sig->hasthis) &&
4768 (MONO_TYPE_ISSTRUCT(arg_type)))
4773 if (arg_type->type == MONO_TYPE_TYPEDBYREF) {
4774 size = sizeof (MonoTypedRef);
4775 align = sizeof (gpointer);
4779 size = mono_type_native_stack_size (&in->klass->byval_arg,
4782 size = mini_type_stack_size (cfg->generic_sharing_context, &in->klass->byval_arg, &align);
4784 if (ainfo->storage == ArgAggregate)
4786 MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
4789 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
4791 vtaddr = mono_compile_create_var (cfg,
4792 &mono_defaults.int_class->byval_arg, OP_LOCAL);
4795 * Part of the structure is passed in registers.
4797 for (j = 0; j < ainfo->nregs; ++j)
4799 int offset, load_op, dest_reg, arg_storage;
4801 slot = ainfo->reg + j;
4802 load_op = CEE_LDIND_I;
4804 dest_reg = ainfo->reg + j;
4805 arg_storage = ArgInIReg;
4807 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4808 load->ssa_op = MONO_SSA_LOAD;
4809 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4811 NEW_ICONST (cfg, offset_ins, offset);
4812 MONO_INST_NEW (cfg, load2, CEE_ADD);
4813 load2->inst_left = load;
4814 load2->inst_right = offset_ins;
4816 MONO_INST_NEW (cfg, load, load_op);
4817 load->inst_left = load2;
4822 MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
4824 add_outarg_reg (cfg, call, set_reg, arg_storage,
4826 if (set_reg != call->out_args)
4828 set_reg->next = call->out_args;
4829 call->out_args = set_reg;
4834 * Part of the structure is passed on the stack.
4836 for (j = ainfo->nregs; j < ainfo->nslots; ++j)
4840 slot = ainfo->reg + j;
4842 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4843 load->ssa_op = MONO_SSA_LOAD;
4844 load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
4846 NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
4847 MONO_INST_NEW (cfg, load2, CEE_ADD);
4848 load2->inst_left = load;
4849 load2->inst_right = offset_ins;
4851 MONO_INST_NEW (cfg, load, CEE_LDIND_I);
4852 load->inst_left = load2;
4857 MONO_INST_NEW (cfg, outarg, OP_OUTARG);
4859 outarg->inst_left = load;
4860 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4861 outarg->dreg = ainfo->offset + (slot - 22) * 8;
4863 if (outarg != call->out_args)
4865 outarg->next = call->out_args;
4866 call->out_args = outarg;
4870 /* Trees can't be shared so make a copy*/
4871 MONO_INST_NEW (cfg, arg, CEE_STIND_I);
4872 arg->cil_code = in->cil_code;
4873 arg->ssa_op = MONO_SSA_STORE;
4874 arg->inst_left = vtaddr;
4875 arg->inst_right = in;
4876 arg->type = in->type;
4878 /* prepend, so they get reversed */
4879 arg->next = call->out_args;
4880 call->out_args = arg;
4884 MonoInst *stack_addr;
4886 CFG_DEBUG(3) g_print("value type, size:%d\n", size);
4888 MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
4889 stack_addr->inst_basereg = alpha_sp;
4890 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4891 stack_addr->inst_offset = ainfo->offset;
4892 //stack_addr->inst_offset = 16 + ainfo->offset;
4893 stack_addr->inst_imm = size;
4895 arg->opcode = OP_OUTARG_VT;
4896 arg->inst_right = stack_addr;
4900 arg->opcode = OP_OUTARG_VT;
4901 arg->klass = in->klass;
4902 arg->backend.is_pinvoke = sig->pinvoke;
4903 arg->inst_imm = size; */
4907 CFG_DEBUG(3) g_print("simple\n");
4909 switch (ainfo->storage)
4912 add_outarg_reg (cfg, call, arg, ainfo->storage,
4916 arg->opcode = OP_OUTARG;
4917 //arg->dreg = -((n - i) * 8);
4918 arg->dreg = ainfo->offset;
4919 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4921 if (!sig->params[i-sig->hasthis]->byref) {
4922 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R4)
4923 arg->opcode = OP_OUTARG_R4;
4925 if (sig->params[i-sig->hasthis]->type == MONO_TYPE_R8)
4926 arg->opcode = OP_OUTARG_R8;
4930 case ArgInDoubleReg:
4931 add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
4934 g_assert_not_reached ();
4940 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4942 if (cinfo->ret.storage == ArgValuetypeInReg) {
4943 MonoInst *zero_inst;
4945 * After the call, the struct is in registers, but needs to be saved
4946 to the memory pointed
4947 * to by vt_arg in this_vret_args. This means that vt_ar
4948 g needs to be saved somewhere
4949 * before calling the function. So we add a dummy instru
4950 ction to represent pushing the
4951 * struct return address to the stack. The return addres
4952 s will be saved to this stack slot
4953 * by the code emitted in this_vret_args.
4955 MONO_INST_NEW (cfg, arg, OP_OUTARG);
4956 MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
4957 zero_inst->inst_p0 = 0;
4958 arg->inst_left = zero_inst;
4959 arg->type = STACK_PTR;
4960 /* prepend, so they get reversed */
4961 arg->next = call->out_args;
4962 call->out_args = arg;
4965 /* if the function returns a struct, the called method a
4966 lready does a ret $0x4 */
4967 if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
4968 ; //cinfo->stack_usage -= 4;
4971 // stack_usage shows how much stack we would need to do the call
4972 // (for example for params that we pass on stack
4973 call->stack_usage = cinfo->stack_usage;
4975 // Save all used regs to do the call in compile unit structure
4976 cfg->used_int_regs |= call->used_iregs;
4983 /*========================= End of Function ========================*/
4985 /*------------------------------------------------------------------*/
4987 /* Name - mono_arch_register_lowlevel_calls */
4989 /* Function - Register routines to help with --trace operation. */
4991 /*------------------------------------------------------------------*/
4994 mono_arch_register_lowlevel_calls (void)
4996 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
4998 mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr",
5002 /*========================= End of Function ========================*/
5004 /*------------------------------------------------------------------*/
5006 /* Name - mono_arch_global_int_regs */
5008 /* Function - Return a list of usable integer registers. */
5010 /*------------------------------------------------------------------*/
5013 mono_arch_get_global_int_regs (MonoCompile *cfg)
5017 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5019 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5020 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5021 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5022 regs = g_list_prepend (regs, (gpointer)alpha_r12);
5023 regs = g_list_prepend (regs, (gpointer)alpha_r13);
5024 regs = g_list_prepend (regs, (gpointer)alpha_r14);
5029 /*========================= End of Function ========================*/
5031 /*------------------------------------------------------------------*/
5033 /* Name - mono_arch_get_allocatable_int_vars */
5037 /*------------------------------------------------------------------*/
5040 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
5044 MonoMethodSignature *sig;
5045 MonoMethodHeader *header;
5048 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5050 header = cfg->header;
5052 sig = mono_method_signature (cfg->method);
5054 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5056 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5058 MonoInst *ins = cfg->args [i];
5060 ArgInfo *ainfo = &cinfo->args [i];
5063 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5066 // if (ainfo->storage == ArgInIReg) {
5067 // /* The input registers are non-volatile */
5068 // ins->opcode = OP_REGVAR;
5069 //ins->dreg = 32 + ainfo->reg;
5073 for (i = 0; i < cfg->num_varinfo; i++)
5075 MonoInst *ins = cfg->varinfo [i];
5076 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
5079 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
5083 (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
5084 (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
5087 if (mono_is_regsize_var (ins->inst_vtype))
5089 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
5090 g_assert (i == vmv->idx);
5091 vars = g_list_prepend (vars, vmv);
5095 vars = mono_varlist_sort (cfg, vars, 0);
5100 /*========================= End of Function ========================*/
5102 /*------------------------------------------------------------------*/
5104 /* Name - mono_arch_get_domain_intrinsic */
5110 /*------------------------------------------------------------------*/
5113 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5117 if (appdomain_tls_offset == -1)
5120 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5121 ins->inst_offset = appdomain_tls_offset;
5125 /*========================= End of Function ========================*/
5127 /*------------------------------------------------------------------*/
5129 /* Name - mono_arch_get_inst_for_method */
5131 /* Function - Check for opcodes we can handle directly in */
5134 /*------------------------------------------------------------------*/
5137 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
5138 MonoMethodSignature *fsig, MonoInst **args)
5140 MonoInst *ins = NULL;
5142 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5144 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod->name);
5149 /*========================= End of Function ========================*/
5151 /*------------------------------------------------------------------*/
5153 /* Name - mono_arch_create_class_init_trampoline */
5155 /* Function - Creates a trampoline function to run a type init- */
5156 /* ializer. If the trampoline is called, it calls */
5157 /* mono_runtime_class_init with the given vtable, */
5158 /* then patches the caller code so it does not get */
5159 /* called any more. */
5161 /* Parameter - vtable - The type to initialize */
5163 /* Returns - A pointer to the newly created code */
5165 /*------------------------------------------------------------------*/
5168 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
5170 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5177 /*------------------------------------------------------------------*/
5179 /* Name - mono_arch_instrument_prolog */
5181 /* Function - Create an "instrumented" prolog. */
5183 /*------------------------------------------------------------------*/
5186 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
5187 gboolean enable_arguments)
5189 unsigned int *code = p;
5192 CallInfo *cinfo = NULL;
5193 MonoMethodSignature *sig;
5195 int i, n, stack_area = 0;
5196 AlphaGotData ge_data;
5198 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5200 /* Keep this in sync with mono_arch_get_argument_info */
5201 if (enable_arguments)
5203 /* Allocate a new area on the stack and save arguments there */
5204 sig = mono_method_signature (cfg->method);
5206 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5208 n = sig->param_count + sig->hasthis;
5210 stack_area = ALIGN_TO (n * 8, 8);
5212 // Correct stack by calculated value
5214 alpha_lda(code, alpha_sp, alpha_sp, -stack_area);
5216 for (i = 0; i < n; ++i)
5218 inst = cfg->args [i];
5220 if (inst->opcode == OP_REGVAR)
5222 switch(cinfo->args[i].storage)
5224 case ArgInDoubleReg:
5225 alpha_stt(code, inst->dreg, alpha_sp, (i*8));
5228 alpha_sts(code, inst->dreg, alpha_sp, (i*8));
5231 alpha_stq(code, inst->dreg, alpha_sp, (i*8));
5236 alpha_ldq(code, alpha_at, inst->inst_basereg, inst->inst_offset);
5237 alpha_stq(code, alpha_at, alpha_sp, (i*8));
5242 offset = (char *)code - (char *)cfg->native_code;
5244 ge_data.data.p = cfg->method;
5246 add_got_entry(cfg, GT_PTR, ge_data,
5247 (char *)code - (char *)cfg->native_code,
5248 MONO_PATCH_INFO_METHODCONST, cfg->method);
5249 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5251 alpha_mov1(code, alpha_sp, alpha_a1);
5253 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5255 if (enable_arguments)
5257 // Correct stack back by calculated value
5259 alpha_lda(code, alpha_sp, alpha_sp, stack_area);
5267 /*========================= End of Function ========================*/
5277 /*------------------------------------------------------------------*/
5279 /* Name - mono_arch_instrument_epilog */
5281 /* Function - Create an epilog that will handle the returned */
5282 /* values used in instrumentation. */
5284 /*------------------------------------------------------------------*/
5287 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5289 unsigned int *code = p;
5290 int save_mode = SAVE_NONE;
5292 MonoMethod *method = cfg->method;
5293 AlphaGotData ge_data;
5294 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5296 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5300 case MONO_TYPE_VOID:
5301 /* special case string .ctor icall */
5302 if (strcmp (".ctor", method->name) &&
5303 method->klass == mono_defaults.string_class)
5304 save_mode = SAVE_R0;
5306 save_mode = SAVE_NONE;
5310 save_mode = SAVE_R0;
5314 save_mode = SAVE_XMM;
5316 case MONO_TYPE_VALUETYPE:
5317 save_mode = SAVE_STRUCT;
5320 save_mode = SAVE_R0;
5324 /* Save the result and copy it into the proper argument register */
5328 alpha_lda(code, alpha_sp, alpha_sp, -8);
5329 alpha_stq(code, alpha_r0, alpha_sp, 0);
5331 if (enable_arguments)
5332 alpha_mov1(code, alpha_r0, alpha_a1);
5337 if (enable_arguments)
5338 alpha_lda(code, alpha_a1, alpha_zero, 0);
5342 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5343 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5345 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5347 * The result is already in the proper argument register so no copying
5354 g_assert_not_reached ();
5357 offset = (char *)code - (char *)cfg->native_code;
5359 ge_data.data.p = cfg->method;
5361 add_got_entry(cfg, GT_PTR, ge_data,
5362 (char *)code - (char *)cfg->native_code,
5363 MONO_PATCH_INFO_METHODCONST, cfg->method);
5365 alpha_ldq(code, alpha_a0, alpha_gp, 0);
5367 code = emit_call(cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func);
5369 /* Restore result */
5373 alpha_ldq(code, alpha_r0, alpha_sp, 0);
5374 alpha_lda(code, alpha_sp, alpha_sp, 8);
5380 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5381 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5382 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5387 g_assert_not_reached ();
5393 /*========================= End of Function ========================*/
5395 /*------------------------------------------------------------------*/
5397 /* Name - mono_arch_allocate_vars */
5399 /* Function - Set var information according to the calling */
5400 /* convention for Alpha. The local var stuff should */
5401 /* most likely be split in another method. */
5403 /* Parameter - @m - Compile unit. */
5405 * This method is called right before working with BBs. Conversion to
5406 * IR was done and some analises what registers would be used.
5407 * Collect info about registers we used - if we want to use a register
5408 * we need to allocate space for it and save on the stack in method
5411 * Alpha calling convertion:
5412 * FP -> Stack top <- SP
5413 * 0: Stack params to call others
5415 * RA <- arch.params_stack_size
5418 * [LMF info] <- arch.lmf_offset
5420 * [possible return values allocated on stack]
5424 * . caller saved regs <- arch.reg_save_area_offset
5425 * . a0 <- arch.args_save_area_offset
5431 * ------------------------
5432 * . a6 - passed args on stack
5435 /*------------------------------------------------------------------*/
5438 mono_arch_allocate_vars (MonoCompile *cfg)
5440 MonoMethodSignature *sig;
5441 MonoMethodHeader *header;
5443 int i, offset = 0, a_off = 0;
5444 guint32 locals_stack_size, locals_stack_align = 0;
5448 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5450 header = cfg->header;
5452 sig = mono_method_signature (cfg->method);
5454 cinfo = get_call_info (cfg->generic_sharing_context, sig, FALSE);
5456 /* if (cfg->arch.omit_fp) {
5457 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5458 cfg->frame_reg = AMD64_RSP;
5463 /* Locals are allocated forwards from FP. After
5464 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5465 * (starting from offset 16).
5466 * FIXME: Check there Arg6...Argn are supposed to be
5468 cfg->frame_reg = alpha_fp;
5469 // offset = MONO_ALPHA_VARS_OFFSET;
5472 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5473 cfg->arch.params_stack_size, cfg->arch.params_stack_size);
5474 offset += cfg->arch.params_stack_size;
5476 offset += 16; // Size to save RA & FP
5478 if (cfg->method->save_lmf)
5480 /* Reserve stack space for saving LMF + argument regs */
5481 guint32 size = sizeof (MonoLMF);
5483 //if (lmf_tls_offset == -1)
5484 // /* Need to save argument regs too */
5485 // size += (AMD64_NREG * 8) + (8 * 8);
5487 cfg->arch.lmf_offset = offset;
5490 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5491 cfg->method->name, cfg->arch.lmf_offset, size);
5494 if (sig->ret->type != MONO_TYPE_VOID)
5496 switch (cinfo->ret.storage)
5500 case ArgInDoubleReg:
5501 if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
5502 !mono_class_from_mono_type (sig->ret)->enumtype) ||
5503 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
5505 /* The register is volatile */
5506 cfg->ret->opcode = OP_REGOFFSET;
5507 cfg->ret->inst_basereg = cfg->frame_reg;
5509 /*if (cfg->arch.omit_fp) {
5510 cfg->ret->inst_offset = offset;
5514 cfg->ret->inst_offset = offset;
5515 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset);
5521 cfg->ret->opcode = OP_REGVAR;
5522 cfg->ret->inst_c0 = cinfo->ret.reg;
5525 case ArgValuetypeInReg:
5526 /* Allocate a local to hold the result, the epilog will
5527 copy it to the correct place */
5528 // g_assert (!cfg->arch.omit_fp);
5530 cfg->ret->opcode = OP_REGOFFSET;
5531 cfg->ret->inst_basereg = cfg->frame_reg;
5532 cfg->ret->inst_offset = offset;
5535 g_assert_not_reached ();
5537 cfg->ret->dreg = cfg->ret->inst_c0;
5540 /* Allocate locals */
5541 offsets = mono_allocate_stack_slots (cfg,
5542 /*cfg->arch.omit_fp ? FALSE:*/ TRUE,
5544 &locals_stack_align);
5546 //g_assert((locals_stack_size % 8) == 0);
5547 if (locals_stack_size % 8)
5549 locals_stack_size += 8 - (locals_stack_size % 8);
5552 /* if (locals_stack_align)
5554 offset += (locals_stack_align - 1);
5555 offset &= ~(locals_stack_align - 1);
5559 cfg->arch.localloc_offset = offset;
5561 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset, offset);
5562 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5563 locals_stack_size, locals_stack_size);
5565 for (i = cfg->locals_start; i < cfg->num_varinfo; i++)
5567 if (offsets [i] != -1) {
5568 MonoInst *inst = cfg->varinfo [i];
5569 inst->opcode = OP_REGOFFSET;
5570 inst->inst_basereg = cfg->frame_reg;
5571 //if (cfg->arch.omit_fp)
5572 // inst->inst_offset = (offset + offsets [i]);
5574 inst->inst_offset = (offset + (locals_stack_size - offsets [i]));
5576 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i);
5577 CFG_DEBUG(3) mono_print_tree_nl (inst);
5581 // TODO check how offsets[i] are calculated
5582 // it seems they are points to the end on data. Like 8, but it actually - 0
5584 offset += locals_stack_size; //+8;
5586 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) {
5587 // g_assert (!cfg->arch.omit_fp);
5588 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
5589 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
5592 // Save offset for caller saved regs
5593 cfg->arch.reg_save_area_offset = offset;
5595 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset, offset);
5597 // Reserve space for caller saved registers
5598 for (i = 0; i < MONO_MAX_IREGS; ++i)
5599 if ((ALPHA_IS_CALLEE_SAVED_REG (i)) &&
5600 (cfg->used_int_regs & (1 << i)))
5602 offset += sizeof (gpointer);
5605 // Save offset to args regs
5606 cfg->arch.args_save_area_offset = offset;
5608 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset, offset);
5610 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5612 ArgInfo *ainfo = &cinfo->args [i];
5614 switch(ainfo->storage)
5618 case ArgInDoubleReg:
5619 offset += sizeof (gpointer);
5622 offset += ainfo->nregs * sizeof (gpointer);
5629 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5632 // Reserve space for method params
5633 for (i = 0; i < sig->param_count + sig->hasthis; ++i)
5635 inst = cfg->args [i];
5637 if (inst->opcode != OP_REGVAR)
5639 ArgInfo *ainfo = &cinfo->args [i];
5640 gboolean inreg = TRUE;
5643 if (sig->hasthis && (i == 0))
5644 arg_type = &mono_defaults.object_class->byval_arg;
5646 arg_type = sig->params [i - sig->hasthis];
5648 /* FIXME: Allocate volatile arguments to registers */
5649 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
5653 * Under AMD64, all registers used to pass arguments to functions
5654 * are volatile across calls. For Alpha too.
5655 * FIXME: Optimize this.
5659 if (inreg && (ainfo->storage == ArgInIReg)
5660 //&& cfg->used_int_regs & (1 << ainfo->reg)
5664 if (//(ainfo->storage == ArgInIReg) ||
5665 (ainfo->storage == ArgInFloatReg) ||
5666 (ainfo->storage == ArgInDoubleReg) ||
5667 (ainfo->storage == ArgValuetypeInReg))
5670 inst->opcode = OP_REGOFFSET;
5672 switch (ainfo->storage)
5676 case ArgInDoubleReg:
5677 inst->opcode = OP_REGVAR;
5678 inst->dreg = ainfo->reg;
5681 // g_assert (!cfg->arch.omit_fp);
5682 inst->opcode = OP_REGOFFSET;
5683 inst->inst_basereg = cfg->frame_reg;
5685 // "offset" here will point to the end of
5686 // array of saved ret,locals, args
5687 // Ideally it would point to "a7"
5688 inst->inst_offset = ainfo->offset + offset;
5690 case ArgValuetypeInReg:
5700 if (!inreg && (ainfo->storage != ArgOnStack))
5702 inst->opcode = OP_REGOFFSET;
5703 inst->inst_basereg = cfg->frame_reg;
5705 /* These arguments are saved to the stack in the prolog */
5706 /*if (cfg->arch.omit_fp) {
5707 inst->inst_offset = offset;
5708 offset += (ainfo->storage == ArgValuetypeInReg) ?
5709 2 * sizeof (gpointer) : sizeof (gpointer);
5712 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5713 // 2 * sizeof (gpointer) : sizeof (gpointer);
5715 inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
5716 switch(ainfo->storage)
5719 a_off += ainfo->nslots * 8;
5722 a_off += sizeof (gpointer);
5724 // (/*(ainfo->reg - 16)*/ i * 8);
5730 cfg->stack_offset = offset;
5735 /*========================= End of Function ========================*/
5737 /*------------------------------------------------------------------*/
5739 /* Name - mono_arch_print_tree */
5741 /* Function - Print platform-specific opcode details. */
5743 /* Returns - 1 - opcode details have been printed */
5744 /* 0 - opcode details have not been printed */
5746 /*------------------------------------------------------------------*/
5749 mono_arch_print_tree (MonoInst *tree, int arity)
5753 ALPHA_DEBUG("mono_arch_print_tree");
5755 switch (tree->opcode) {
5762 /*========================= End of Function ========================*/
5766 ** mono_arch_get_vcall_slot_addr
5767 ** is called by mono_magic_trampoline to determine that the JIT compiled
5768 ** method is called via vtable slot. We need to analyze call sequence
5769 ** and determine that. In case it is true - we need to return address
5772 ** code - points to the next instruction after call
5773 ** reg - points to saved regs before the call (this is done
5774 ** by mono_magic_trampoline function
5778 mono_arch_get_vcall_slot_addr (guint8* code, mgreg_t *regs)
5780 unsigned int *pc = (unsigned int *)code;
5782 int start_index = -2;
5784 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5787 // Check if we have parameters on stack
5788 if ((pc[-2] & 0xFFFF0000) == 0x23DE0000) // lda sp,-n(sp)
5791 // Check for (call_membase):
5792 // -4: mov v0,a0 - load this ???
5793 // -3: ldq v0,0(v0) - load vtable
5794 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5795 if ((pc[start_index-1] & 0xFC00FFFF) == 0xA4000000 &&
5796 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5799 disp = pc[start_index] & 0xFFFF;
5800 reg = (pc[start_index-1] >> AXP_REG1_SHIFT) & AXP_REG_MASK;
5801 //reg = 0; // For now
5803 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5805 return (gpointer)(((guint64)(regs [reg])) + disp);
5808 // Check for interface call
5811 // -3: ldq v0,-n(v0)
5812 // -2: ldq t12,0(v0)
5813 if ((pc[start_index-2] & 0xFC00FFFF) == 0xA4000000 &&
5814 (pc[start_index-1] & 0xFFFF0000) == 0xA4000000 &&
5815 (pc[start_index] & 0xFFFF0000) == 0xA7600000
5818 disp = pc[start_index] & 0xFFFF;;
5821 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5823 return (gpointer)(((guint64)(regs [reg])) + disp);
5830 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
5832 unsigned int *pc = (unsigned int *)code;
5834 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_this_arg_from_call] code: %p regs: %p",
5837 if (MONO_TYPE_ISSTRUCT (sig->ret))
5838 return (gpointer)regs [alpha_a1];
5840 return (gpointer)regs [alpha_a0];
5844 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5846 unsigned int *code, *start;
5847 MonoDomain *domain = mono_domain_get ();
5850 ALPHA_PRINT g_debug("ALPHA_CHECK: [mono_arch_get_delegate_invoke_impl]");
5852 /* FIXME: Support more cases */
5853 if (MONO_TYPE_ISSTRUCT (sig->ret))
5860 mono_arch_get_patch_offset (guint8 *code)
5866 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5868 /* FIXME: implement */
5869 g_assert_not_reached ();