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 gboolean tls_offset_inited
= FALSE
;
77 static int appdomain_tls_offset
= -1,
79 thread_tls_offset
= -1;
81 pthread_key_t lmf_addr_key
;
83 gboolean lmf_addr_key_inited
= FALSE
;
86 mono_breakpoint_info
[MONO_BREAKPOINT_ARRAY_SIZE
];
88 /*====================== End of Global Variables ===================*/
90 gpointer
mono_arch_get_lmf_addr (void);
97 ArgValuetypeInReg
, // ??
108 /* Only if storage == ArgAggregate */
110 //AggregateType atype; // So far use only AggregateNormal
116 // guint32 struct_ret; /// ???
120 gboolean need_stack_align
;
127 static CallInfo
* get_call_info (MonoGenericSharingContext
*gsctx
, MonoMethodSignature
*sig
, gboolean is_pinvoke
);
128 static unsigned int *emit_call(MonoCompile
*cfg
, unsigned int *code
,
129 guint32 patch_type
, gconstpointer data
);
132 static int param_regs
[] =
139 //static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
142 add_general (guint32
*gr
, guint32
*stack_size
, ArgInfo
*ainfo
)
144 ainfo
->offset
= *stack_size
;
146 if (*gr
>= PARAM_REGS
)
148 ainfo
->storage
= ArgOnStack
;
149 (*stack_size
) += sizeof (gpointer
);
153 ainfo
->storage
= ArgInIReg
;
154 ainfo
->reg
= param_regs
[*gr
];
159 #define FLOAT_PARAM_REGS 6
160 static int fparam_regs
[] = { alpha_fa0
, alpha_fa1
, alpha_fa2
, alpha_fa3
,
161 alpha_fa4
, alpha_fa5
};
164 add_float (guint32
*gr
, guint32
*stack_size
, ArgInfo
*ainfo
,
167 ainfo
->offset
= *stack_size
;
169 if (*gr
>= FLOAT_PARAM_REGS
)
171 ainfo
->storage
= ArgOnStack
;
172 (*stack_size
) += sizeof (gpointer
);
176 /* A double register */
178 ainfo
->storage
= ArgInDoubleReg
;
180 ainfo
->storage
= ArgInFloatReg
;
182 ainfo
->reg
= fparam_regs
[*gr
];
188 add_valuetype (MonoGenericSharingContext
*gsctx
, MonoMethodSignature
*sig
, ArgInfo
*ainfo
, MonoType
*type
,
190 guint32
*gr
, guint32
*fr
, guint32
*stack_size
)
194 MonoMarshalType
*info
;
195 //gboolean is_hfa = TRUE;
196 //guint32 hfa_type = 0;
198 klass
= mono_class_from_mono_type (type
);
199 if (type
->type
== MONO_TYPE_TYPEDBYREF
)
200 size
= 3 * sizeof (gpointer
);
201 else if (sig
->pinvoke
)
202 size
= mono_type_native_stack_size (&klass
->byval_arg
, NULL
);
204 size
= mini_type_stack_size (gsctx
, &klass
->byval_arg
, NULL
);
206 if (!sig
->pinvoke
|| (size
== 0) || is_return
) {
207 /* Allways pass in memory */
208 ainfo
->offset
= *stack_size
;
209 *stack_size
+= ALIGN_TO (size
, 8);
210 ainfo
->storage
= ArgOnStack
;
215 info
= mono_marshal_load_type_info (klass
);
218 ainfo
->storage
= ArgAggregate
;
219 //ainfo->atype = AggregateNormal;
222 /* This also handles returning of TypedByRef used by some icalls */
225 ainfo
->reg
= IA64_R8
;
226 ainfo
->nregs
= (size
+ 7) / 8;
227 ainfo
->nslots
= ainfo
->nregs
;
234 ainfo
->reg
= param_regs
[*gr
];
235 ainfo
->offset
= *stack_size
;
236 ainfo
->nslots
= (size
+ 7) / 8;
238 if (((*gr
) + ainfo
->nslots
) <= 6) {
239 /* Fits entirely in registers */
240 ainfo
->nregs
= ainfo
->nslots
;
241 (*gr
) += ainfo
->nregs
;
245 ainfo
->nregs
= 6 - (*gr
);
247 (*stack_size
) += (ainfo
->nslots
- ainfo
->nregs
) * 8;
251 // This function is called from mono_arch_call_opcode and
252 // should determine which registers will be used to do the call
253 // For Alpha we could calculate number of parameter used for each
254 // call and allocate space in stack only for whose "a0-a5" registers
255 // that will be used in calls
257 add_outarg_reg (MonoCompile
*cfg
, MonoCallInst
*call
, MonoInst
*arg
,
258 ArgStorage storage
, int reg
, MonoInst
*tree
)
263 arg
->opcode
= OP_OUTARG_REG
;
264 arg
->inst_left
= tree
;
265 arg
->inst_right
= (MonoInst
*)call
;
266 arg
->backend
.reg3
= reg
;
267 call
->used_iregs
|= 1 << reg
;
270 arg
->opcode
= OP_OUTARG_FREG
;
271 arg
->inst_left
= tree
;
272 arg
->inst_right
= (MonoInst
*)call
;
273 arg
->backend
.reg3
= reg
;
274 call
->used_fregs
|= 1 << reg
;
277 arg
->opcode
= OP_OUTARG_FREG
;
278 arg
->inst_left
= tree
;
279 arg
->inst_right
= (MonoInst
*)call
;
280 arg
->backend
.reg3
= reg
;
281 call
->used_fregs
|= 1 << reg
;
284 g_assert_not_reached ();
289 insert_after_ins (MonoBasicBlock
*bb
, MonoInst
*ins
, MonoInst
*to_insert
)
294 bb
->code
= to_insert
;
295 to_insert
->next
= ins
;
299 to_insert
->next
= ins
->next
;
300 ins
->next
= to_insert
;
304 static void add_got_entry(MonoCompile
*cfg
, AlphaGotType ge_type
,
305 AlphaGotData ge_data
,
306 int ip
, MonoJumpInfoType type
, gconstpointer target
)
308 AlphaGotEntry
*AGE
= mono_mempool_alloc (cfg
->mempool
,
309 sizeof (AlphaGotEntry
));
316 AGE
->value
.data
.i
= ge_data
.data
.i
;
319 AGE
->value
.data
.l
= ge_data
.data
.l
;
322 AGE
->value
.data
.p
= ge_data
.data
.p
;
325 AGE
->value
.data
.f
= ge_data
.data
.f
;
328 AGE
->value
.data
.d
= ge_data
.data
.d
;
331 AGE
->value
.data
.l
= ip
;
337 if (type
!= MONO_PATCH_INFO_NONE
)
339 mono_add_patch_info(cfg
, ip
, type
, target
);
340 AGE
->patch_info
= cfg
->patch_info
;
345 if (AGE
->type
!= GT_LD_GTADDR
)
347 mono_add_patch_info(cfg
, ip
, MONO_PATCH_INFO_GOT_OFFSET
, 0);
348 AGE
->got_patch_info
= cfg
->patch_info
;
351 AGE
->next
= cfg
->arch
.got_data
;
353 cfg
->arch
.got_data
= AGE
;
356 /*------------------------------------------------------------------*/
358 /* Name - mono_arch_create_vars */
365 * cfg - pointer to compile unit
368 * This method is called right before starting converting compiled
369 * method to IR. I guess we could find out how many arguments we
370 * should expect, what type and what return value would be.
371 * After that we could correct "cfg" structure, or "arch" part of
375 /*------------------------------------------------------------------*/
378 mono_arch_create_vars (MonoCompile
*cfg
)
380 MonoMethodSignature
*sig
;
383 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_create_vars");
385 sig
= mono_method_signature (cfg
->method
);
387 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
, FALSE
);
389 if (cinfo
->ret
.storage
== ArgValuetypeInReg
)
390 cfg
->ret_var_is_local
= TRUE
;
396 /*------------------------------------------------------------------*/
398 /* Name - mono_arch_get_lmf_addr */
404 /*------------------------------------------------------------------*/
407 mono_arch_get_lmf_addr (void)
409 ALPHA_DEBUG("mono_arch_get_lmf_addr");
411 return pthread_getspecific (lmf_addr_key
);
414 /*========================= End of Function ========================*/
416 /*------------------------------------------------------------------*/
418 /* Name - mono_arch_free_jit_tls_data */
420 /* Function - Free tls data. */
422 /*------------------------------------------------------------------*/
425 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
427 ALPHA_DEBUG("mono_arch_free_jit_tls_data");
430 /*========================= End of Function ========================*/
432 // This peephole function is called before "local_regalloc" method
433 // TSV_TODO - Check what we need to move here
435 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
437 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_1 pass\n");
440 // This peephole function is called after "local_regalloc" method
442 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
444 MonoInst
*ins
, *n
, *last_ins
= NULL
;
447 CFG_DEBUG(3) g_print ("ALPHA: PEEPHOLE_2 pass\n");
449 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
457 * OP_MOVE reg, reg except special case (mov at, at)
459 if (ins
->dreg
== ins
->sreg1
&&
460 ins
->dreg
!= alpha_at
)
462 MONO_DELETE_INS (bb
, ins
);
472 if (last_ins
&& last_ins
->opcode
== OP_MOVE
&&
473 ins
->sreg1
== last_ins
->dreg
&&
474 last_ins
->dreg
!= alpha_at
&&
475 ins
->dreg
== last_ins
->sreg1
)
477 MONO_DELETE_INS (bb
, ins
);
484 /* remove unnecessary multiplication with 1 */
485 if (ins
->inst_imm
== 1)
487 if (ins
->dreg
!= ins
->sreg1
)
489 ins
->opcode
= OP_MOVE
;
493 MONO_DELETE_INS (bb
, ins
);
500 case OP_LOADI8_MEMBASE
:
501 case OP_LOAD_MEMBASE
:
503 * Note: if reg1 = reg2 the load op is removed
505 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
506 * OP_LOADI8_MEMBASE offset(basereg), reg2
508 * OP_STOREI8_MEMBASE_REG reg1, offset(basereg)
512 (last_ins
->opcode
== OP_STOREI8_MEMBASE_REG
||
513 last_ins
->opcode
== OP_STORE_MEMBASE_REG
) &&
514 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
515 ins
->inst_offset
== last_ins
->inst_offset
)
517 if (ins
->dreg
== last_ins
->sreg1
)
519 MONO_DELETE_INS (bb
, ins
);
524 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
525 ins
->opcode
= OP_MOVE
;
526 ins
->sreg1
= last_ins
->sreg1
;
532 case OP_LOAD_MEMBASE
:
533 case OP_LOADI4_MEMBASE
:
535 * Note: if reg1 = reg2 the load op is removed
537 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
538 * OP_LOAD_MEMBASE offset(basereg), reg2
540 * OP_STORE_MEMBASE_REG reg1, offset(basereg)
543 if (last_ins
&& (last_ins
->opcode
== OP_STOREI4_MEMBASE_REG
544 /*|| last_ins->opcode == OP_STORE_MEMBASE_REG*/) &&
545 ins
->inst_basereg
== last_ins
->inst_destbasereg
&&
546 ins
->inst_offset
== last_ins
->inst_offset
)
548 if (ins
->dreg
== last_ins
->sreg1
)
550 MONO_DELETE_INS (bb
, ins
);
555 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
556 ins
->opcode
= OP_MOVE
;
557 ins
->sreg1
= last_ins
->sreg1
;
561 * Note: reg1 must be different from the basereg in the second load
562 * Note: if reg1 = reg2 is equal then second load is removed
564 * OP_LOAD_MEMBASE offset(basereg), reg1
565 * OP_LOAD_MEMBASE offset(basereg), reg2
567 * OP_LOAD_MEMBASE offset(basereg), reg1
571 if (last_ins
&& (last_ins
->opcode
== OP_LOADI4_MEMBASE
572 || last_ins
->opcode
== OP_LOAD_MEMBASE
) &&
573 ins
->inst_basereg
!= last_ins
->dreg
&&
574 ins
->inst_basereg
== last_ins
->inst_basereg
&&
575 ins
->inst_offset
== last_ins
->inst_offset
)
577 if (ins
->dreg
== last_ins
->dreg
)
579 MONO_DELETE_INS (bb
, ins
);
584 ins
->opcode
= OP_MOVE
;
585 ins
->sreg1
= last_ins
->dreg
;
588 //g_assert_not_reached ();
598 bb
->last_ins
= last_ins
;
601 // Convert to opposite branch opcode
602 static guint16
cvt_branch_opcode(guint16 opcode
)
607 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BEQ -> CEE_BNE_UN\n");
612 //printf("ALPHA: Branch cvt: CEE_CGT_UN -> OP_IBEQ\n");
616 //printf("ALPHA: Branch cvt: OP_LCGT_UN -> OP_IBEQ\n");
620 //printf("ALPHA: Branch cvt: OP_CGT_UN -> OP_IBEQ\n");
624 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBEQ -> OP_IBNE_UN\n");
628 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_FBEQ -> OP_FBNE_UN\n");
632 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_FBNE_UN -> OP_FBEQ\n");
636 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBNE_UN -> OP_IBEQ\n");
640 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BNE_UN -> OP_IBEQ\n");
644 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBLE -> OP_IBNE_UN\n");
648 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBLE_UN -> OP_IBNE_UN\n");
652 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BLE -> OP_IBNE_UN\n");
656 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BLE_UN -> OP_IBNE_UN\n");
660 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBLT -> OP_IBNE_UN\n");
664 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BLT -> OP_IBNE_UN\n");
668 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BLT_UN -> OP_IBNE_UN\n");
672 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBLT_UN -> OP_IBNE_UN\n");
676 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBGE -> OP_IBEQ\n");
680 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BGE -> OP_IBEQ\n");
684 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BGT -> OP_IBEQ\n");
688 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBGT -> OP_IBEQ\n");
692 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BGT_UN -> OP_IBEQ\n");
696 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBGT_UN -> OP_IBEQ\n");
700 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: CEE_BGE_UN -> OP_IBEQ\n");
704 ALPHA_PRINT
g_debug("ALPHA: Branch cvt: OP_IBGE_UN -> OP_IBEQ\n");
711 ALPHA_PRINT
g_debug("ALPHA: WARNING: No Branch cvt for: %d\n", opcode
);
716 typedef enum { EQ
, ULE
, LE
, LT
, ULT
} ALPHA_CMP_OPS
;
718 static guint16
cvt_cmp_opcode(guint16 opcode
, ALPHA_CMP_OPS cond
)
724 /* Use inssel-alpha.brg to handle cmp+b<cond> -> cmp<cond>+b<cond> cvt */
735 return OP_ALPHA_CMP_EQ
;
737 return OP_ALPHA_CMP_ULE
;
739 return OP_ALPHA_CMP_LE
;
741 return OP_ALPHA_CMP_LT
;
743 return OP_ALPHA_CMP_ULT
;
748 case OP_ICOMPARE_IMM
:
754 return OP_ALPHA_CMP_IMM_EQ
;
756 return OP_ALPHA_CMP_IMM_ULE
;
758 return OP_ALPHA_CMP_IMM_LE
;
760 return OP_ALPHA_CMP_IMM_LT
;
762 return OP_ALPHA_CMP_IMM_ULT
;
767 g_assert_not_reached();
772 static void cvt_cmp_branch(MonoInst
*curr
, MonoInst
*next
)
774 // Instead of compare+b<cond>,
775 // Alpha has compare<cond>+br<cond>
776 // we need to convert
777 // Handle floating compare here too
783 // Convert cmp + beq -> cmpeq + bne
784 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, EQ
);
785 next
->opcode
= cvt_branch_opcode(next
->opcode
);
790 // cmp + ibne_un -> cmpeq + beq
791 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, EQ
);
792 next
->opcode
= cvt_branch_opcode(next
->opcode
);
797 // cmp + ible -> cmple + bne, lcmp + ble -> cmple + bne
798 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LE
);
799 next
->opcode
= cvt_branch_opcode(next
->opcode
);
804 // cmp + ible_un -> cmpule + bne, lcmp + ble.un -> cmpule + bne
805 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULE
);
806 next
->opcode
= cvt_branch_opcode(next
->opcode
);
811 // cmp + iblt -> cmplt + bne, lcmp + blt -> cmplt + bne
812 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LT
);
813 next
->opcode
= cvt_branch_opcode(next
->opcode
);
818 // lcmp + blt.un -> cmpult + bne
819 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULT
);
820 next
->opcode
= cvt_branch_opcode(next
->opcode
);
825 // cmp + ibge -> cmplt + beq, lcmp + bge -> cmplt + beq
826 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LT
);
827 next
->opcode
= cvt_branch_opcode(next
->opcode
);
832 //lcmp + bge.un -> cmpult + beq
833 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULT
);
834 next
->opcode
= cvt_branch_opcode(next
->opcode
);
839 // lcmp + bgt -> cmple + beq, cmp + ibgt -> cmple + beq
840 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LE
);
841 next
->opcode
= cvt_branch_opcode(next
->opcode
);
846 // lcmp + bgt -> cmpule + beq, cmp + ibgt -> cmpule + beq
847 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULE
);
848 next
->opcode
= cvt_branch_opcode(next
->opcode
);
854 // cmp + cgt_un -> cmpule + beq
855 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULE
);
860 // cmp + iceq -> cmpeq + bne
861 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, EQ
);
866 // cmp + int_cgt -> cmple + beq
867 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LE
);
872 // cmp + int_clt -> cmplt + bne
873 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LT
);
878 // cmp + int_clt_un -> cmpult + bne
879 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULT
);
883 // The conditional exceptions will be handled in
884 // output_basic_blocks. Here we just determine correct
887 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LE
);
890 case OP_COND_EXC_GT_UN
:
891 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULE
);
895 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, LT
);
898 case OP_COND_EXC_LT_UN
:
899 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULT
);
902 case OP_COND_EXC_LE_UN
:
903 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, ULE
);
906 case OP_COND_EXC_NE_UN
:
907 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, EQ
);
911 curr
->opcode
= cvt_cmp_opcode(curr
->opcode
, EQ
);
916 g_warning("cvt_cmp_branch called with %s(%0X) br opcode",
917 mono_inst_name(next
->opcode
), next
->opcode
);
919 // g_assert_not_reached();
927 * mono_arch_lowering_pass:
929 * Converts complex opcodes into simpler ones so that each IR instruction
930 * corresponds to one machine instruction.
933 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
935 MonoInst
*ins
, *n
, *temp
, *last_ins
= NULL
;
941 * FIXME: Need to add more instructions, but the current machine
942 * description can't model some parts of the composite instructions like
946 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
954 NEW_INS (cfg
, temp
, OP_I8CONST
);
955 temp
->inst_c0
= ins
->inst_imm
;
956 temp
->dreg
= mono_alloc_ireg (cfg
);
961 ins
->opcode
= CEE_MUL
;
964 ins
->opcode
= OP_LDIV
;
967 ins
->opcode
= OP_LREM
;
970 ins
->opcode
= OP_IDIV
;
973 ins
->opcode
= OP_IREM
;
977 ins
->sreg2
= temp
->dreg
;
985 // Instead of compare+b<cond>/fcompare+b<cond>,
986 // Alpha has compare<cond>+br<cond>/fcompare<cond>+br<cond>
987 // we need to convert
990 cvt_cmp_branch(ins
, next
);
995 if (!alpha_is_imm (ins
->inst_imm
))
997 NEW_INS (cfg
, temp
, OP_I8CONST
);
998 temp
->inst_c0
= ins
->inst_imm
;
999 temp
->dreg
= mono_alloc_ireg (cfg
);
1000 ins
->opcode
= OP_COMPARE
;
1001 ins
->sreg2
= temp
->dreg
;
1003 // We should try to reevaluate new IR opcode
1009 cvt_cmp_branch(ins
, next
);
1013 case OP_ICOMPARE_IMM
:
1014 if (!alpha_is_imm (ins
->inst_imm
))
1016 NEW_INS (cfg
, temp
, OP_ICONST
);
1017 temp
->inst_c0
= ins
->inst_imm
;
1018 temp
->dreg
= mono_alloc_ireg (cfg
);
1019 ins
->opcode
= OP_ICOMPARE
;
1020 ins
->sreg2
= temp
->dreg
;
1022 // We should try to reevaluate new IR opcode
1028 cvt_cmp_branch(ins
, next
);
1032 case OP_STORE_MEMBASE_IMM
:
1033 case OP_STOREI8_MEMBASE_IMM
:
1034 if (ins
->inst_imm
!= 0)
1036 NEW_INS (cfg
, temp
, OP_I8CONST
);
1037 temp
->inst_c0
= ins
->inst_imm
;
1038 temp
->dreg
= mono_alloc_ireg (cfg
);
1039 ins
->opcode
= OP_STOREI8_MEMBASE_REG
;
1040 ins
->sreg1
= temp
->dreg
;
1044 case OP_STOREI4_MEMBASE_IMM
:
1045 if (ins
->inst_imm
!= 0)
1048 NEW_INS (cfg
, temp
, OP_ICONST
);
1049 temp
->inst_c0
= ins
->inst_imm
;
1050 temp
->dreg
= mono_alloc_ireg (cfg
);
1051 ins
->opcode
= OP_STOREI4_MEMBASE_REG
;
1052 ins
->sreg1
= temp
->dreg
;
1056 case OP_STOREI1_MEMBASE_IMM
:
1057 if (ins
->inst_imm
!= 0 || !bwx_supported
)
1060 NEW_INS (cfg
, temp
, OP_ICONST
);
1061 temp
->inst_c0
= ins
->inst_imm
;
1062 temp
->dreg
= mono_alloc_ireg (cfg
);
1063 ins
->opcode
= OP_STOREI1_MEMBASE_REG
;
1064 ins
->sreg1
= temp
->dreg
;
1068 case OP_STOREI2_MEMBASE_IMM
:
1069 if (ins
->inst_imm
!= 0 || !bwx_supported
)
1072 NEW_INS (cfg
, temp
, OP_ICONST
);
1073 temp
->inst_c0
= ins
->inst_imm
;
1074 temp
->dreg
= mono_alloc_ireg (cfg
);
1075 ins
->opcode
= OP_STOREI2_MEMBASE_REG
;
1076 ins
->sreg1
= temp
->dreg
;
1087 case OP_ISHR_UN_IMM
:
1088 if (!alpha_is_imm(ins
->inst_imm
))
1091 NEW_INS (cfg
, temp
, OP_ICONST
);
1092 temp
->inst_c0
= ins
->inst_imm
;
1093 temp
->dreg
= mono_alloc_ireg (cfg
);
1098 ins
->opcode
= OP_IADD
;
1101 ins
->opcode
= OP_ISUB
;
1104 ins
->opcode
= OP_IAND
;
1107 ins
->opcode
= OP_IOR
;
1110 ins
->opcode
= OP_IXOR
;
1113 ins
->opcode
= OP_ISHL
;
1116 ins
->opcode
= OP_ISHR
;
1118 case OP_ISHR_UN_IMM
:
1119 ins
->opcode
= OP_ISHR_UN
;
1125 ins
->sreg2
= temp
->dreg
;
1131 if (!alpha_is_imm(ins
->inst_imm
))
1134 NEW_INS (cfg
, temp
, OP_ICONST
);
1135 temp
->inst_c0
= ins
->inst_imm
;
1136 temp
->dreg
= mono_alloc_ireg (cfg
);
1141 ins
->opcode
= CEE_ADD
;
1144 ins
->opcode
= CEE_SUB
;
1147 ins
->opcode
= CEE_AND
;
1150 ins
->opcode
= CEE_SHL
;
1156 ins
->sreg2
= temp
->dreg
;
1160 if (!alpha_is_imm(ins
->inst_imm
))
1163 NEW_INS(cfg
, temp
, OP_ICONST
);
1164 temp
->inst_c0
= ins
->inst_imm
;
1165 temp
->dreg
= mono_alloc_ireg (cfg
);
1166 ins
->sreg2
= temp
->dreg
;
1167 ins
->opcode
= OP_LSHR
;
1171 if (!alpha_is_imm(ins
->inst_imm
))
1174 NEW_INS(cfg
, temp
, OP_ICONST
);
1175 temp
->inst_c0
= ins
->inst_imm
;
1176 temp
->dreg
= mono_alloc_ireg (cfg
);
1177 ins
->sreg2
= temp
->dreg
;
1178 ins
->opcode
= OP_LSHL
;
1190 bb
->last_ins
= last_ins
;
1192 bb
->max_vreg
= cfg
->next_vreg
;
1195 /*========================= End of Function ========================*/
1197 #define AXP_GENERAL_REGS 6
1198 #define AXP_MIN_STACK_SIZE 24
1200 /* A typical Alpha stack frame looks like this */
1202 fun: // called from outside the module.
1203 ldgp gp,0(pv) // load the global pointer
1204 fun..ng: // called from inside the module.
1205 lda sp, -SIZE( sp ) // grow the stack downwards.
1207 stq ra, 0(sp) // save the return address.
1209 stq s0, 8(sp) // callee-saved registers.
1210 stq s1, 16(sp) // ...
1212 // Move the arguments to the argument registers...
1214 mov addr, pv // Load the callee address
1215 jsr ra, (pv) // call the method.
1216 ldgp gp, 0(ra) // restore gp
1218 // return value is in v0
1220 ldq ra, 0(sp) // free stack frame
1221 ldq s0, 8(sp) // restore callee-saved registers.
1223 ldq sp, 32(sp) // restore stack pointer
1225 ret zero, (ra), 1 // return.
1228 // our call must look like this.
1234 lda sp, -SIZE(sp) // grow stack SIZE bytes.
1235 stq ra, SIZE-48(sp) // store ra
1236 stq fp, SIZE-40(sp) // store fp (frame pointer)
1237 stq a0, SIZE-32(sp) // store args. a0 = func
1238 stq a1, SIZE-24(sp) // a1 = retval
1239 stq a2, SIZE-16(sp) // a2 = this
1240 stq a3, SIZE-8(sp) // a3 = args
1241 mov sp, fp // set frame pointer
1261 jsr ra, (pv) // call func
1262 ldgp gp, 0(ra) // restore gp.
1263 mov v0, t1 // move return value into t1
1266 ldq t0, SIZE-24(fp) // load retval into t2
1267 stl t1, 0(t0) // store value.
1278 * emit_load_volatile_arguments:
1280 * Load volatile arguments from the stack to the original input registers.
1281 * Required before a tail call.
1283 static unsigned int*
1284 emit_load_volatile_arguments (MonoCompile
*cfg
, unsigned int *code
)
1286 MonoMethod
*method
= cfg
->method
;
1287 MonoMethodSignature
*sig
;
1292 /* FIXME: Generate intermediate code instead */
1294 sig
= mono_method_signature (method
);
1296 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
, FALSE
);
1298 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
1299 if ((cinfo
->ret
.storage
== ArgInIReg
) &&
1300 (cfg
->ret
->opcode
!= OP_REGVAR
))
1302 alpha_ldq(code
, cinfo
->ret
.reg
, cfg
->ret
->inst_basereg
,
1303 cfg
->ret
->inst_offset
);
1307 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
)
1309 ArgInfo
*ainfo
= &cinfo
->args
[i
];
1310 MonoInst
*inst
= cfg
->args
[i
];
1312 switch(ainfo
->storage
)
1315 // We need to save all used a0-a5 params
1316 //for (i=0; i<PARAM_REGS; i++)
1318 // if (i < cinfo->reg_usage)
1320 //alpha_stq(code, ainfo->reg, alpha_fp, offset);
1321 alpha_ldq(code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
1323 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1324 ainfo
->reg
, inst
->inst_offset
/*offset*/);
1328 case ArgInDoubleReg
:
1330 // We need to save all used af0-af5 params
1331 //for (i=0; i<PARAM_REGS; i++)
1333 // if (i < cinfo->freg_usage)
1335 switch(cinfo
->args
[i
].storage
)
1338 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1339 alpha_lds(code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
1341 case ArgInDoubleReg
:
1342 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1343 alpha_ldt(code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
1349 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1350 ainfo
->reg
, /*offset*/inst
->inst_offset
);
1359 /*------------------------------------------------------------------*/
1361 /* Name - mono_arch_emit_prolog */
1363 /* Function - Create the instruction sequence for a function */
1366 * How to handle consts and method addreses:
1367 * For method we will allocate array of qword after method epiloge.
1368 * These qword will hold readonly info to method to properly to run.
1369 * For example: qword constants, method addreses
1370 * GP will point to start of data. Offsets to the data will be equal
1371 * to "address" of data - start of GP. (GP = 0 during method jiting).
1372 * GP is easily calculated from passed PV (method start address).
1373 * The patch will update GP loadings.
1374 * The GOT section should be more than 32Kb.
1375 * The patch code should put proper offset since the real position of
1376 * qword array will be known after the function epiloge.
1378 /*------------------------------------------------------------------*/
1381 mono_arch_emit_prolog (MonoCompile
*cfg
)
1383 MonoMethod
*method
= cfg
->method
;
1384 MonoMethodSignature
*sig
= mono_method_signature (method
);
1385 //int alloc_size, code_size, max_offset, quad;
1388 int i
, stack_size
, offset
;
1389 gint32 lmf_offset
= cfg
->arch
.lmf_offset
;
1391 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_prolog");
1393 // FIXME: Use just one field to hold calculated stack size
1394 cfg
->arch
.stack_size
= stack_size
= cfg
->stack_offset
;
1395 cfg
->arch
.got_data
= 0;
1397 cfg
->code_size
= 512;
1399 code
= (unsigned int *)g_malloc(cfg
->code_size
);
1400 cfg
->native_code
= (void *)code
;
1402 // Emit method prolog
1403 // Calculate GP from passed PV, allocate stack
1405 alpha_ldah( code
, alpha_gp
, alpha_pv
, 0 );
1406 alpha_lda( code
, alpha_gp
, alpha_gp
, 0 ); // ldgp gp, 0(pv)
1407 alpha_lda( code
, alpha_sp
, alpha_sp
, -(stack_size
) );
1409 offset
= cfg
->arch
.params_stack_size
;
1411 /* store call convention parameters on stack */
1412 alpha_stq( code
, alpha_ra
, alpha_sp
, (offset
+ 0) ); // RA
1413 alpha_stq( code
, alpha_fp
, alpha_sp
, (offset
+ 8) ); // FP
1415 /* set the frame pointer */
1416 alpha_mov1( code
, alpha_sp
, alpha_fp
);
1419 if (method
->save_lmf
)
1422 alpha_stq(code
, alpha_pv
, alpha_fp
,
1423 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, eip
)));
1425 alpha_stq(code
, alpha_sp
, alpha_fp
,
1426 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, rsp
)));
1428 alpha_stq(code
, alpha_fp
, alpha_fp
,
1429 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, ebp
)));
1431 alpha_stq(code
, alpha_gp
, alpha_fp
,
1432 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, rgp
)));
1435 alpha_stq(code
, alpha_pv
, alpha_fp
,
1436 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, method
)));
1439 /* Save (global) regs */
1440 offset
= cfg
->arch
.reg_save_area_offset
;
1442 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1443 if (ALPHA_IS_CALLEE_SAVED_REG (i
) &&
1444 (cfg
->used_int_regs
& (1 << i
)) &&
1445 !( ALPHA_ARGS_REGS
& (1 << i
)) )
1447 alpha_stq(code
, i
, alpha_fp
, offset
);
1448 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1453 offset
= cfg
->arch
.args_save_area_offset
;
1455 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
, FALSE
);
1457 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
1459 if ((cinfo
->ret
.storage
== ArgInIReg
) &&
1460 (cfg
->ret
->opcode
!= OP_REGVAR
))
1462 /* Save volatile arguments to the stack */
1463 alpha_stq(code
, cinfo
->ret
.reg
, cfg
->ret
->inst_basereg
,
1464 cfg
->ret
->inst_offset
);
1468 /* Keep this in sync with emit_load_volatile_arguments */
1469 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
)
1471 ArgInfo
*ainfo
= &cinfo
->args
[i
];
1472 MonoInst
*inst
= cfg
->args
[i
];
1475 switch(ainfo
->storage
)
1478 // We need to save all used a0-a5 params
1480 if (inst
->opcode
== OP_REGVAR
)
1482 alpha_mov1(code
, ainfo
->reg
, inst
->dreg
);
1483 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d in reg %d\n",
1484 ainfo
->reg
, inst
->dreg
);
1488 alpha_stq(code
, ainfo
->reg
, inst
->inst_basereg
,
1491 CFG_DEBUG(3) g_print("ALPHA: Saved int arg reg %d at offset: %0lx\n",
1492 ainfo
->reg
, inst
->inst_offset
);
1500 for(j
=0; j
<ainfo
->nregs
; j
++)
1502 CFG_DEBUG(3) g_print("ALPHA: Saved aggregate arg reg %d at offset: %0lx\n",
1503 ainfo
->reg
+ j
, inst
->inst_offset
+ (8*j
));
1504 alpha_stq(code
, (ainfo
->reg
+j
), inst
->inst_basereg
,
1505 (inst
->inst_offset
+ (8*j
)));
1510 case ArgInDoubleReg
:
1512 // We need to save all used af0-af5 params
1514 switch(cinfo
->args
[i
].storage
)
1517 //alpha_sts(code, ainfo->reg, alpha_fp, offset);
1518 alpha_sts(code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
1520 case ArgInDoubleReg
:
1521 //alpha_stt(code, ainfo->reg, alpha_fp, offset);
1522 alpha_stt(code
, ainfo
->reg
, inst
->inst_basereg
, inst
->inst_offset
);
1528 CFG_DEBUG(3) g_print("ALPHA: Saved float arg reg %d at offset: %0lx\n",
1529 ainfo
->reg
, /*offset*/inst
->inst_offset
);
1536 offset
= cfg
->arch
.reg_save_area_offset
;
1539 for (i = 0; i < MONO_MAX_VREGS; ++i)
1540 if (ALPHA_IS_CALLEE_SAVED_REG (i) &&
1541 (cfg->used_int_regs & (1 << i)) &&
1542 !( ALPHA_ARGS_REGS & (1 << i)) )
1544 alpha_stq(code, i, alpha_fp, offset);
1545 CFG_DEBUG(3) g_print("ALPHA: Saved caller reg %d at offset: %0x\n",
1550 // TODO - check amd64 code for "Might need to attach the thread to the JIT"
1552 if (method
->save_lmf
)
1555 * The call might clobber argument registers, but they are already
1556 * saved to the stack/global regs.
1559 code
= emit_call (cfg
, code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
1560 (gpointer
)"mono_get_lmf_addr");
1563 alpha_stq(code
, alpha_r0
, alpha_fp
,
1564 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
1565 // Load "previous_lmf" member of MonoLMF struct
1566 alpha_ldq(code
, alpha_r1
, alpha_r0
, 0);
1568 // Save it to MonoLMF struct
1569 alpha_stq(code
, alpha_r1
, alpha_fp
,
1570 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
1573 alpha_lda(code
, alpha_r1
, alpha_fp
, lmf_offset
);
1574 alpha_stq(code
, alpha_r1
, alpha_r0
, 0);
1579 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
1580 code
= mono_arch_instrument_prolog (cfg
, mono_trace_enter_method
,
1583 cfg
->code_len
= ((char *)code
) - ((char *)cfg
->native_code
);
1585 g_assert (cfg
->code_len
< cfg
->code_size
);
1587 return (gint8
*)code
;
1590 /*========================= End of Function ========================*/
1592 /*------------------------------------------------------------------*/
1594 /* Name - mono_arch_flush_register_windows */
1600 /*------------------------------------------------------------------*/
1603 mono_arch_flush_register_windows (void)
1605 ALPHA_DEBUG("mono_arch_flush_register_windows");
1607 /*========================= End of Function ========================*/
1609 /*------------------------------------------------------------------*/
1611 /* Name - mono_arch_regalloc_cost */
1613 /* Function - Determine the cost, in the number of memory */
1614 /* references, of the action of allocating the var- */
1615 /* iable VMV into a register during global register */
1618 /* Returns - Cost */
1620 /*------------------------------------------------------------------*/
1623 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
1625 MonoInst
*ins
= cfg
->varinfo
[vmv
->idx
];
1628 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_regalloc_cost");
1630 if (cfg
->method
->save_lmf
)
1631 /* The register is already saved */
1632 /* substract 1 for the invisible store in the prolog */
1633 return (ins
->opcode
== OP_ARG
) ? 1 : 0;
1636 return (ins
->opcode
== OP_ARG
) ? 2 : 1;
1639 /*========================= End of Function ========================*/
1643 ** This method emits call sequience
1646 static unsigned int *
1647 emit_call(MonoCompile
*cfg
, unsigned int *code
,
1648 guint32 patch_type
, gconstpointer data
)
1651 AlphaGotData ge_data
;
1653 offset
= (char *)code
- (char *)cfg
->native_code
;
1655 ge_data
.data
.p
= (void *)data
;
1656 add_got_entry(cfg
, GT_PTR
, ge_data
,
1657 offset
, patch_type
, data
);
1659 // Load call address into PV
1660 alpha_ldq(code
, alpha_pv
, alpha_gp
, 0);
1663 alpha_jsr(code
, alpha_ra
, alpha_pv
, 0);
1665 offset
= (char *)code
- (char *)cfg
->native_code
;
1668 ALPHA_LOAD_GP(offset
)
1669 alpha_ldah(code
, alpha_gp
, alpha_ra
, 0);
1670 alpha_lda(code
, alpha_gp
, alpha_gp
, 0);
1675 /*------------------------------------------------------------------*/
1677 /* Name - arch_get_argument_info */
1679 /* Function - Gathers information on parameters such as size, */
1680 /* alignment, and padding. arg_info should be large */
1681 /* enough to hold param_count + 1 entries. */
1683 /* Parameters - @csig - Method signature */
1684 /* @param_count - No. of parameters to consider */
1685 /* @arg_info - An array to store the result info */
1687 /* Returns - Size of the activation frame */
1689 /*------------------------------------------------------------------*/
1692 mono_arch_get_argument_info (MonoMethodSignature
*csig
,
1694 MonoJitArgumentInfo
*arg_info
)
1697 CallInfo
*cinfo
= get_call_info (NULL
, csig
, FALSE
);
1698 guint32 args_size
= cinfo
->stack_usage
;
1700 ALPHA_DEBUG("mono_arch_get_argument_info");
1702 /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
1705 arg_info
[0].offset
= 0;
1708 for (k
= 0; k
< param_count
; k
++)
1710 arg_info
[k
+ 1].offset
= ((k
+ csig
->hasthis
) * 8);
1714 // The size is checked only for valuetype in trace.c
1715 arg_info
[k
+ 1].size
= 8;
1723 /*------------------------------------------------------------------*/
1725 /* Name - mono_arch_emit_epilog */
1727 /* Function - Emit the instructions for a function epilog. */
1729 /*------------------------------------------------------------------*/
1732 mono_arch_emit_epilog (MonoCompile
*cfg
)
1734 MonoMethod
*method
= cfg
->method
;
1737 int max_epilog_size
= 128;
1738 int stack_size
= cfg
->arch
.stack_size
;
1740 gint32 lmf_offset
= cfg
->arch
.lmf_offset
;
1742 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_epilog");
1744 while (cfg
->code_len
+ max_epilog_size
> (cfg
->code_size
- 16))
1746 cfg
->code_size
*= 2;
1747 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
1748 mono_jit_stats
.code_reallocs
++;
1751 code
= (unsigned int *)(cfg
->native_code
+ cfg
->code_len
);
1753 if (mono_jit_trace_calls
!= NULL
&& mono_trace_eval (method
))
1754 code
= mono_arch_instrument_epilog (cfg
, mono_trace_leave_method
,
1757 if (method
->save_lmf
)
1759 /* Restore previous lmf */
1760 alpha_ldq(code
, alpha_at
, alpha_fp
,
1761 (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, previous_lmf
)));
1762 alpha_ldq(code
, alpha_ra
, alpha_fp
,
1763 (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, lmf_addr
)));
1764 alpha_stq(code
, alpha_at
, alpha_ra
, 0);
1768 alpha_mov1( code
, alpha_fp
, alpha_sp
);
1770 // Restore saved regs
1771 offset
= cfg
->arch
.reg_save_area_offset
;
1773 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
)
1774 if (ALPHA_IS_CALLEE_SAVED_REG (i
) &&
1775 (cfg
->used_int_regs
& (1 << i
)) &&
1776 !( ALPHA_ARGS_REGS
& (1 << i
)) )
1778 alpha_ldq(code
, i
, alpha_sp
, offset
);
1779 CFG_DEBUG(3) g_print("ALPHA: Restored caller reg %d at offset: %0x\n",
1784 /* restore fp, ra, sp */
1785 offset
= cfg
->arch
.params_stack_size
;
1787 alpha_ldq( code
, alpha_ra
, alpha_sp
, (offset
+ 0) );
1788 alpha_ldq( code
, alpha_fp
, alpha_sp
, (offset
+ 8) );
1789 alpha_lda( code
, alpha_sp
, alpha_sp
, stack_size
);
1792 alpha_ret( code
, alpha_ra
, 1 );
1794 cfg
->code_len
= ((char *)code
) - ((char *)cfg
->native_code
);
1796 g_assert (cfg
->code_len
< cfg
->code_size
);
1799 /*========================= End of Function ========================*/
1801 /*------------------------------------------------------------------*/
1803 /* Name - mono_arch_emit_exceptions */
1805 /* Function - Emit the blocks to handle exception conditions. */
1807 /*------------------------------------------------------------------*/
1810 mono_arch_emit_exceptions (MonoCompile
*cfg
)
1812 MonoJumpInfo
*patch_info
;
1814 unsigned int *code
, *got_start
;
1815 unsigned long *corlib_exc_adr
;
1816 MonoClass
*exc_classes
[16];
1817 guint8
*exc_throw_start
[16], *exc_throw_end
[16];
1818 guint32 code_size
= 8; // Reserve space for address to mono_arch_throw_corlib_exception
1819 AlphaGotEntry
*got_data
;
1821 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_exceptions");
1823 /* Compute needed space */
1824 for (patch_info
= cfg
->patch_info
; patch_info
;
1825 patch_info
= patch_info
->next
)
1827 if (patch_info
->type
== MONO_PATCH_INFO_EXC
)
1829 if (patch_info
->type
== MONO_PATCH_INFO_R8
)
1830 code_size
+= 8 + 7; /* sizeof (double) + alignment */
1831 if (patch_info
->type
== MONO_PATCH_INFO_R4
)
1832 code_size
+= 4 + 7; /* sizeof (float) + alignment */
1835 // Reserve space for GOT entries
1836 for (got_data
= cfg
->arch
.got_data
; got_data
;
1837 got_data
= got_data
->next
)
1839 // Reserve space for 8 byte const (for now)
1840 if (got_data
->type
!= GT_LD_GTADDR
)
1844 while (cfg
->code_len
+ code_size
> (cfg
->code_size
- 16))
1846 cfg
->code_size
*= 2;
1847 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
1848 mono_jit_stats
.code_reallocs
++;
1851 code
= (unsigned int *)((char *)cfg
->native_code
+ cfg
->code_len
);
1853 // Set code alignment
1854 if (((unsigned long)code
) % 8)
1859 /* Add code to store conts and modify patch into to store offset in got */
1860 for (got_data
= cfg
->arch
.got_data
; got_data
;
1861 got_data
= got_data
->next
)
1863 unsigned long data
= got_data
->value
.data
.l
;
1864 MonoJumpInfo
*got_ref
= got_data
->got_patch_info
;
1866 // Modify loading of GP
1867 if (got_data
->type
== GT_LD_GTADDR
)
1869 short high_off
, low_off
;
1870 unsigned int *ldgp_code
=
1871 (unsigned int *)(cfg
->native_code
+ got_data
->value
.data
.l
);
1872 unsigned int got_off
= (char *)got_start
- (char *)ldgp_code
;
1874 high_off
= got_off
/ 0x10000;
1875 low_off
= got_off
% 0x10000;
1879 // Set offset from current point to GOT array
1880 // modify the following code sequence
1881 // ldah gp, 0(pv) or ldah gp, 0(ra)
1883 *ldgp_code
= (*ldgp_code
| (high_off
& 0xFFFF));
1885 *ldgp_code
= (*ldgp_code
| (low_off
& 0xFFFF));
1890 patch_info
= got_data
->patch_info
;
1892 // Check code alignment
1893 if (((unsigned long)code
) % 8)
1896 got_ref
->data
.offset
= ((char *)code
- (char *)got_start
);
1899 patch_info
->ip
.i
= ((char *)code
- (char *)cfg
->native_code
);
1901 *code
= (unsigned int)(data
& 0xFFFFFFFF);
1903 *code
= (unsigned int)((data
>> 32) & 0xFFFFFFFF);
1908 corlib_exc_adr
= (unsigned long *)code
;
1910 /* add code to raise exceptions */
1912 for (patch_info
= cfg
->patch_info
; patch_info
;
1913 patch_info
= patch_info
->next
)
1915 switch (patch_info
->type
)
1917 case MONO_PATCH_INFO_EXC
:
1919 MonoClass
*exc_class
;
1920 unsigned int *buf
, *buf2
;
1925 // Add patch info to call mono_arch_throw_corlib_exception
1926 // method to raise corlib exception
1927 // Will be added at the begining of the patch info list
1928 mono_add_patch_info(cfg
,
1929 ((char *)code
- (char *)cfg
->native_code
),
1930 MONO_PATCH_INFO_INTERNAL_METHOD
,
1931 "mono_arch_throw_corlib_exception");
1933 // Skip longword before starting the code
1938 exc_class
= mono_class_from_name (mono_defaults
.corlib
,
1939 "System", patch_info
->data
.name
);
1941 g_assert (exc_class
);
1942 throw_ip
= patch_info
->ip
.i
;
1944 //x86_breakpoint (code);
1945 /* Find a throw sequence for the same exception class */
1946 for (i
= 0; i
< nthrows
; ++i
)
1947 if (exc_classes
[i
] == exc_class
)
1954 // Patch original branch (patch info) to jump here
1955 patch_info
->type
= MONO_PATCH_INFO_METHOD_REL
;
1956 patch_info
->data
.target
=
1957 (char *)code
- (char *)cfg
->native_code
;
1959 alpha_lda(code
, alpha_a1
, alpha_zero
,
1960 -((short)((((char *)exc_throw_end
[i
] -
1961 (char *)cfg
->native_code
)) - throw_ip
) - 4) );
1963 br_offset
= ((char *)exc_throw_start
[i
] - (char *)code
- 4)/4;
1965 alpha_bsr(code
, alpha_zero
, br_offset
);
1971 // Save exception token type as first 32bit word for new
1972 // exception handling jump code
1973 *code
= exc_class
->type_token
;
1976 // Patch original branch (patch info) to jump here
1977 patch_info
->type
= MONO_PATCH_INFO_METHOD_REL
;
1978 patch_info
->data
.target
=
1979 (char *)code
- (char *)cfg
->native_code
;
1982 alpha_lda(code
, alpha_a1
, alpha_zero
, 0);
1986 exc_classes
[nthrows
] = exc_class
;
1987 exc_throw_start
[nthrows
] = code
;
1990 // Load exception token
1991 alpha_ldl(code
, alpha_a0
, alpha_gp
,
1992 ((char *)buf
- (char *)got_start
/*cfg->native_code*/));
1993 // Load corlib exception raiser code address
1994 alpha_ldq(code
, alpha_pv
, alpha_gp
,
1995 ((char *)corlib_exc_adr
-
1996 (char *)got_start
/*cfg->native_code*/));
1998 //amd64_mov_reg_imm (code, AMD64_RDI, exc_class->type_token);
1999 //patch_info->data.name = "mono_arch_throw_corlib_exception";
2000 //**patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
2001 //patch_info->type = MONO_PATCH_INFO_NONE;
2002 //patch_info->ip.i = (char *)code - (char *)cfg->native_code;
2004 if (cfg
->compile_aot
)
2006 // amd64_mov_reg_membase (code, GP_SCRATCH_REG, AMD64_RIP, 0, 8);
2007 //amd64_call_reg (code, GP_SCRATCH_REG);
2009 /* The callee is in memory allocated using
2011 alpha_jsr(code
, alpha_ra
, alpha_pv
, 0);
2014 alpha_lda(buf2
, alpha_a1
, alpha_zero
,
2015 -((short)(((char *)code
- (char *)cfg
->native_code
) -
2020 exc_throw_end
[nthrows
] = code
;
2032 /* Handle relocations with RIP relative addressing */
2033 for (patch_info
= cfg
->patch_info
; patch_info
;
2034 patch_info
= patch_info
->next
)
2036 gboolean remove
= FALSE
;
2038 switch (patch_info
->type
)
2040 case MONO_PATCH_INFO_R8
:
2044 code
= (guint8
*)ALIGN_TO (code
, 8);
2046 pos
= cfg
->native_code
+ patch_info
->ip
.i
;
2048 *(double*)code
= *(double*)patch_info
->data
.target
;
2051 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2053 *(guint32
*)(pos
+ 3) = (guint8
*)code
- pos
- 7;
2059 case MONO_PATCH_INFO_R4
:
2063 code
= (guint8
*)ALIGN_TO (code
, 8);
2065 pos
= cfg
->native_code
+ patch_info
->ip
.i
;
2067 *(float*)code
= *(float*)patch_info
->data
.target
;
2070 // *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
2072 *(guint32
*)(pos
+ 3) = (guint8
*)code
- pos
- 7;
2084 if (patch_info
== cfg
->patch_info
)
2085 cfg
->patch_info
= patch_info
->next
;
2090 for (tmp
= cfg
->patch_info
; tmp
->next
!= patch_info
;
2093 tmp
->next
= patch_info
->next
;
2098 cfg
->code_len
= (char *)code
- (char *)cfg
->native_code
;
2100 g_assert (cfg
->code_len
< cfg
->code_size
);
2104 /*========================= End of Function ========================*/
2106 #define EMIT_ALPHA_BRANCH(Tins, PRED_REG, ALPHA_BR) \
2107 offset = ((char *)code - \
2108 (char *)cfg->native_code); \
2109 if (Tins->flags & MONO_INST_BRLABEL) \
2111 if (Tins->inst_i0->inst_c0) \
2113 CFG_DEBUG(3) g_print("inst_c0: %0lX, data: %p]\n", \
2114 Tins->inst_i0->inst_c0, \
2115 cfg->native_code + Tins->inst_i0->inst_c0); \
2116 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2120 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n", \
2121 offset, Tins->inst_i0); \
2122 mono_add_patch_info (cfg, offset, \
2123 MONO_PATCH_INFO_LABEL, Tins->inst_i0); \
2124 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2129 if (Tins->inst_true_bb->native_offset) \
2131 long br_offset = (char *)cfg->native_code + \
2132 Tins->inst_true_bb->native_offset - 4 - (char *)code; \
2133 CFG_DEBUG(3) g_print("jump to: native_offset: %0X, address %p]\n", \
2134 Tins->inst_target_bb->native_offset, \
2135 cfg->native_code + \
2136 Tins->inst_true_bb->native_offset); \
2137 alpha_##ALPHA_BR (code, PRED_REG, br_offset/4); \
2141 CFG_DEBUG(3) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n", \
2142 offset, Tins->inst_target_bb); \
2143 mono_add_patch_info (cfg, offset, \
2144 MONO_PATCH_INFO_BB, \
2145 Tins->inst_true_bb); \
2146 alpha_##ALPHA_BR (code, PRED_REG, 0); \
2151 #define EMIT_COND_EXC_BRANCH(ALPHA_BR, PRED_REG, EXC_NAME) \
2154 MonoInst *tins = mono_branch_optimize_exception_target (cfg, \
2159 mono_add_patch_info (cfg, \
2161 (char *)cfg->native_code), \
2162 MONO_PATCH_INFO_EXC, EXC_NAME); \
2163 alpha_##ALPHA_BR(code, PRED_REG, 0); \
2167 EMIT_ALPHA_BRANCH(tins, PRED_REG, ALPHA_BR); \
2172 /*------------------------------------------------------------------*/
2174 /* Name - mono_arch_output_basic_block */
2176 /* Function - Perform the "real" work of emitting instructions */
2177 /* that will do the work of in the basic block. */
2179 /*------------------------------------------------------------------*/
2182 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
2187 unsigned int *code
= (unsigned int *)(cfg
->native_code
+ cfg
->code_len
);
2188 MonoInst
*last_ins
= NULL
;
2189 guint last_offset
= 0;
2192 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_output_basic_block");
2194 CFG_DEBUG(2) g_print ("Basic block %d(%p) starting at offset 0x%x\n",
2195 bb
->block_num
, bb
, bb
->native_offset
);
2197 cpos
= bb
->max_offset
;
2199 offset
= ((char *)code
) - ((char *)cfg
->native_code
);
2201 mono_debug_open_block (cfg
, bb
, offset
);
2203 MONO_BB_FOR_EACH_INS (bb
, ins
) {
2204 offset
= ((char *)code
) - ((char *)cfg
->native_code
);
2206 max_len
= ((guint8
*)ins_get_spec (ins
->opcode
))[MONO_INST_LEN
];
2208 if (offset
> (cfg
->code_size
- max_len
- 16))
2210 cfg
->code_size
*= 2;
2211 cfg
->native_code
= g_realloc (cfg
->native_code
, cfg
->code_size
);
2212 code
= (unsigned int *)(cfg
->native_code
+ offset
);
2213 mono_jit_stats
.code_reallocs
++;
2216 mono_debug_record_line_number (cfg
, ins
, offset
);
2218 CFG_DEBUG(3) g_print("ALPHA: Emiting [%s] opcode\n",
2219 mono_inst_name(ins
->opcode
));
2221 switch (ins
->opcode
)
2223 case OP_RELAXED_NOP
:
2226 // Shift 64 bit value right
2227 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2228 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2229 alpha_sra(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2233 // Shift 64 bit value right
2234 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2235 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2236 alpha_srl(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2240 // Shift 64 bit value right by constant
2241 g_assert(alpha_is_imm(ins
->inst_imm
));
2242 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2243 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2244 alpha_sra_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2248 // Shift 32 bit value left
2249 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2250 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2251 alpha_sll(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2252 alpha_addl_(code
, ins
->dreg
, 0, ins
->dreg
);
2256 // Shift 32 bit value left by constant
2257 g_assert(alpha_is_imm(ins
->inst_imm
));
2258 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2259 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2260 alpha_sll_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2261 alpha_addl_(code
, ins
->dreg
, 0, ins
->dreg
);
2265 g_assert(alpha_is_imm(ins
->inst_imm
));
2266 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2267 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2268 alpha_sll_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2272 g_assert(alpha_is_imm(ins
->inst_imm
));
2273 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl_imm] dreg=%d, sreg1=%d, const=%ld\n",
2274 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2275 alpha_sll_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2280 // Shift 32 bit value left
2281 CFG_DEBUG(4) g_print("ALPHA_CHECK: [shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2282 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2283 alpha_sll(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2287 // Shift 64 bit value left
2288 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shl] dreg=%d, sreg1=%d, sreg2=%d\n",
2289 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2290 alpha_sll(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2295 // Shift 32 bit value right
2296 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr] dreg=%d, sreg1=%d, sreg2=%d\n",
2297 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2298 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2299 alpha_sra(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2303 // Shift 32 bit value rigth by constant
2304 g_assert(alpha_is_imm(ins
->inst_imm
));
2305 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_imm] dreg=%d, sreg1=%d, const=%ld\n",
2306 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2307 //alpha_zap_(code, ins->sreg1, 0xF0, ins->dreg);
2308 alpha_sra_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2312 // Shift 32 bit unsigned value right
2313 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un] dreg=%d, sreg1=%d, sreg2=%d\n",
2314 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2315 alpha_zap_(code
, ins
->sreg1
, 0xF0, alpha_at
/*ins->dreg*/);
2316 alpha_srl(code
, alpha_at
/*ins->dreg*/, ins
->sreg2
, ins
->dreg
);
2319 case OP_ISHR_UN_IMM
:
2320 // Shift 32 bit unassigned value rigth by constant
2321 g_assert(alpha_is_imm(ins
->inst_imm
));
2322 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2323 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2324 alpha_zap_(code
, ins
->sreg1
, 0xF0, alpha_at
/*ins->dreg*/);
2325 alpha_srl_(code
, alpha_at
/*ins->dreg*/, ins
->inst_imm
, ins
->dreg
);
2328 case OP_LSHR_UN_IMM
:
2329 // Shift 64 bit unassigned value rigth by constant
2330 g_assert(alpha_is_imm(ins
->inst_imm
));
2331 CFG_DEBUG(4) g_print("ALPHA_CHECK: [long_shr_un_imm] dreg=%d, sreg1=%d, const=%ld\n",
2332 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2333 alpha_srl_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2337 // Sum two 64 bits regs
2338 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add] dreg=%d, sreg1=%d, sreg2=%d\n",
2339 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2340 alpha_addq(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2344 // Subtract two 64 bit regs
2345 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sub] dreg=%d, sreg1=%d, sreg2=%d\n",
2346 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2347 alpha_subq(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2351 // Add imm value to 64 bits int
2352 g_assert(alpha_is_imm(ins
->inst_imm
));
2353 CFG_DEBUG(4) g_print("ALPHA_CHECK: [add_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2354 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2355 alpha_addq_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2359 // Add two 32 bit ints
2360 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd] dreg=%d, sreg1=%d, sreg2=%d\n",
2361 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2362 alpha_addl(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2366 // Add two 32 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: [iaddcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2371 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2372 alpha_addl(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 two 64 bit ints with overflow detection
2390 // Use AT to hold flag of signed overflow
2391 // Use t12(PV) to hold unsigned overflow
2392 // Use RA to hold intermediate result
2393 CFG_DEBUG(4) g_print("ALPHA_CHECK: [addcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2394 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2395 alpha_addq(code
, ins
->sreg1
, ins
->sreg2
, alpha_ra
);
2396 alpha_ble(code
, ins
->sreg2
, 2);
2398 /* (sreg2 > 0) && (res < ins->sreg1) => signed overflow */
2399 alpha_cmplt(code
, alpha_ra
, ins
->sreg1
, alpha_at
);
2400 alpha_br(code
, alpha_zero
, 1);
2402 /* (sreg2 <= 0) && (res > ins->sreg1) => signed overflow */
2403 alpha_cmplt(code
, ins
->sreg1
, alpha_ra
, alpha_at
);
2405 /* res <u sreg1 => unsigned overflow */
2406 alpha_cmpult(code
, alpha_ra
, ins
->sreg1
, alpha_pv
);
2408 alpha_mov1(code
, alpha_ra
, ins
->dreg
);
2412 // Add imm value to 32 bits int
2413 g_assert(alpha_is_imm(ins
->inst_imm
));
2414 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iadd_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2415 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2416 alpha_addl_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2420 // Substract to 32 bit ints
2421 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub] dreg=%d, sreg1=%d, sreg2=%d\n",
2422 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2423 alpha_subl(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2427 // Sub imm value from 32 bits int
2428 g_assert(alpha_is_imm(ins
->inst_imm
));
2429 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isub_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2430 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2431 alpha_subl_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2435 // Sub to 32 bit ints with overflow detection
2436 CFG_DEBUG(4) g_print("ALPHA_CHECK: [isubcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2437 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2438 alpha_subl(code
, ins
->sreg1
, ins
->sreg2
, alpha_ra
);
2439 alpha_ble(code
, ins
->sreg2
, 2);
2441 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2442 alpha_cmplt(code
, ins
->sreg1
, alpha_ra
, alpha_at
);
2443 alpha_br(code
, alpha_zero
, 1);
2445 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2446 alpha_cmplt(code
, alpha_ra
, ins
->sreg1
, alpha_at
);
2448 /* sreg1 <u sreg2 => unsigned overflow */
2449 alpha_cmpult(code
, ins
->sreg1
, ins
->sreg2
, alpha_pv
);
2451 alpha_mov1(code
, alpha_ra
, ins
->dreg
);
2455 // Sub to 64 bit ints with overflow detection
2456 CFG_DEBUG(4) g_print("ALPHA_CHECK: [subcc] dreg=%d, sreg1=%d, sreg2=%d\n",
2457 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2459 alpha_subq(code
, ins
->sreg1
, ins
->sreg2
, alpha_ra
);
2460 alpha_ble(code
, ins
->sreg2
, 2);
2462 /* (sreg2 > 0) && (res > ins->sreg1) => signed overflow */
2463 alpha_cmplt(code
, ins
->sreg1
, alpha_ra
, alpha_at
);
2464 alpha_br(code
, alpha_zero
, 1);
2466 /* (sreg2 <= 0) && (res < ins->sreg1) => signed overflow */
2467 alpha_cmplt(code
, alpha_ra
, ins
->sreg1
, alpha_at
);
2469 /* sreg1 <u sreg2 => unsigned overflow */
2470 alpha_cmpult(code
, ins
->sreg1
, ins
->sreg2
, alpha_pv
);
2472 alpha_mov1(code
, alpha_ra
, ins
->dreg
);
2477 // AND to 32 bit ints
2478 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand/and] dreg=%d, sreg1=%d, sreg2=%d\n",
2479 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2480 alpha_and(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2485 // AND imm value with 32 bit int
2486 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iand_imm/and_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2487 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2489 g_assert(alpha_is_imm(ins
->inst_imm
));
2490 alpha_and_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2496 // OR two 32/64 bit ints
2497 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior/or] dreg=%d, sreg1=%d, sreg2=%d\n",
2498 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2499 alpha_bis(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2503 // OR imm value with 32 bit int
2504 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ior_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2505 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2507 g_assert(alpha_is_imm(ins
->inst_imm
));
2508 alpha_bis_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2514 // XOR two 32/64 bit ints
2515 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor/xor] dreg=%d, sreg1=%d, sreg2=%d\n",
2516 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2517 alpha_xor(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2521 // XOR imm value with 32 bit int
2522 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ixor_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2523 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2525 g_assert(alpha_is_imm(ins
->inst_imm
));
2526 alpha_xor_(code
, ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
2532 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ineg] dreg=%d, sreg1=%d\n",
2533 ins
->dreg
, ins
->sreg1
);
2534 alpha_subl(code
, alpha_zero
, ins
->sreg1
, ins
->dreg
);
2539 CFG_DEBUG(4) g_print("ALPHA_CHECK: [neg] dreg=%d, sreg1=%d\n",
2540 ins
->dreg
, ins
->sreg1
);
2541 alpha_subq(code
, alpha_zero
, ins
->sreg1
, ins
->dreg
);
2546 // NOT 32/64 bit reg
2547 CFG_DEBUG(4) g_print("ALPHA_CHECK: [inot/not] dreg=%d, sreg1=%d\n",
2548 ins
->dreg
, ins
->sreg1
);
2549 alpha_not(code
, ins
->sreg1
, ins
->dreg
);
2557 case OP_IMUL_OVF_UN
:
2560 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",
2561 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2565 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mul] dreg=%d, sreg1=%d, sreg2=%d\n",
2566 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
2567 alpha_mull(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2571 CFG_DEBUG(4) g_print("ALPHA_TODO: [imul_imm] dreg=%d, sreg1=%d, imm=%ld\n",
2572 ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
2576 CFG_DEBUG(4) g_print("ALPHA_CHECK: [check_this] sreg1=%d\n",
2578 alpha_ldl(code
, alpha_at
, ins
->sreg1
, 0);
2582 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i1] dreg=%d, sreg1=%d\n",
2583 ins
->dreg
, ins
->sreg1
);
2584 alpha_sll_(code
, ins
->sreg1
, 56, ins
->dreg
);
2585 alpha_sra_(code
, ins
->dreg
, 56, ins
->dreg
);
2589 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i2] dreg=%d, sreg1=%d\n",
2590 ins
->dreg
, ins
->sreg1
);
2591 alpha_sll_(code
, ins
->sreg1
, 48, ins
->dreg
);
2592 alpha_sra_(code
, ins
->dreg
, 48, ins
->dreg
);
2596 CFG_DEBUG(4) g_print("ALPHA_CHECK: [sext_i4] dreg=%d, sreg1=%d\n",
2597 ins
->dreg
, ins
->sreg1
);
2598 alpha_sll_(code
, ins
->sreg1
, 32, ins
->dreg
);
2599 alpha_sra_(code
, ins
->dreg
, 32, ins
->dreg
);
2603 // Actually ICONST is 32 bits long
2604 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iconst] dreg=%d, const=%0lX\n",
2605 ins
->dreg
, ins
->inst_c0
);
2608 if (ins
->inst_c0
== 0)
2610 alpha_clr(code
, ins
->dreg
);
2614 // if -32768 < const <= 32767
2615 if (ins
->inst_c0
> -32768 && ins
->inst_c0
<= 32767)
2617 alpha_lda( code
, ins
->dreg
, alpha_zero
, ins
->inst_c0
);
2618 //if (ins->inst_c0 & 0xFFFFFFFF00000000L)
2619 // alpha_zap_(code, ins->dreg, 0xF0, ins->dreg);
2623 int lo
= (char *)code
- (char *)cfg
->native_code
;
2624 AlphaGotData ge_data
;
2626 //ge_data.data.l = (ins->inst_c0 & 0xFFFFFFFF);
2627 ge_data
.data
.l
= ins
->inst_c0
;
2629 add_got_entry(cfg
, GT_LONG
, ge_data
,
2630 lo
, MONO_PATCH_INFO_NONE
, 0);
2631 //mono_add_patch_info(cfg, lo, MONO_PATCH_INFO_GOT_OFFSET,
2633 //alpha_ldl(code, ins->dreg, alpha_gp, 0);
2634 alpha_ldq(code
, ins
->dreg
, alpha_gp
, 0);
2642 // To load 64 bit values we will have to use ldah/lda combination
2643 // and temporary register. As temporary register use r28
2644 // Divide 64 bit value in two parts and load upper 32 bits into
2645 // temp reg, lower 32 bits into dreg. Later set higher 32 bits in
2646 // dreg from temp reg
2647 // the 32 bit value could be loaded with ldah/lda
2648 CFG_DEBUG(4) g_print("ALPHA_CHECK: [i8conts] dreg=%d, const=%0lX\n",
2649 ins
->dreg
, ins
->inst_c0
);
2652 if (ins
->inst_c0
== 0)
2654 alpha_clr(code
, ins
->dreg
);
2658 // if -32768 < const <= 32767
2659 if (ins
->inst_c0
> -32768 && ins
->inst_c0
<= 32767)
2660 alpha_lda( code
, ins
->dreg
, alpha_zero
, ins
->inst_c0
);
2663 AlphaGotData ge_data
;
2665 lo
= (char *)code
- (char *)cfg
->native_code
;
2667 ge_data
.data
.l
= ins
->inst_c0
;
2669 add_got_entry(cfg
, GT_LONG
, ge_data
,
2670 lo
, MONO_PATCH_INFO_NONE
, 0);
2671 alpha_ldq(code
, ins
->dreg
, alpha_gp
, 0);
2678 double d
= *(double *)ins
->inst_p0
;
2679 AlphaGotData ge_data
;
2681 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r8const] dreg=%d, r8const=%g\n",
2685 add_got_entry(cfg
, GT_DOUBLE
, ge_data
,
2686 (char *)code
- (char *)cfg
->native_code
,
2687 MONO_PATCH_INFO_NONE
, 0);
2688 alpha_ldt(code
, ins
->dreg
, alpha_gp
, 0);
2695 float d
= *(float *)ins
->inst_p0
;
2696 AlphaGotData ge_data
;
2698 CFG_DEBUG(4) g_print("ALPHA_CHECK: [r4const] dreg=%d, r4const=%f\n",
2702 add_got_entry(cfg
, GT_FLOAT
, ge_data
,
2703 (char *)code
- (char *)cfg
->native_code
,
2704 MONO_PATCH_INFO_NONE
, 0);
2705 alpha_lds(code
, ins
->dreg
, alpha_gp
, 0);
2710 case OP_LOADU4_MEMBASE
:
2711 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2712 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2714 alpha_ldl(code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2715 // alpha_zapnot_(code, ins->dreg, 0x0F, ins->dreg);
2718 case OP_LOADU1_MEMBASE
:
2719 // Load unassigned byte from REGOFFSET
2720 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2721 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2723 alpha_ldbu(code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2726 alpha_ldq_u(code
, alpha_r25
, ins
->inst_basereg
,
2728 alpha_lda(code
, alpha_at
, ins
->inst_basereg
, ins
->inst_offset
);
2729 alpha_extbl(code
, alpha_r25
, alpha_at
, ins
->dreg
);
2733 case OP_LOADU2_MEMBASE
:
2734 // Load unassigned word from REGOFFSET
2735 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadu2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2736 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2739 alpha_ldwu(code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2742 alpha_ldq_u(code
, alpha_r24
, ins
->inst_basereg
,
2744 alpha_ldq_u(code
, alpha_r25
, ins
->inst_basereg
,
2745 (ins
->inst_offset
+1));
2746 alpha_lda(code
, alpha_at
, ins
->inst_basereg
, ins
->inst_offset
);
2747 alpha_extwl(code
, alpha_r24
, alpha_at
, ins
->dreg
);
2748 alpha_extwh(code
, alpha_r25
, alpha_at
, alpha_r25
);
2749 alpha_bis(code
, alpha_r25
, ins
->dreg
, ins
->dreg
);
2753 case OP_LOAD_MEMBASE
:
2754 CFG_DEBUG(4) g_print("ALPHA_CHECK: [load_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2755 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2756 alpha_ldq( code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2759 case OP_LOADI8_MEMBASE
:
2760 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi8_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2761 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2762 alpha_ldq( code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2765 case OP_LOADI4_MEMBASE
:
2766 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi4_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2767 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2768 alpha_ldl( code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2771 case OP_LOADI1_MEMBASE
:
2772 // Load sign-extended byte from REGOFFSET
2773 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi1_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2774 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2777 alpha_ldbu(code
, ins
->dreg
, ins
->inst_basereg
,
2779 alpha_sextb(code
, ins
->dreg
, ins
->dreg
);
2783 alpha_ldq_u(code
, alpha_r25
, ins
->inst_basereg
,
2785 alpha_lda(code
, alpha_at
, ins
->inst_basereg
,
2786 (ins
->inst_offset
+1));
2787 alpha_extqh(code
, alpha_r25
, alpha_at
, ins
->dreg
);
2788 alpha_sra_(code
, ins
->dreg
, 56, ins
->dreg
);
2792 case OP_LOADI2_MEMBASE
:
2793 // Load sign-extended word from REGOFFSET
2794 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadi2_membase] dreg=%d, basereg=%d, offset=%0lx\n",
2795 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2798 alpha_ldwu(code
, ins
->dreg
, ins
->inst_basereg
,
2800 alpha_sextw(code
, ins
->dreg
, ins
->dreg
);
2804 alpha_ldq_u(code
, alpha_r24
, ins
->inst_basereg
,
2806 alpha_ldq_u(code
, alpha_r25
, ins
->inst_basereg
,
2807 (ins
->inst_offset
+1));
2808 alpha_lda(code
, alpha_at
, ins
->inst_basereg
,
2809 (ins
->inst_offset
+2));
2810 alpha_extql(code
, alpha_r24
, alpha_at
, ins
->dreg
);
2811 alpha_extqh(code
, alpha_r25
, alpha_at
, alpha_r25
);
2812 alpha_bis(code
, alpha_r25
, ins
->dreg
, ins
->dreg
);
2813 alpha_sra_(code
, ins
->dreg
, 48, ins
->dreg
);
2817 case OP_STOREI1_MEMBASE_IMM
:
2818 // Store signed byte at REGOFFSET
2819 // Valid only for storing 0
2820 // storei1_membase_reg will do the rest
2822 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2823 ins
->inst_imm
, ins
->inst_destbasereg
, ins
->inst_offset
);
2824 g_assert(ins
->inst_imm
== 0);
2827 alpha_stb(code
, alpha_zero
, ins
->inst_destbasereg
,
2830 g_assert_not_reached();
2834 case OP_STOREI1_MEMBASE_REG
:
2835 // Store byte at REGOFFSET
2836 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei1_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2837 ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
2840 alpha_stb(code
, ins
->sreg1
, ins
->inst_destbasereg
,
2845 alpha_lda(code
, alpha_at
, ins
->inst_destbasereg
,
2847 alpha_ldq_u(code
, alpha_r25
, ins
->inst_destbasereg
,
2849 alpha_insbl(code
, ins
->sreg1
, alpha_at
, alpha_r24
);
2850 alpha_mskbl(code
, alpha_r25
, alpha_at
, alpha_r25
);
2851 alpha_bis(code
, alpha_r25
, alpha_r24
, alpha_r25
);
2852 alpha_stq_u(code
, alpha_r25
, ins
->inst_destbasereg
,
2857 case OP_STOREI2_MEMBASE_IMM
:
2858 // Store signed word at REGOFFSET
2859 // Now work only for storing 0
2860 // For now storei2_membase_reg will do the work
2862 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2863 ins
->inst_imm
, ins
->inst_destbasereg
, ins
->inst_offset
);
2865 g_assert(ins
->inst_imm
== 0);
2868 alpha_stw(code
, alpha_zero
, ins
->inst_destbasereg
,
2871 g_assert_not_reached();
2875 case OP_STOREI2_MEMBASE_REG
:
2876 // Store signed word from reg to REGOFFSET
2877 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei2_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
2878 ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
2882 alpha_stw(code
, ins
->sreg1
, ins
->inst_destbasereg
,
2887 alpha_lda(code
, alpha_at
, ins
->inst_destbasereg
,
2889 alpha_ldq_u(code
, alpha_r25
, ins
->inst_destbasereg
,
2890 (ins
->inst_offset
+1));
2891 alpha_ldq_u(code
, alpha_r24
, ins
->inst_destbasereg
,
2893 alpha_inswh(code
, ins
->sreg1
, alpha_at
, alpha_r23
);
2894 alpha_inswl(code
, ins
->sreg1
, alpha_at
, alpha_r22
);
2895 alpha_mskwh(code
, alpha_r25
, alpha_at
, alpha_r25
);
2896 alpha_mskwl(code
, alpha_r24
, alpha_at
, alpha_r24
);
2897 alpha_bis(code
, alpha_r25
, alpha_r23
, alpha_r25
);
2898 alpha_bis(code
, alpha_r24
, alpha_r22
, alpha_r24
);
2899 alpha_stq_u(code
, alpha_r25
, ins
->inst_destbasereg
,
2900 (ins
->inst_offset
+1));
2901 alpha_stq_u(code
, alpha_r24
, ins
->inst_destbasereg
,
2907 case OP_STOREI4_MEMBASE_IMM
:
2908 // We will get here only with ins->inst_imm = 0
2909 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_imm(0)] const=%0lx, destbasereg=%d, offset=%0lx\n",
2910 ins
->inst_imm
, ins
->inst_destbasereg
, ins
->inst_offset
);
2912 g_assert(ins
->inst_imm
== 0);
2914 alpha_stl(code
, alpha_zero
,
2915 ins
->inst_destbasereg
, ins
->inst_offset
);
2918 case OP_STORER4_MEMBASE_REG
:
2919 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2920 ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
2921 alpha_sts(code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
2924 case OP_STORER8_MEMBASE_REG
:
2925 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storer8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lX\n",
2926 ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
2927 alpha_stt(code
, ins
->sreg1
, ins
->inst_destbasereg
,
2931 case OP_LOADR4_MEMBASE
:
2932 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr4_membase] dreg=%d basereg=%d offset=%0lX\n",
2933 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2934 alpha_lds(code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2937 case OP_LOADR8_MEMBASE
:
2938 CFG_DEBUG(4) g_print("ALPHA_CHECK: [loadr8_membase] dreg=%d basereg=%d offset=%0lX\n",
2939 ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2940 alpha_ldt(code
, ins
->dreg
, ins
->inst_basereg
, ins
->inst_offset
);
2944 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fmove] sreg1=%d, dreg=%d\n",
2945 ins
->sreg1
, ins
->dreg
);
2946 alpha_cpys(code
, ins
->sreg1
, ins
->sreg1
, ins
->dreg
);
2950 // Later check different rounding and exc modes
2951 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_add] sreg1=%d, sreg2=%d, dreg=%d\n",
2952 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2953 alpha_addt_su(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2958 // Later check different rounding and exc modes
2959 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2960 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2961 alpha_subt_su(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2966 // Later check different rounding and exc modes
2967 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_sub] sreg1=%d, sreg2=%d, dreg=%d\n",
2968 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2969 alpha_mult(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
2973 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_neg] sreg1=%d, dreg=%d\n",
2974 ins
->sreg1
, ins
->dreg
);
2975 alpha_cpysn(code
, ins
->sreg1
, ins
->sreg1
, ins
->dreg
);
2978 case OP_ALPHA_TRAPB
:
2979 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_trapb]\n");
2984 CFG_DEBUG(4) g_print("ALPHA_CHECK: [float_abs] sreg1=%d, dreg=%d\n",
2985 ins
->sreg1
, ins
->dreg
);
2986 alpha_cpys(code
, alpha_f31
, ins
->sreg1
, ins
->dreg
);
2989 case OP_STORE_MEMBASE_IMM
:
2990 case OP_STOREI8_MEMBASE_IMM
:
2991 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_imm/storei8_membase_imm] const=%0lx, destbasereg=%d, offset=%0lx\n",
2992 ins
->inst_imm
, ins
->inst_destbasereg
, ins
->inst_offset
);
2993 g_assert(ins
->inst_imm
== 0);
2995 alpha_stq(code
, alpha_zero
,
2996 ins
->inst_destbasereg
, ins
->inst_offset
);
2999 case OP_STORE_MEMBASE_REG
:
3000 case OP_STOREI8_MEMBASE_REG
:
3001 CFG_DEBUG(4) g_print("ALPHA_CHECK: [store_membase_reg/storei8_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3002 ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3003 alpha_stq( code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3006 case OP_STOREI4_MEMBASE_REG
:
3007 CFG_DEBUG(4) g_print("ALPHA_CHECK: [storei4_membase_reg] sreg1=%d, destbasereg=%d, offset=%0lx\n",
3008 ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3009 alpha_stl( code
, ins
->sreg1
, ins
->inst_destbasereg
, ins
->inst_offset
);
3012 case OP_ICOMPARE_IMM
:
3013 CFG_DEBUG(4) g_print("ALPHA_CHECK: [icompare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3014 ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3016 g_assert_not_reached();
3020 case OP_COMPARE_IMM
:
3021 CFG_DEBUG(4) g_print("ALPHA_CHECK: [compare_imm] sreg1=%d, dreg=%d, const=%0lX\n",
3022 ins
->sreg1
, ins
->dreg
, ins
->inst_imm
);
3024 g_assert_not_reached();
3028 case OP_COMPARE
: // compare two 32 bit regs
3029 case OP_LCOMPARE
: // compare two 64 bit regs
3030 case OP_FCOMPARE
: // compare two floats
3031 CFG_DEBUG(4) g_print("ALPHA_FIX: [compare/lcompare/fcompare] sreg1=%d, sreg2=%d, dreg=%d\n",
3032 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3034 g_assert_not_reached();
3038 case OP_ALPHA_CMPT_UN
:
3039 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un] sreg1=%d, sreg2=%d, dreg=%d\n",
3040 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3041 alpha_cmptun(code
, ins
->sreg1
, ins
->sreg2
, (alpha_at
+1));
3044 case OP_ALPHA_CMPT_UN_SU
:
3045 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_un_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3046 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3047 alpha_cmptun_su(code
, ins
->sreg1
, ins
->sreg2
, (alpha_at
+1));
3050 case OP_ALPHA_CMPT_EQ
:
3051 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3052 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3053 alpha_cmpteq(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3056 case OP_ALPHA_CMPT_EQ_SU
:
3057 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_eq_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3058 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3059 alpha_cmpteq_su(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3063 case OP_ALPHA_CMPT_LT
:
3064 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3065 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3066 alpha_cmptlt(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3069 case OP_ALPHA_CMPT_LT_SU
:
3070 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_lt_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3071 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3072 alpha_cmptlt_su(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3075 case OP_ALPHA_CMPT_LE
:
3076 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3077 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3078 alpha_cmptle(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3081 case OP_ALPHA_CMPT_LE_SU
:
3082 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmpt_le_su] sreg1=%d, sreg2=%d, dreg=%d\n",
3083 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3084 alpha_cmptle_su(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3087 case OP_ALPHA_CMP_EQ
:
3088 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_eq] sreg1=%d, sreg2=%d, dreg=%d\n",
3089 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3090 alpha_cmpeq(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3093 case OP_ALPHA_CMP_IMM_EQ
:
3094 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_eq] sreg1=%d, const=%0lX, dreg=%d\n",
3095 ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
3096 alpha_cmpeq_(code
, ins
->sreg1
, ins
->inst_imm
, alpha_at
);
3099 case OP_ALPHA_CMP_IMM_ULE
:
3100 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ule] sreg1=%d, const=%0lX, dreg=%d\n",
3101 ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
3102 alpha_cmpule_(code
, ins
->sreg1
, ins
->inst_imm
, alpha_at
);
3105 case OP_ALPHA_CMP_ULT
:
3106 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ult] sreg1=%d, sreg2=%d, dreg=%d\n",
3107 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3108 alpha_cmpult(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3111 case OP_ALPHA_CMP_IMM_ULT
:
3112 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_ult] sreg1=%d, const=%0lX, dreg=%d\n",
3113 ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
3114 alpha_cmpult_(code
, ins
->sreg1
, ins
->inst_imm
, alpha_at
);
3117 case OP_ALPHA_CMP_LE
:
3118 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_le] sreg1=%d, sreg2=%d, dreg=%d\n",
3119 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3120 alpha_cmple(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3123 case OP_ALPHA_CMP_ULE
:
3124 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_ule] sreg1=%d, sreg2=%d, dreg=%d\n",
3125 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3126 alpha_cmpule(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3130 case OP_ALPHA_CMP_IMM_LE
:
3131 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_le] sreg1=%d, const=%0lX, dreg=%d\n",
3132 ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
3133 alpha_cmple_(code
, ins
->sreg1
, ins
->inst_imm
, alpha_at
);
3136 case OP_ALPHA_CMP_LT
:
3137 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_lt] sreg1=%d, sreg2=%d, dreg=%d\n",
3138 ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3139 alpha_cmplt(code
, ins
->sreg1
, ins
->sreg2
, alpha_at
);
3142 case OP_ALPHA_CMP_IMM_LT
:
3143 CFG_DEBUG(4) g_print("ALPHA_CHECK: [alpha_cmp_imm_lt] sreg1=%d, const=%0lX, dreg=%d\n",
3144 ins
->sreg1
, ins
->inst_imm
, ins
->dreg
);
3145 alpha_cmplt_(code
, ins
->sreg1
, ins
->inst_imm
, alpha_at
);
3148 case OP_COND_EXC_GT
:
3149 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt] (cmple + beq) Exc: %s\n",
3150 (char *)ins
->inst_p1
);
3152 EMIT_COND_EXC_BRANCH(beq
, alpha_at
, ins
->inst_p1
);
3155 case OP_COND_EXC_GT_UN
:
3156 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_gt_un] (cmpule + beq) Exc: %s\n",
3157 (char *)ins
->inst_p1
);
3159 EMIT_COND_EXC_BRANCH(beq
, alpha_at
, ins
->inst_p1
);
3162 case OP_COND_EXC_LT
:
3163 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt] (cmplt + bne) Exc: %s\n",
3164 (char *)ins
->inst_p1
);
3166 EMIT_COND_EXC_BRANCH(bne
, alpha_at
, ins
->inst_p1
);
3169 case OP_COND_EXC_LT_UN
:
3170 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_lt_un] (cmpult + bne) Exc: %s\n",
3171 (char *)ins
->inst_p1
);
3173 EMIT_COND_EXC_BRANCH(bne
, alpha_at
, ins
->inst_p1
);
3177 case OP_COND_EXC_LE_UN
:
3178 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_le_un] (cmpule + bne) Exc: %s\n",
3179 (char *)ins
->inst_p1
);
3180 EMIT_COND_EXC_BRANCH(bne
, alpha_at
, ins
->inst_p1
);
3183 case OP_COND_EXC_NE_UN
:
3184 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_ne_un] (cmpeq + beq) Exc: %s\n",
3185 (char *)ins
->inst_p1
);
3186 EMIT_COND_EXC_BRANCH(beq
, alpha_at
, ins
->inst_p1
);
3189 case OP_COND_EXC_EQ
:
3190 CFG_DEBUG(4) g_print("ALPHA_CHECK: [op_cond_exc_eq] (cmpeq + bne) Exc: %s\n",
3191 (char *)ins
->inst_p1
);
3192 EMIT_COND_EXC_BRANCH(bne
, alpha_at
, ins
->inst_p1
);
3195 case OP_COND_EXC_IOV
:
3196 case OP_COND_EXC_OV
:
3197 EMIT_COND_EXC_BRANCH(bne
, alpha_at
, "OverflowException");
3200 case OP_COND_EXC_IC
:
3202 EMIT_COND_EXC_BRANCH(bne
, alpha_pv
, "OverflowException");
3205 case CEE_CONV_OVF_U4
:
3206 // Convert unsigned 32 bit value to 64 bit reg
3208 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_u4] sreg=%d, dreg=%d\n",
3209 ins
->sreg1
, ins
->dreg
);
3210 alpha_cmplt_(code
, ins
->sreg1
, 0, alpha_at
);
3211 EMIT_COND_EXC_BRANCH(bne
, alpha_at
, "OverflowException");
3212 alpha_mov1(code
, ins
->sreg1
, ins
->dreg
);
3215 case CEE_CONV_OVF_I4_UN
:
3216 // Convert unsigned 32 bit value to 64 bit reg
3218 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_ovf_i4_un] sreg=%d, dreg=%d\n",
3219 ins
->sreg1
, ins
->dreg
);
3220 alpha_zap_(code
, ins
->sreg1
, 0x0F, alpha_at
);
3222 EMIT_COND_EXC_BRANCH(bne
, alpha_at
, "OverflowException");
3223 alpha_mov1(code
, ins
->sreg1
, ins
->dreg
);
3227 // Move I1 (byte) to dreg(64 bits) and sign extend it
3229 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i1] sreg=%d, dreg=%d\n",
3230 ins
->sreg1
, ins
->dreg
);
3232 alpha_sextb(code
, ins
->sreg1
, ins
->dreg
);
3235 alpha_sll_(code
, ins
->sreg1
, 24, alpha_at
);
3236 alpha_addl(code
, alpha_at
, alpha_zero
, ins
->dreg
);
3237 alpha_sra_(code
, ins
->dreg
, 24, ins
->dreg
);
3242 // Move I2 (word) to dreg(64 bits) and sign extend it
3243 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i2] sreg=%d, dreg=%d\n",
3244 ins
->sreg1
, ins
->dreg
);
3246 alpha_sextw(code
, ins
->sreg1
, ins
->dreg
);
3249 alpha_sll_(code
, ins
->sreg1
, 16, alpha_at
);
3250 alpha_addl(code
, alpha_at
, alpha_zero
, ins
->dreg
);
3251 alpha_sra_(code
, ins
->dreg
, 16, ins
->dreg
);
3256 // Move I4 (long) to dreg(64 bits) and sign extend it
3257 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i4] sreg=%d, dreg=%d\n",
3258 ins
->sreg1
, ins
->dreg
);
3259 alpha_addl(code
, ins
->sreg1
, alpha_zero
, ins
->dreg
);
3264 // Convert I/I8 (64 bit) to dreg (64 bit) and sign extend it
3265 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_i8/conv_i] sreg=%d, dreg=%d\n",
3266 ins
->sreg1
, ins
->dreg
);
3267 //alpha_addl(code, ins->sreg1, alpha_zero, ins->dreg);
3268 alpha_mov1(code
, ins
->sreg1
, ins
->dreg
);
3272 // Move U1 (byte) to dreg(64 bits) don't sign extend it
3273 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u1] sreg=%d, dreg=%d\n",
3274 ins
->sreg1
, ins
->dreg
);
3275 alpha_extbl_(code
, ins
->sreg1
, 0, ins
->dreg
);
3279 // Move U2 (word) to dreg(64 bits) don't sign extend it
3280 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u2] sreg=%d, dreg=%d\n",
3281 ins
->sreg1
, ins
->dreg
);
3282 alpha_extwl_(code
, ins
->sreg1
, 0, ins
->dreg
);
3286 // Move U4 (long) to dreg(64 bits) don't sign extend it
3287 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u4] sreg=%d, dreg=%d\n",
3288 ins
->sreg1
, ins
->dreg
);
3289 alpha_extll_(code
, ins
->sreg1
, 0, ins
->dreg
);
3294 // Move U4 (long) to dreg(64 bits) don't sign extend it
3295 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_u8/conv_u] sreg=%d, dreg=%d\n",
3296 ins
->sreg1
, ins
->dreg
);
3297 alpha_extll_(code
, ins
->sreg1
, 0, ins
->dreg
);
3300 case OP_FCONV_TO_I4
:
3301 case OP_FCONV_TO_I8
:
3302 // Move float to 32 bit reg
3303 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i4/fconv_to_i8] sreg=%d, dreg=%d\n",
3304 ins
->sreg1
, ins
->dreg
);
3305 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3306 alpha_cvttq_c(code
, ins
->sreg1
, ins
->sreg1
);
3307 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
3308 alpha_stt(code
, ins
->sreg1
, alpha_sp
, 0);
3309 alpha_ldq(code
, ins
->dreg
, alpha_sp
, 0);
3310 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
3313 case OP_FCONV_TO_I2
:
3314 // Move float to 16 bit reg
3315 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i2] sreg=%d, dreg=%d\n",
3316 ins
->sreg1
, ins
->dreg
);
3317 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3318 alpha_cvttq_c(code
, ins
->sreg1
, ins
->sreg1
);
3319 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
3320 alpha_stt(code
, ins
->sreg1
, alpha_sp
, 0);
3321 alpha_ldq(code
, ins
->dreg
, alpha_sp
, 0);
3322 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
3323 alpha_sll_(code
, ins
->dreg
, 48, ins
->dreg
);
3324 alpha_sra_(code
, ins
->dreg
, 48, ins
->dreg
);
3327 case OP_FCONV_TO_U2
:
3328 // Move float to 16 bit reg as unsigned
3329 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u2] sreg=%d, dreg=%d\n",
3330 ins
->sreg1
, ins
->dreg
);
3331 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3332 alpha_cvttq_c(code
, ins
->sreg1
, ins
->sreg1
);
3333 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
3334 alpha_stt(code
, ins
->sreg1
, alpha_sp
, 0);
3335 alpha_ldq(code
, ins
->dreg
, alpha_sp
, 0);
3336 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
3337 alpha_zapnot_(code
, ins
->dreg
, 3, ins
->dreg
);
3340 case OP_FCONV_TO_U1
:
3341 // Move float to 8 bit reg as unsigned
3342 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_u1] sreg=%d, dreg=%d\n",
3343 ins
->sreg1
, ins
->dreg
);
3344 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3345 alpha_cvttq_c(code
, ins
->sreg1
, ins
->sreg1
);
3346 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
3347 alpha_stt(code
, ins
->sreg1
, alpha_sp
, 0);
3348 alpha_ldq(code
, ins
->dreg
, alpha_sp
, 0);
3349 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
3350 alpha_and_(code
, ins
->dreg
, 0xff, ins
->dreg
);
3353 case OP_FCONV_TO_I1
:
3354 // Move float to 8 bit reg
3355 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_to_i1] sreg=%d, dreg=%d\n",
3356 ins
->sreg1
, ins
->dreg
);
3357 //alpha_ftoit(code, ins->sreg1, ins->dreg); - 21264/EV6
3358 alpha_cvttq_c(code
, ins
->sreg1
, ins
->sreg1
);
3359 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
3360 alpha_stt(code
, ins
->sreg1
, alpha_sp
, 0);
3361 alpha_ldq(code
, ins
->dreg
, alpha_sp
, 0);
3362 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
3363 alpha_sll_(code
, ins
->dreg
, 56, ins
->dreg
);
3364 alpha_sra_(code
, ins
->dreg
, 56, ins
->dreg
);
3368 case OP_LCONV_TO_R4
:
3369 // Move 32/64 bit int into float
3370 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r4/lconv_r4] sreg=%d, dreg=%d\n",
3371 ins
->sreg1
, ins
->dreg
);
3372 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
3373 alpha_stq(code
, ins
->sreg1
, alpha_sp
, 0);
3374 alpha_ldt(code
, ins
->dreg
, alpha_sp
, 0);
3375 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
3376 alpha_cvtqs(code
, ins
->dreg
, ins
->dreg
);
3381 case OP_LCONV_TO_R8
:
3382 // Move 32/64 bit int into double
3383 CFG_DEBUG(4) g_print("ALPHA_CHECK: [conv_r8/lconv_r8] sreg=%d, dreg=%d\n",
3384 ins
->sreg1
, ins
->dreg
);
3385 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
3386 alpha_stq(code
, ins
->sreg1
, alpha_sp
, 0);
3387 alpha_ldt(code
, ins
->dreg
, alpha_sp
, 0);
3388 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
3389 alpha_cvtqt(code
, ins
->dreg
, ins
->dreg
);
3393 case OP_FCONV_TO_R4
:
3394 // Convert 64 bit float to 32 bit float (T -> S)
3395 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fconv_r4] sreg=%d, dreg=%d\n",
3396 ins
->sreg1
, ins
->dreg
);
3397 alpha_cvtts_su(code
, ins
->sreg1
, ins
->dreg
);
3402 // Allocate sreg1 bytes on stack, round bytes by 8,
3403 // modify SP, set dreg to end of current stack frame
3404 // top of stack is used for call params
3405 CFG_DEBUG(4) g_print("ALPHA_CHECK: [localloc] sreg=%d, dreg=%d\n",
3406 ins
->sreg1
, ins
->dreg
);
3408 alpha_addq_(code
, ins
->sreg1
, (MONO_ARCH_LOCALLOC_ALIGNMENT
- 1), ins
->sreg1
);
3409 alpha_bic_(code
, ins
->sreg1
, (MONO_ARCH_LOCALLOC_ALIGNMENT
- 1), ins
->sreg1
);
3410 if (ins
->flags
& MONO_INST_INIT
)
3411 alpha_mov1(code
, ins
->sreg1
, ins
->sreg2
);
3413 alpha_subq(code
, alpha_sp
, ins
->sreg1
, alpha_sp
);
3414 if (cfg
->arch
.params_stack_size
> 0)
3416 alpha_lda(code
, ins
->dreg
, alpha_zero
,
3417 (cfg
->arch
.params_stack_size
));
3418 alpha_addq(code
, alpha_sp
, ins
->dreg
, ins
->dreg
);
3421 alpha_mov1(code
, alpha_sp
, ins
->dreg
);
3423 if (ins
->flags
& MONO_INST_INIT
)
3425 // TODO: Optimize it later
3426 alpha_lda(code
, ins
->sreg2
, ins
->sreg2
,
3427 -(MONO_ARCH_LOCALLOC_ALIGNMENT
));
3428 alpha_blt(code
, ins
->sreg2
, 3);
3429 alpha_addq(code
, ins
->sreg2
, ins
->dreg
, alpha_at
);
3430 alpha_stq(code
, alpha_zero
, alpha_at
, 0);
3431 alpha_br(code
, alpha_zero
, -5);
3437 CFG_DEBUG(4) g_print("ALPHA_CHECK: [move] sreg=%d, dreg=%d\n",
3438 ins
->sreg1
, ins
->dreg
);
3439 alpha_mov1(code
, ins
->sreg1
, ins
->dreg
);
3446 CFG_DEBUG(4) g_print("ALPHA_CHECK: [cgt/cgt_un/icgt_un/int_cgt] dreg=%d\n",
3448 alpha_clr(code
, ins
->dreg
);
3449 alpha_cmoveq_(code
, alpha_at
, 1, ins
->dreg
);
3456 CFG_DEBUG(4) g_print("ALPHA_CHECK: [int_clt/int_clt_un/clt/clt_un] dreg=%d\n",
3458 alpha_clr(code
, ins
->dreg
);
3459 alpha_cmovne_(code
, alpha_at
, 1, ins
->dreg
);
3464 CFG_DEBUG(4) g_print("ALPHA_CHECK: [iceq/ceq] dreg=%d\n",
3466 alpha_clr(code
, ins
->dreg
);
3467 alpha_cmovne_(code
, alpha_at
, 1, ins
->dreg
);
3471 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fceq] dreg=%d\n",
3473 alpha_clr(code
, ins
->dreg
);
3474 alpha_fbeq(code
, alpha_at
, 1);
3475 alpha_lda(code
, ins
->dreg
, alpha_zero
, 1);
3478 alpha_cvttq_c(code, alpha_at, alpha_at);
3479 alpha_lda(code, alpha_sp, alpha_sp, -8);
3480 alpha_stt(code, alpha_at, alpha_sp, 0);
3481 alpha_ldq(code, alpha_at, alpha_sp, 0);
3482 alpha_lda(code, alpha_sp, alpha_sp, 8);
3484 alpha_cmovne_(code, alpha_at, 1, ins->dreg);
3489 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcgt] dreg=%d\n",
3491 alpha_clr(code
, ins
->dreg
);
3492 alpha_fbne(code
, alpha_at
, 1);
3493 alpha_lda(code
, ins
->dreg
, alpha_zero
, 1);
3496 alpha_cvttq_c(code, alpha_at, alpha_at);
3497 alpha_lda(code, alpha_sp, alpha_sp, -8);
3498 alpha_stt(code, alpha_at, alpha_sp, 0);
3499 alpha_ldq(code, alpha_at, alpha_sp, 0);
3500 alpha_lda(code, alpha_sp, alpha_sp, 8);
3502 alpha_cmoveq_(code, alpha_at, 1, ins->dreg);
3508 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt] dreg=%d\n",
3510 alpha_clr(code
, ins
->dreg
);
3511 alpha_fbeq(code
, alpha_at
, 1);
3512 alpha_lda(code
, ins
->dreg
, alpha_zero
, 1);
3516 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fclt_un] dreg=%d\n",
3519 alpha_clr(code
, ins
->dreg
);
3520 alpha_fbne(code
, (alpha_at
+1), 1);
3521 alpha_fbeq(code
, alpha_at
, 1);
3522 alpha_lda(code
, ins
->dreg
, alpha_zero
, 1);
3527 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibne_un] [");
3528 EMIT_ALPHA_BRANCH(ins
, alpha_at
, bne
);
3532 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbne_un] [");
3533 alpha_fbeq(code
, (alpha_at
+1), 1);
3534 alpha_cpys(code
, alpha_zero
, alpha_zero
, alpha_at
);
3535 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbeq
);
3539 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge_un] [");
3540 alpha_fbeq(code
, (alpha_at
+1), 1);
3541 alpha_cpys(code
, alpha_zero
, alpha_zero
, alpha_at
);
3542 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbeq
);
3546 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbge] [");
3547 alpha_fbne(code
, (alpha_at
+1), 1);
3548 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbeq
);
3552 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble_un] [");
3553 alpha_fbeq(code
, (alpha_at
+1), 1);
3554 alpha_cpys(code
, (alpha_at
+1), (alpha_at
+1), alpha_at
);
3555 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbne
);
3559 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fble] [");
3560 alpha_fbne(code
, (alpha_at
+1), 1);
3561 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbne
);
3565 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt_un] [");
3566 alpha_fbeq(code
, (alpha_at
+1), 1);
3567 alpha_cpys(code
, (alpha_at
+1), (alpha_at
+1), alpha_at
);
3568 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbne
);
3572 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fblt] [");
3573 alpha_fbne(code
, (alpha_at
+1), 1);
3574 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbne
);
3578 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt_un] [");
3579 alpha_fbeq(code
, (alpha_at
+1), 1);
3580 alpha_cpys(code
, alpha_zero
, alpha_zero
, alpha_at
);
3581 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbeq
);
3585 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbgt] [");
3586 alpha_fbne(code
, (alpha_at
+1), 1);
3587 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbeq
);
3591 CFG_DEBUG(4) g_print("ALPHA_CHECK: [ibeq] [");
3592 EMIT_ALPHA_BRANCH(ins
, alpha_at
, beq
);
3596 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fbeq] [");
3597 EMIT_ALPHA_BRANCH(ins
, alpha_at
, fbne
);
3601 CFG_DEBUG(4) g_print("ALPHA_CHECK: [beq] [");
3602 EMIT_ALPHA_BRANCH(ins
, alpha_at
, beq
);
3606 CFG_DEBUG(4) g_print("ALPHA_CHECK: [bne_un] [");
3607 EMIT_ALPHA_BRANCH(ins
, alpha_at
, bne
);
3611 CFG_DEBUG(4) g_print("ALPHA_CHECK: [label]\n");
3612 ins
->inst_c0
= (char *)code
- (char *)cfg
->native_code
;
3616 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br] target: %p, next: %p, curr: %p, last: %p [",
3617 ins
->inst_target_bb
, bb
->next_bb
, ins
, bb
->last_ins
);
3619 if (ins
->flags
& MONO_INST_BRLABEL
)
3621 if (ins
->inst_i0
->inst_c0
)
3623 CFG_DEBUG(4) g_print("inst_c0: %0lX, data: %p]\n",
3624 ins
->inst_i0
->inst_c0
,
3625 cfg
->native_code
+ ins
->inst_i0
->inst_c0
);
3626 alpha_br(code
, alpha_zero
, 0);
3630 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_LABEL offset: %0X, inst_i0: %p]\n",
3631 offset
, ins
->inst_i0
);
3632 mono_add_patch_info (cfg
, offset
,
3633 MONO_PATCH_INFO_LABEL
, ins
->inst_i0
);
3635 alpha_br(code
, alpha_zero
, 0);
3640 if (ins
->inst_target_bb
->native_offset
)
3642 // Somehow native offset is offset from
3643 // start of the code. So convert it to
3645 long br_offset
= (char *)cfg
->native_code
+
3646 ins
->inst_target_bb
->native_offset
- 4 - (char *)code
;
3648 CFG_DEBUG(4) g_print("jump to: native_offset: %0X, address %p]\n",
3649 ins
->inst_target_bb
->native_offset
,
3651 ins
->inst_target_bb
->native_offset
);
3652 alpha_br(code
, alpha_zero
, br_offset
/4);
3656 CFG_DEBUG(4) g_print("add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3657 offset
, ins
->inst_target_bb
);
3659 mono_add_patch_info (cfg
, offset
,
3661 ins
->inst_target_bb
);
3662 alpha_br(code
, alpha_zero
, 0);
3669 CFG_DEBUG(4) g_print("ALPHA_CHECK: [br_reg] sreg1=%d\n",
3672 alpha_jmp(code
, alpha_zero
, ins
->sreg1
, 0);
3680 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall/lcall/vcall/voidcall/call] Target: [");
3681 call
= (MonoCallInst
*)ins
;
3683 if (ins
->flags
& MONO_INST_HAS_METHOD
)
3685 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_METHOD] %p\n", call
->method
);
3686 code
= emit_call (cfg
, code
,
3687 MONO_PATCH_INFO_METHOD
, call
->method
);
3691 CFG_DEBUG(4) g_print("MONO_PATCH_INFO_ABS] %p\n", call
->fptr
);
3692 code
= emit_call (cfg
, code
,
3693 MONO_PATCH_INFO_ABS
, call
->fptr
);
3696 //code = emit_move_return_value (cfg, ins, code);
3703 case OP_VOIDCALL_REG
:
3708 CFG_DEBUG(4) g_print("ALPHA_CHECK: [fcall_reg/lcall_reg/vcall_reg/voidcall_reg/call_reg]: TargetReg: %d\n", ins
->sreg1
);
3709 call
= (MonoCallInst
*)ins
;
3711 alpha_mov1(code
, ins
->sreg1
, alpha_pv
);
3713 alpha_jsr(code
, alpha_ra
, alpha_pv
, 0);
3715 offset
= (char *)code
- (char *)cfg
->native_code
;
3718 ALPHA_LOAD_GP(offset
)
3719 alpha_ldah(code
, alpha_gp
, alpha_ra
, 0);
3720 alpha_lda(code
, alpha_gp
, alpha_gp
, 0);
3724 case OP_FCALL_MEMBASE
:
3725 case OP_CALL_MEMBASE
:
3726 case OP_LCALL_MEMBASE
:
3727 case OP_VCALL_MEMBASE
:
3731 CFG_DEBUG(4) g_print("ALPHA_CHECK: [(lvf)call_membase] basereg=%d, offset=%0lx\n",
3732 ins
->inst_basereg
, ins
->inst_offset
);
3733 call
= (MonoCallInst
*)ins
;
3735 alpha_ldq(code
, alpha_pv
, ins
->inst_basereg
, ins
->inst_offset
);
3736 alpha_jsr(code
, alpha_ra
, alpha_pv
, 0);
3738 offset
= (char *)code
- (char *)cfg
->native_code
;
3741 ALPHA_LOAD_GP(offset
)
3742 alpha_ldah(code
, alpha_gp
, alpha_ra
, 0);
3743 alpha_lda(code
, alpha_gp
, alpha_gp
, 0);
3747 case OP_VOIDCALL_MEMBASE
:
3751 CFG_DEBUG(4) g_print("ALPHA_CHECK: [voidcall_membase] basereg=%d, offset=%0lx\n",
3752 ins
->inst_basereg
, ins
->inst_offset
);
3753 call
= (MonoCallInst
*)ins
;
3755 alpha_ldq(code
, alpha_pv
, ins
->inst_basereg
, ins
->inst_offset
);
3756 alpha_jsr(code
, alpha_ra
, alpha_pv
, 0);
3758 offset
= (char *)code
- (char *)cfg
->native_code
;
3761 ALPHA_LOAD_GP(offset
)
3762 alpha_ldah(code
, alpha_gp
, alpha_ra
, 0);
3763 alpha_lda(code
, alpha_gp
, alpha_gp
, 0);
3767 case OP_START_HANDLER
:
3769 // TODO - find out when we called by call_handler or resume_context
3770 // of by call_filter. There should be difference. For now just
3771 // handle - call_handler
3773 CFG_DEBUG(4) g_print("ALPHA_CHECK: [start_handler] basereg=%d, offset=%0lx\n",
3774 ins
->inst_left
->inst_basereg
, ins
->inst_left
->inst_offset
);
3776 alpha_stq(code
, alpha_ra
, ins
->inst_left
->inst_basereg
,
3777 ins
->inst_left
->inst_offset
);
3783 // Keep in sync with start_handler
3784 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfinally] basereg=%d, offset=%0lx\n",
3785 ins
->inst_left
->inst_basereg
, ins
->inst_left
->inst_offset
);
3787 alpha_ldq(code
, alpha_ra
, ins
->inst_left
->inst_basereg
,
3788 ins
->inst_left
->inst_offset
);
3790 alpha_ret(code
, alpha_ra
, 1);
3796 // Keep in sync with start_handler
3797 CFG_DEBUG(4) g_print("ALPHA_CHECK: [endfilter] sreg1=%d, basereg=%d, offset=%0lx\n",
3798 ins
->sreg1
, ins
->inst_left
->inst_basereg
, ins
->inst_left
->inst_offset
);
3800 alpha_ldq(code
, alpha_ra
, ins
->inst_left
->inst_basereg
,
3801 ins
->inst_left
->inst_offset
);
3803 if (ins
->sreg1
!= -1 && ins
->sreg1
!= alpha_r0
)
3804 alpha_mov1(code
, ins
->sreg1
, alpha_r0
);
3806 alpha_ret(code
, alpha_ra
, 1);
3810 case OP_CALL_HANDLER
:
3814 offset
= (char *)code
- (char *)cfg
->native_code
;
3816 CFG_DEBUG(4) g_print("ALPHA_CHECK: [call_handler] add patch info: MONO_PATCH_INFO_BB offset: %0X, target_bb: %p]\n",
3817 offset
, ins
->inst_target_bb
);
3819 mono_add_patch_info (cfg
, offset
,
3821 ins
->inst_target_bb
);
3822 alpha_bsr(code
, alpha_ra
, 0);
3827 CFG_DEBUG(4) g_print("ALPHA_CHECK: [throw] sreg1=%0x\n",
3829 alpha_mov1(code
, ins
->sreg1
, alpha_a0
);
3830 code
= emit_call (cfg
, code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3831 (gpointer
)"mono_arch_throw_exception");
3835 CFG_DEBUG(4) g_print("ALPHA_CHECK: [rethrow] sreg1=%0x\n",
3837 alpha_mov1(code
, ins
->sreg1
, alpha_a0
);
3838 code
= emit_call (cfg
, code
, MONO_PATCH_INFO_INTERNAL_METHOD
,
3839 (gpointer
)"mono_arch_rethrow_exception");
3845 * Note: this 'frame destruction' logic is useful for tail calls,
3846 too. Keep in sync with the code in emit_epilog.
3849 AlphaGotData ge_data
;
3851 CFG_DEBUG(4) g_print("ALPHA_CHECK: [jmp] %p\n", ins
->inst_p0
);
3853 /* FIXME: no tracing support... */
3854 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
3855 code
= mono_arch_instrument_epilog (cfg
,
3856 mono_profiler_method_leave
, code
, FALSE
);
3857 g_assert (!cfg
->method
->save_lmf
);
3859 alpha_mov1( code
, alpha_fp
, alpha_sp
);
3861 code
= emit_load_volatile_arguments (cfg
, code
);
3863 offset
= cfg
->arch
.params_stack_size
;
3865 alpha_ldq( code
, alpha_ra
, alpha_sp
, (offset
+ 0) );
3866 alpha_ldq( code
, alpha_fp
, alpha_sp
, (offset
+ 8) );
3867 alpha_lda( code
, alpha_sp
, alpha_sp
, cfg
->arch
.stack_size
);
3869 ge_data
.data
.p
= ins
->inst_p0
;
3870 add_got_entry(cfg
, GT_PTR
, ge_data
,
3871 (char *)code
- (char *)cfg
->native_code
,
3872 MONO_PATCH_INFO_METHOD_JUMP
, ins
->inst_p0
);
3873 alpha_ldq( code
, alpha_pv
, alpha_gp
, 0);
3875 alpha_jsr( code
, alpha_zero
, alpha_pv
, 0);
3880 mono_add_patch_info (cfg
, offset
,
3881 (MonoJumpInfoType
)ins
->inst_i1
, ins
->inst_p0
);
3884 case OP_MEMORY_BARRIER
:
3885 CFG_DEBUG(4) g_print("ALPHA_CHECK: [mb]\n");
3890 // Float register contains a value which we need to check
3892 double ni
= -1.0 / 0.0;
3893 double pi
= 1.0 / 0.0;
3894 AlphaGotData ge_data
;
3896 CFG_DEBUG(4) g_print("ALPHA_TODO: [chfinite] sreg1=%d\n", ins
->sreg1
);
3897 alpha_cmptun_su(code
, ins
->sreg1
, ins
->sreg1
, alpha_at
);
3899 EMIT_COND_EXC_BRANCH(fbne
, alpha_at
, "ArithmeticException");
3901 // Negative infinity
3902 ge_data
.data
.d
= ni
;
3903 add_got_entry(cfg
, GT_DOUBLE
, ge_data
,
3904 (char *)code
- (char *)cfg
->native_code
,
3905 MONO_PATCH_INFO_NONE
, 0);
3906 alpha_ldt(code
, alpha_at
, alpha_gp
, 0);
3908 alpha_cmpteq_su(code
, ins
->sreg1
, alpha_at
, alpha_at
);
3911 EMIT_COND_EXC_BRANCH(fbne
, alpha_at
, "ArithmeticException");
3913 // Positive infinity
3914 ge_data
.data
.d
= pi
;
3915 add_got_entry(cfg
, GT_DOUBLE
, ge_data
,
3916 (char *)code
- (char *)cfg
->native_code
,
3917 MONO_PATCH_INFO_NONE
, 0);
3918 alpha_ldt(code
, alpha_at
, alpha_gp
, 0);
3920 alpha_cmpteq_su(code
, ins
->sreg1
, alpha_at
, alpha_at
);
3923 EMIT_COND_EXC_BRANCH(fbne
, alpha_at
, "ArithmeticException");
3927 CFG_DEBUG(4) g_print("ALPHA_TODO: [fdiv] dest=%d, sreg1=%d, sreg2=%d\n",
3928 ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
3929 alpha_divt_su(code
, ins
->sreg1
, ins
->sreg2
, ins
->dreg
);
3934 g_warning ("unknown opcode %s in %s()\n",
3935 mono_inst_name (ins
->opcode
), __FUNCTION__
);
3937 // g_assert_not_reached ();
3941 if ( (((char *)code
) -
3942 ((char *)cfg
->native_code
) -
3945 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
3946 mono_inst_name (ins
->opcode
), max_len
,
3947 ((char *)code
) - ((char *)cfg
->native_code
) - offset
);
3948 //g_assert_not_reached ();
3954 last_offset
= offset
;
3957 cfg
->code_len
= ((char *)code
) - ((char *)cfg
->native_code
);
3960 /*========================= End of Function ========================*/
3965 /*------------------------------------------------------------------*/
3967 /* Name - mono_arch_cpu_optimizazions */
3969 /* Function - Returns the optimizations supported on this CPU */
3971 /*------------------------------------------------------------------*/
3974 mono_arch_cpu_optimizazions (guint32
*exclude_mask
)
3978 if (getenv("MONO_ALPHA_DEBUG"))
3979 mini_alpha_verbose_level
= 1;
3981 ALPHA_DEBUG("mono_arch_cpu_optimizazions");
3983 /*----------------------------------------------------------*/
3984 /* no alpha-specific optimizations yet */
3985 /*----------------------------------------------------------*/
3986 *exclude_mask
= MONO_OPT_LINEARS
;
3987 // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
3991 /*========================= End of Function ========================*/
3993 /*------------------------------------------------------------------*/
3995 /* Name - mono_arch_flush_icache */
3997 /* Function - Flush the CPU icache. */
3999 /*------------------------------------------------------------------*/
4002 mono_arch_flush_icache (guint8
*code
, gint size
)
4004 //ALPHA_DEBUG("mono_arch_flush_icache");
4006 /* flush instruction cache to see trampoline code */
4007 asm volatile("imb":::"memory");
4010 /*========================= End of Function ========================*/
4012 /*------------------------------------------------------------------*/
4014 /* Name - mono_arch_regname */
4016 /* Function - Returns the name of the register specified by */
4017 /* the input parameter. */
4019 /*------------------------------------------------------------------*/
4022 mono_arch_regname (int reg
) {
4023 static const char * rnames
[] = {
4024 "alpha_r0", "alpha_r1", "alpha_r2", "alpha_r3", "alpha_r4",
4025 "alpha_r5", "alpha_r6", "alpha_r7", "alpha_r8", "alpha_r9",
4026 "alpha_r10", "alpha_r11", "alpha_r12", "alpha_r13", "alpha_r14",
4027 "alpha_r15", "alpha_r16", "alpha_r17", "alpha_r18", "alpha_r19",
4028 "alpha_r20", "alpha_r21", "alpha_r22", "alpha_r23", "alpha_r24",
4029 "alpha_r25", "alpha_r26", "alpha_r27", "alpha_r28", "alpha_r29",
4030 "alpha_r30", "alpha_r31"
4033 if (reg
>= 0 && reg
< 32)
4034 return rnames
[reg
];
4038 /*========================= End of Function ========================*/
4040 /*------------------------------------------------------------------*/
4042 /* Name - mono_arch_fregname */
4044 /* Function - Returns the name of the register specified by */
4045 /* the input parameter. */
4047 /*------------------------------------------------------------------*/
4050 mono_arch_fregname (int reg
) {
4051 static const char * rnames
[] = {
4052 "alpha_f0", "alpha_f1", "alpha_f2", "alpha_f3", "alpha_f4",
4053 "alpha_f5", "alpha_f6", "alpha_f7", "alpha_f8", "alpha_f9",
4054 "alpha_f10", "alpha_f11", "alpha_f12", "alpha_f13", "alpha_f14",
4055 "alpha_f15", "alpha_f16", "alpha_f17", "alpha_f18", "alpha_f19",
4056 "alpha_f20", "alpha_f21", "alpha_f22", "alpha_f23", "alpha_f24",
4057 "alpha_f25", "alpha_f26", "alpha_f27", "alpha_f28", "alpha_f29",
4058 "alpha_f30", "alpha_f31"
4061 if (reg
>= 0 && reg
< 32)
4062 return rnames
[reg
];
4067 /*========================= End of Function ========================*/
4069 /*------------------------------------------------------------------*/
4071 /* Name - mono_arch_patch_code */
4073 /* Function - Process the patch data created during the */
4074 /* instruction build process. This resolves jumps, */
4075 /* calls, variables etc. */
4077 /*------------------------------------------------------------------*/
4080 mono_arch_patch_code (MonoMethod
*method
, MonoDomain
*domain
,
4081 guint8
*code
, MonoJumpInfo
*ji
, gboolean run_cctors
)
4083 MonoJumpInfo
*patch_info
;
4084 gboolean compile_aot
= !run_cctors
;
4086 ALPHA_DEBUG("mono_arch_patch_code");
4088 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
)
4090 unsigned char *ip
= patch_info
->ip
.i
+ code
;
4091 const unsigned char *target
;
4093 target
= mono_resolve_patch_target (method
, domain
,
4094 code
, patch_info
, run_cctors
);
4098 switch (patch_info
->type
)
4101 case MONO_PATCH_INFO_BB
:
4102 case MONO_PATCH_INFO_LABEL
:
4105 /* No need to patch these */
4110 switch (patch_info
->type
)
4112 case MONO_PATCH_INFO_NONE
:
4115 case MONO_PATCH_INFO_GOT_OFFSET
:
4117 unsigned int *ip2
= (unsigned int *)ip
;
4118 unsigned int inst
= *ip2
;
4119 unsigned int off
= patch_info
->data
.offset
& 0xFFFFFFFF;
4121 g_assert(!(off
& 0xFFFF8000));
4129 case MONO_PATCH_INFO_CLASS_INIT
:
4131 /* Might already been changed to a nop */
4132 unsigned int* ip2
= (unsigned int *)ip
;
4133 unsigned long t_addr
= (unsigned long)target
;
4135 if (*ip2
!= (t_addr
& 0xFFFFFFFF) ||
4136 *(ip2
+1) != ((t_addr
>>32) & 0xFFFFFFFF))
4138 // amd64_call_code (ip2, 0);
4142 // case MONO_PATCH_INFO_METHOD_REL:
4143 case MONO_PATCH_INFO_R8
:
4144 case MONO_PATCH_INFO_R4
:
4145 g_assert_not_reached ();
4147 case MONO_PATCH_INFO_BB
:
4150 case MONO_PATCH_INFO_METHOD
:
4151 case MONO_PATCH_INFO_METHODCONST
:
4152 case MONO_PATCH_INFO_INTERNAL_METHOD
:
4153 case MONO_PATCH_INFO_METHOD_JUMP
:
4155 volatile unsigned int *p
= (unsigned int *)ip
;
4156 unsigned long t_addr
;
4163 g_debug("ALPHA_PATCH: MONO_PATCH_INFO_METHOD(CONST) calc target: %p, stored target: %0lX",
4165 if (target
!= ((void *)t_addr
))
4167 t_addr
= (unsigned long)target
;
4168 *p
= (unsigned int)(t_addr
& 0xFFFFFFFF);
4169 *(p
+1) = (unsigned int)((t_addr
>> 32) & 0xFFFFFFFF);
4174 case MONO_PATCH_INFO_ABS
:
4176 volatile unsigned int *p
= (unsigned int *)ip
;
4177 unsigned long t_addr
;
4183 ALPHA_PRINT
g_debug("ALPHA_PATCH: MONO_PATCH_INFO_ABS calc target: %p, stored target: %0lX",
4188 case MONO_PATCH_INFO_SWITCH
:
4190 unsigned int *pcode
= (unsigned int *)ip
;
4191 unsigned long t_addr
;
4193 t_addr
= (unsigned long)target
;
4195 if (((unsigned long)ip
) % 8)
4201 //alpha_ldq(pcode, alpha_at, alpha_gp, (ip - code + 8));
4202 alpha_nop(pcode
); // TODO optimize later
4203 alpha_bsr(pcode
, alpha_at
, 2);
4205 *pcode
= (unsigned int)(t_addr
& 0xFFFFFFFF);
4207 *pcode
= (unsigned int)((t_addr
>> 32) & 0xFFFFFFFF);
4210 alpha_ldq(pcode
, alpha_at
, alpha_at
, 0);
4220 volatile unsigned int *p
= (unsigned int *)ip
;
4221 unsigned int alpha_ins
= *p
;
4222 unsigned int opcode
;
4225 opcode
= (alpha_ins
>> AXP_OP_SHIFT
) & AXP_OFF6_MASK
;
4227 if (opcode
>= 0x30 && opcode
<= 0x3f)
4229 // This is branch with offset instruction
4230 br_offset
= (target
- ip
- 4);
4232 g_assert(!(br_offset
& 3));
4234 alpha_ins
|= (br_offset
/4) & AXP_OFF21_MASK
;
4242 /*========================= End of Function ========================*/
4243 /*------------------------------------------------------------------*/
4245 /* Name - mono_arch_emit_this_vret_args */
4249 /*------------------------------------------------------------------*/
4252 mono_arch_emit_this_vret_args (MonoCompile
*cfg
, MonoCallInst
*inst
,
4253 int this_reg
, int this_type
, int vt_reg
)
4255 MonoCallInst
*call
= (MonoCallInst
*)inst
;
4256 CallInfo
* cinfo
= get_call_info (cfg
->generic_sharing_context
, inst
->signature
, FALSE
);
4258 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_emit_this_vret_args");
4264 if (cinfo
->ret
.storage
== ArgValuetypeInReg
)
4267 * The valuetype is in RAX:RDX after the call, need to be copied to
4268 * the stack. Push the address here, so the call instruction can
4271 //MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
4272 //vtarg->sreg1 = vt_reg;
4273 //mono_bblock_add_inst (cfg->cbb, vtarg);
4276 //MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_E
4281 MONO_INST_NEW (cfg
, vtarg
, OP_MOVE
);
4282 vtarg
->sreg1
= vt_reg
;
4283 vtarg
->dreg
= mono_alloc_ireg (cfg
);
4284 mono_bblock_add_inst (cfg
->cbb
, vtarg
);
4286 mono_call_inst_add_outarg_reg (cfg
, call
, vtarg
->dreg
,
4287 cinfo
->ret
.reg
, FALSE
);
4291 /* add the this argument */
4295 MONO_INST_NEW (cfg
, this, OP_MOVE
);
4296 this->type
= this_type
;
4297 this->sreg1
= this_reg
;
4298 this->dreg
= mono_alloc_ireg (cfg
);
4299 mono_bblock_add_inst (cfg
->cbb
, this);
4301 mono_call_inst_add_outarg_reg (cfg
, call
, this->dreg
,
4302 cinfo
->args
[0].reg
, FALSE
);
4308 /*========================= End of Function ========================*/
4310 /*------------------------------------------------------------------*/
4312 /* Name - mono_arch_is_inst_imm */
4314 /* Function - Determine if operand qualifies as an immediate */
4315 /* value. For Alpha this is a value 0 - 255 */
4317 /* Returns - True|False - is [not] immediate value. */
4319 /*------------------------------------------------------------------*/
4322 mono_arch_is_inst_imm (gint64 imm
)
4324 // ALPHA_DEBUG("mono_arch_is_inst_imm");
4326 return (imm
& ~(0x0FFL
)) ? 0 : 1;
4329 /*------------------------------------------------------------------*/
4331 /* Name - mono_arch_setup_jit_tls_data */
4333 /* Function - Setup the JIT's Thread Level Specific Data. */
4335 /*------------------------------------------------------------------*/
4338 mono_arch_setup_jit_tls_data (MonoJitTlsData
*tls
)
4340 ALPHA_DEBUG("mono_arch_setup_jit_tls_data");
4342 if (!tls_offset_inited
) {
4343 tls_offset_inited
= TRUE
;
4346 if (!lmf_addr_key_inited
) {
4347 lmf_addr_key_inited
= TRUE
;
4348 pthread_key_create (&lmf_addr_key
, NULL
);
4351 pthread_setspecific (lmf_addr_key
, &tls
->lmf
);
4354 /*------------------------------------------------------------------*/
4356 /* Name - mono_arch_cpu_init */
4358 /* Function - Perform CPU specific initialization to execute */
4361 /*------------------------------------------------------------------*/
4364 mono_arch_cpu_init (void)
4366 unsigned long amask
, implver
;
4367 register long v0
__asm__("$0") = -1;
4369 ALPHA_DEBUG("mono_arch_cpu_init");
4371 __asm__ (".long 0x47e00c20" : "=r"(v0
) : "0"(v0
));
4373 __asm__ (".long 0x47e03d80" : "=r"(v0
));
4379 //printf("amask: %x, implver: %x", amask, implver);
4383 * Initialize architecture specific code.
4386 mono_arch_init (void)
4391 * Cleanup architecture specific code.
4394 mono_arch_cleanup (void)
4401 * Obtain information about a call according to the calling convention.
4403 * For x86 ELF, see the "System V Application Binary Interface Intel386
4404 * Architecture Processor Supplment, Fourth Edition" document for more
4406 * For x86 win32, see ???.
4409 get_call_info (MonoGenericSharingContext
*gsctx
, MonoMethodSignature
*sig
, gboolean is_pinvoke
)
4411 guint32 i
, gr
, fr
, *pgr
, *pfr
;
4413 int n
= sig
->hasthis
+ sig
->param_count
;
4414 guint32 stack_size
= 0;
4417 cinfo
= g_malloc0 (sizeof (CallInfo
) + (sizeof (ArgInfo
) * n
));
4432 ret_type
= mono_type_get_underlying_type (sig
->ret
);
4433 switch (ret_type
->type
) {
4434 case MONO_TYPE_BOOLEAN
:
4439 case MONO_TYPE_CHAR
:
4445 case MONO_TYPE_FNPTR
:
4446 case MONO_TYPE_CLASS
:
4447 case MONO_TYPE_OBJECT
:
4448 case MONO_TYPE_SZARRAY
:
4449 case MONO_TYPE_ARRAY
:
4450 case MONO_TYPE_STRING
:
4451 cinfo
->ret
.storage
= ArgInIReg
;
4452 cinfo
->ret
.reg
= alpha_r0
;
4456 cinfo
->ret
.storage
= ArgInIReg
;
4457 cinfo
->ret
.reg
= alpha_r0
;
4460 cinfo
->ret
.storage
= ArgInFloatReg
;
4461 cinfo
->ret
.reg
= alpha_f0
;
4464 cinfo
->ret
.storage
= ArgInDoubleReg
;
4465 cinfo
->ret
.reg
= alpha_f0
;
4467 case MONO_TYPE_GENERICINST
:
4468 if (!mono_type_generic_inst_is_valuetype (sig
->ret
))
4470 cinfo
->ret
.storage
= ArgInIReg
;
4471 cinfo
->ret
.reg
= alpha_r0
;
4475 case MONO_TYPE_VALUETYPE
:
4477 guint32 tmp_gr
= 0, tmp_fr
= 0, tmp_stacksize
= 0;
4479 add_valuetype (gsctx
, sig
, &cinfo
->ret
, sig
->ret
, TRUE
,
4480 &tmp_gr
, &tmp_fr
, &tmp_stacksize
);
4482 if (cinfo
->ret
.storage
== ArgOnStack
)
4483 /* The caller passes the address where the value
4485 add_general (pgr
, &stack_size
, &cinfo
->ret
);
4488 case MONO_TYPE_TYPEDBYREF
:
4489 /* Same as a valuetype with size 24 */
4490 add_general (pgr
, &stack_size
, &cinfo
->ret
);
4493 case MONO_TYPE_VOID
:
4496 g_error ("Can't handle as return value 0x%x", sig
->ret
->type
);
4502 add_general (pgr
, &stack_size
, cinfo
->args
+ 0);
4504 if (!sig
->pinvoke
&&
4505 (sig
->call_convention
== MONO_CALL_VARARG
) && (n
== 0))
4508 fr
= FLOAT_PARAM_REGS
;
4510 /* Emit the signature cookie just before the implicit arguments
4512 add_general (pgr
, &stack_size
, &cinfo
->sig_cookie
);
4515 for (i
= 0; i
< sig
->param_count
; ++i
)
4517 ArgInfo
*ainfo
= &cinfo
->args
[sig
->hasthis
+ i
];
4520 if (!sig
->pinvoke
&&
4521 (sig
->call_convention
== MONO_CALL_VARARG
) &&
4522 (i
== sig
->sentinelpos
))
4524 /* We allways pass the sig cookie on the stack for simpl
4527 * Prevent implicit arguments + the sig cookie from being passed
4531 fr
= FLOAT_PARAM_REGS
;
4533 /* Emit the signature cookie just before the implicit arguments */
4534 add_general (pgr
, &stack_size
, &cinfo
->sig_cookie
);
4537 if (sig
->params
[i
]->byref
) {
4538 add_general (pgr
, &stack_size
, ainfo
);
4542 ptype
= mono_type_get_underlying_type (sig
->params
[i
]);
4544 switch (ptype
->type
) {
4545 case MONO_TYPE_BOOLEAN
:
4548 add_general (pgr
, &stack_size
, ainfo
);
4552 case MONO_TYPE_CHAR
:
4553 add_general (pgr
, &stack_size
, ainfo
);
4557 add_general (pgr
, &stack_size
, ainfo
);
4562 case MONO_TYPE_FNPTR
:
4563 case MONO_TYPE_CLASS
:
4564 case MONO_TYPE_OBJECT
:
4565 case MONO_TYPE_STRING
:
4566 case MONO_TYPE_SZARRAY
:
4567 case MONO_TYPE_ARRAY
:
4568 add_general (pgr
, &stack_size
, ainfo
);
4570 case MONO_TYPE_GENERICINST
:
4571 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
]))
4573 add_general (pgr
, &stack_size
, ainfo
);
4577 case MONO_TYPE_VALUETYPE
:
4579 /* We allways pass valuetypes on the stack */
4580 add_valuetype (gsctx
, sig
, ainfo
, sig
->params
[i
],
4581 FALSE
, pgr
, pfr
, &stack_size
);
4583 case MONO_TYPE_TYPEDBYREF
:
4584 stack_size
+= sizeof (MonoTypedRef
);
4585 ainfo
->storage
= ArgOnStack
;
4589 add_general (pgr
, &stack_size
, ainfo
);
4592 add_float (pfr
, &stack_size
, ainfo
, FALSE
);
4595 add_float (pfr
, &stack_size
, ainfo
, TRUE
);
4598 g_assert_not_reached ();
4602 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
) &&
4603 (n
> 0) && (sig
->sentinelpos
== sig
->param_count
))
4606 fr
= FLOAT_PARAM_REGS
;
4608 /* Emit the signature cookie just before the implicit arguments
4610 add_general (pgr
, &stack_size
, &cinfo
->sig_cookie
);
4613 cinfo
->stack_usage
= stack_size
;
4614 cinfo
->reg_usage
= gr
;
4615 cinfo
->freg_usage
= fr
;
4620 static const char *CvtMonoType(MonoTypeEnum t
)
4625 return "MONO_TYPE_END";
4626 case MONO_TYPE_VOID
:
4627 return "MONO_TYPE_VOID";
4628 case MONO_TYPE_BOOLEAN
:
4629 return "MONO_TYPE_BOOLEAN";
4630 case MONO_TYPE_CHAR
:
4631 return "MONO_TYPE_CHAR";
4633 return "MONO_TYPE_I1";
4635 return "MONO_TYPE_U1";
4637 return "MONO_TYPE_I2";
4639 return "MONO_TYPE_U2";
4641 return "MONO_TYPE_I4";
4643 return "MONO_TYPE_U4";
4645 return "MONO_TYPE_I8";
4647 return "MONO_TYPE_U8";
4649 return "MONO_TYPE_R4";
4651 return "MONO_TYPE_R8";
4652 case MONO_TYPE_STRING
:
4653 return "MONO_TYPE_STRING";
4655 return "MONO_TYPE_PTR";
4656 case MONO_TYPE_BYREF
:
4657 return "MONO_TYPE_BYREF";
4658 case MONO_TYPE_VALUETYPE
:
4659 return "MONO_TYPE_VALUETYPE";
4660 case MONO_TYPE_CLASS
:
4661 return "MONO_TYPE_CLASS";
4663 return "MONO_TYPE_VAR";
4664 case MONO_TYPE_ARRAY
:
4665 return "MONO_TYPE_ARRAY";
4666 case MONO_TYPE_GENERICINST
:
4667 return "MONO_TYPE_GENERICINST";
4668 case MONO_TYPE_TYPEDBYREF
:
4669 return "MONO_TYPE_TYPEDBYREF";
4671 return "MONO_TYPE_I";
4673 return "MONO_TYPE_U";
4674 case MONO_TYPE_FNPTR
:
4675 return "MONO_TYPE_FNPTR";
4676 case MONO_TYPE_OBJECT
:
4677 return "MONO_TYPE_OBJECT";
4678 case MONO_TYPE_SZARRAY
:
4679 return "MONO_TYPE_SZARRAY";
4680 case MONO_TYPE_MVAR
:
4681 return "MONO_TYPE_MVAR";
4682 case MONO_TYPE_CMOD_REQD
:
4683 return "MONO_TYPE_CMOD_REQD";
4684 case MONO_TYPE_CMOD_OPT
:
4685 return "MONO_TYPE_CMOD_OPT";
4686 case MONO_TYPE_INTERNAL
:
4687 return "MONO_TYPE_INTERNAL";
4688 case MONO_TYPE_MODIFIER
:
4689 return "MONO_TYPE_MODIFIER";
4690 case MONO_TYPE_SENTINEL
:
4691 return "MONO_TYPE_SENTINEL";
4692 case MONO_TYPE_PINNED
:
4693 return "MONO_TYPE_PINNED";
4701 /*------------------------------------------------------------------*/
4703 /* Name - mono_arch_call_opcode */
4705 /* Function - Take the arguments and generate the arch-specific */
4706 /* instructions to properly call the function. This */
4707 /* includes pushing, moving argments to the correct */
4710 * This method is called during converting method to IR
4711 * We need to generate IR ints to follow calling convention
4712 * cfg - points to currently compiled unit
4714 * call - points to structure that describes what we are going to
4715 * call (at least number of parameters required for the call)
4718 * On return we need to pass back modified call structure
4720 /*------------------------------------------------------------------*/
4723 mono_arch_call_opcode (MonoCompile
*cfg
, MonoBasicBlock
* bb
,
4724 MonoCallInst
*call
, int is_virtual
)
4727 MonoMethodSignature
*sig
;
4732 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_call_opcode");
4734 sig
= call
->signature
;
4735 n
= sig
->param_count
+ sig
->hasthis
;
4737 // Collect info about method we age going to call
4738 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
, sig
->pinvoke
);
4740 CFG_DEBUG(3) g_print("ALPHA: Will call %s method with %d(%d) params. RetType: %s(0x%X)\n",
4741 sig
->pinvoke
? "PInvoke" : "Managed",
4742 sig
->param_count
, sig
->hasthis
,
4743 CvtMonoType(sig
->ret
->type
), sig
->ret
->type
);
4745 if (cinfo
->stack_usage
> cfg
->arch
.params_stack_size
)
4746 cfg
->arch
.params_stack_size
= cinfo
->stack_usage
;
4748 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
))
4749 sentinelpos
= sig
->sentinelpos
+ (is_virtual
? 1 : 0);
4751 for (i
= 0; i
< n
; ++i
)
4753 ArgInfo
*ainfo
= cinfo
->args
+ i
;
4755 /* Emit the signature cookie just before the implicit arguments
4757 if (!sig
->pinvoke
&&
4758 (sig
->call_convention
== MONO_CALL_VARARG
) &&
4761 MonoMethodSignature
*tmp_sig
;
4764 /* FIXME: Add support for signature tokens to AOT */
4765 cfg
->disable_aot
= TRUE
;
4766 MONO_INST_NEW (cfg
, arg
, OP_OUTARG
);
4769 * mono_ArgIterator_Setup assumes the signature cookie is
4770 * passed first and all the arguments which were before it are
4771 * passed on the stack after the signature. So compensate by
4772 * passing a different signature.
4774 tmp_sig
= mono_metadata_signature_dup (call
->signature
);
4775 tmp_sig
->param_count
-= call
->signature
->sentinelpos
;
4776 tmp_sig
->sentinelpos
= 0;
4777 memcpy (tmp_sig
->params
,
4778 call
->signature
->params
+ call
->signature
->sentinelpos
,
4779 tmp_sig
->param_count
* sizeof (MonoType
*));
4781 MONO_INST_NEW (cfg
, sig_arg
, OP_ICONST
);
4782 sig_arg
->inst_p0
= tmp_sig
;
4784 MONO_INST_NEW (cfg
, arg
, OP_OUTARG
);
4785 arg
->inst_left
= sig_arg
;
4786 arg
->type
= STACK_PTR
;
4788 /* prepend, so they get reversed */
4789 arg
->next
= call
->out_args
;
4790 call
->out_args
= arg
;
4793 if (is_virtual
&& i
== 0) {
4794 /* the argument will be attached to the call instrucion
4796 in
= call
->args
[i
];
4800 MONO_INST_NEW (cfg
, arg
, OP_OUTARG
);
4801 in
= call
->args
[i
];
4802 arg
->cil_code
= in
->cil_code
;
4803 arg
->inst_left
= in
;
4804 arg
->type
= in
->type
;
4805 /* prepend, so they get reversed */
4806 arg
->next
= call
->out_args
;
4807 call
->out_args
= arg
;
4809 CFG_DEBUG(3) g_print("ALPHA: Param[%d] - ", i
);
4811 if (sig
->hasthis
&& (i
== 0))
4812 arg_type
= &mono_defaults
.object_class
->byval_arg
;
4814 arg_type
= sig
->params
[i
- sig
->hasthis
];
4816 if ((i
>= sig
->hasthis
) &&
4817 (MONO_TYPE_ISSTRUCT(arg_type
)))
4822 if (arg_type
->type
== MONO_TYPE_TYPEDBYREF
) {
4823 size
= sizeof (MonoTypedRef
);
4824 align
= sizeof (gpointer
);
4828 size
= mono_type_native_stack_size (&in
->klass
->byval_arg
,
4831 size
= mini_type_stack_size (cfg
->generic_sharing_context
, &in
->klass
->byval_arg
, &align
);
4833 if (ainfo
->storage
== ArgAggregate
)
4835 MonoInst
*vtaddr
, *load
, *load2
, *offset_ins
, *set_reg
;
4838 CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size
);
4840 vtaddr
= mono_compile_create_var (cfg
,
4841 &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
4844 * Part of the structure is passed in registers.
4846 for (j
= 0; j
< ainfo
->nregs
; ++j
)
4848 int offset
, load_op
, dest_reg
, arg_storage
;
4850 slot
= ainfo
->reg
+ j
;
4851 load_op
= CEE_LDIND_I
;
4853 dest_reg
= ainfo
->reg
+ j
;
4854 arg_storage
= ArgInIReg
;
4856 MONO_INST_NEW (cfg
, load
, CEE_LDIND_I
);
4857 load
->ssa_op
= MONO_SSA_LOAD
;
4858 load
->inst_i0
= (cfg
)->varinfo
[vtaddr
->inst_c0
];
4860 NEW_ICONST (cfg
, offset_ins
, offset
);
4861 MONO_INST_NEW (cfg
, load2
, CEE_ADD
);
4862 load2
->inst_left
= load
;
4863 load2
->inst_right
= offset_ins
;
4865 MONO_INST_NEW (cfg
, load
, load_op
);
4866 load
->inst_left
= load2
;
4871 MONO_INST_NEW (cfg
, set_reg
, OP_OUTARG_REG
);
4873 add_outarg_reg (cfg
, call
, set_reg
, arg_storage
,
4875 if (set_reg
!= call
->out_args
)
4877 set_reg
->next
= call
->out_args
;
4878 call
->out_args
= set_reg
;
4883 * Part of the structure is passed on the stack.
4885 for (j
= ainfo
->nregs
; j
< ainfo
->nslots
; ++j
)
4889 slot
= ainfo
->reg
+ j
;
4891 MONO_INST_NEW (cfg
, load
, CEE_LDIND_I
);
4892 load
->ssa_op
= MONO_SSA_LOAD
;
4893 load
->inst_i0
= (cfg
)->varinfo
[vtaddr
->inst_c0
];
4895 NEW_ICONST (cfg
, offset_ins
, (j
* sizeof (gpointer
)));
4896 MONO_INST_NEW (cfg
, load2
, CEE_ADD
);
4897 load2
->inst_left
= load
;
4898 load2
->inst_right
= offset_ins
;
4900 MONO_INST_NEW (cfg
, load
, CEE_LDIND_I
);
4901 load
->inst_left
= load2
;
4906 MONO_INST_NEW (cfg
, outarg
, OP_OUTARG
);
4908 outarg
->inst_left
= load
;
4909 //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
4910 outarg
->dreg
= ainfo
->offset
+ (slot
- 22) * 8;
4912 if (outarg
!= call
->out_args
)
4914 outarg
->next
= call
->out_args
;
4915 call
->out_args
= outarg
;
4919 /* Trees can't be shared so make a copy*/
4920 MONO_INST_NEW (cfg
, arg
, CEE_STIND_I
);
4921 arg
->cil_code
= in
->cil_code
;
4922 arg
->ssa_op
= MONO_SSA_STORE
;
4923 arg
->inst_left
= vtaddr
;
4924 arg
->inst_right
= in
;
4925 arg
->type
= in
->type
;
4927 /* prepend, so they get reversed */
4928 arg
->next
= call
->out_args
;
4929 call
->out_args
= arg
;
4933 MonoInst
*stack_addr
;
4935 CFG_DEBUG(3) g_print("value type, size:%d\n", size
);
4937 MONO_INST_NEW (cfg
, stack_addr
, OP_REGOFFSET
);
4938 stack_addr
->inst_basereg
= alpha_sp
;
4939 //stack_addr->inst_offset = -(cinfo->stack_usage - ainfo->offset);
4940 stack_addr
->inst_offset
= ainfo
->offset
;
4941 //stack_addr->inst_offset = 16 + ainfo->offset;
4942 stack_addr
->inst_imm
= size
;
4944 arg
->opcode
= OP_OUTARG_VT
;
4945 arg
->inst_right
= stack_addr
;
4949 arg->opcode = OP_OUTARG_VT;
4950 arg->klass = in->klass;
4951 arg->backend.is_pinvoke = sig->pinvoke;
4952 arg->inst_imm = size; */
4956 CFG_DEBUG(3) g_print("simple\n");
4958 switch (ainfo
->storage
)
4961 add_outarg_reg (cfg
, call
, arg
, ainfo
->storage
,
4965 arg
->opcode
= OP_OUTARG
;
4966 //arg->dreg = -((n - i) * 8);
4967 arg
->dreg
= ainfo
->offset
;
4968 //arg->inst_left->inst_imm = (n - i - 1) * 8;
4970 if (!sig
->params
[i
-sig
->hasthis
]->byref
) {
4971 if (sig
->params
[i
-sig
->hasthis
]->type
== MONO_TYPE_R4
)
4972 arg
->opcode
= OP_OUTARG_R4
;
4974 if (sig
->params
[i
-sig
->hasthis
]->type
== MONO_TYPE_R8
)
4975 arg
->opcode
= OP_OUTARG_R8
;
4979 case ArgInDoubleReg
:
4980 add_outarg_reg (cfg
, call
, arg
, ainfo
->storage
, ainfo
->reg
, in
);
4983 g_assert_not_reached ();
4989 if (sig
->ret
&& MONO_TYPE_ISSTRUCT (sig
->ret
))
4991 if (cinfo
->ret
.storage
== ArgValuetypeInReg
) {
4992 MonoInst
*zero_inst
;
4994 * After the call, the struct is in registers, but needs to be saved
4995 to the memory pointed
4996 * to by vt_arg in this_vret_args. This means that vt_ar
4997 g needs to be saved somewhere
4998 * before calling the function. So we add a dummy instru
4999 ction to represent pushing the
5000 * struct return address to the stack. The return addres
5001 s will be saved to this stack slot
5002 * by the code emitted in this_vret_args.
5004 MONO_INST_NEW (cfg
, arg
, OP_OUTARG
);
5005 MONO_INST_NEW (cfg
, zero_inst
, OP_ICONST
);
5006 zero_inst
->inst_p0
= 0;
5007 arg
->inst_left
= zero_inst
;
5008 arg
->type
= STACK_PTR
;
5009 /* prepend, so they get reversed */
5010 arg
->next
= call
->out_args
;
5011 call
->out_args
= arg
;
5014 /* if the function returns a struct, the called method a
5015 lready does a ret $0x4 */
5016 if (sig
->ret
&& MONO_TYPE_ISSTRUCT (sig
->ret
))
5017 ; //cinfo->stack_usage -= 4;
5020 // stack_usage shows how much stack we would need to do the call
5021 // (for example for params that we pass on stack
5022 call
->stack_usage
= cinfo
->stack_usage
;
5024 // Save all used regs to do the call in compile unit structure
5025 cfg
->used_int_regs
|= call
->used_iregs
;
5032 /*========================= End of Function ========================*/
5034 /*------------------------------------------------------------------*/
5036 /* Name - mono_arch_register_lowlevel_calls */
5038 /* Function - Register routines to help with --trace operation. */
5040 /*------------------------------------------------------------------*/
5043 mono_arch_register_lowlevel_calls (void)
5045 ALPHA_DEBUG("mono_arch_register_lowlevel_calls");
5047 mono_register_jit_icall (mono_arch_get_lmf_addr
, "mono_arch_get_lmf_addr",
5051 /*========================= End of Function ========================*/
5053 /*------------------------------------------------------------------*/
5055 /* Name - mono_arch_global_int_regs */
5057 /* Function - Return a list of usable integer registers. */
5059 /*------------------------------------------------------------------*/
5062 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
5066 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_global_int_regs");
5068 // regs = g_list_prepend (regs, (gpointer)alpha_r9);
5069 // regs = g_list_prepend (regs, (gpointer)alpha_r10);
5070 // regs = g_list_prepend (regs, (gpointer)alpha_r11);
5071 regs
= g_list_prepend (regs
, (gpointer
)alpha_r12
);
5072 regs
= g_list_prepend (regs
, (gpointer
)alpha_r13
);
5073 regs
= g_list_prepend (regs
, (gpointer
)alpha_r14
);
5078 /*========================= End of Function ========================*/
5080 /*------------------------------------------------------------------*/
5082 /* Name - mono_arch_get_allocatable_int_vars */
5086 /*------------------------------------------------------------------*/
5089 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
5093 MonoMethodSignature
*sig
;
5094 MonoMethodHeader
*header
;
5097 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_allocatable_int_vars");
5099 header
= mono_method_get_header (cfg
->method
);
5101 sig
= mono_method_signature (cfg
->method
);
5103 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
, FALSE
);
5105 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
)
5107 MonoInst
*ins
= cfg
->args
[i
];
5109 ArgInfo
*ainfo
= &cinfo
->args
[i
];
5112 (MONO_INST_IS_DEAD
|MONO_INST_VOLATILE
|MONO_INST_INDIRECT
))
5115 // if (ainfo->storage == ArgInIReg) {
5116 // /* The input registers are non-volatile */
5117 // ins->opcode = OP_REGVAR;
5118 //ins->dreg = 32 + ainfo->reg;
5122 for (i
= 0; i
< cfg
->num_varinfo
; i
++)
5124 MonoInst
*ins
= cfg
->varinfo
[i
];
5125 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
5128 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
5132 (MONO_INST_IS_DEAD
|MONO_INST_VOLATILE
|MONO_INST_INDIRECT
)) ||
5133 (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
5136 if (mono_is_regsize_var (ins
->inst_vtype
))
5138 g_assert (MONO_VARINFO (cfg
, i
)->reg
== -1);
5139 g_assert (i
== vmv
->idx
);
5140 vars
= g_list_prepend (vars
, vmv
);
5144 vars
= mono_varlist_sort (cfg
, vars
, 0);
5149 /*========================= End of Function ========================*/
5151 /*------------------------------------------------------------------*/
5153 /* Name - mono_arch_get_domain_intrinsic */
5159 /*------------------------------------------------------------------*/
5162 mono_arch_get_domain_intrinsic (MonoCompile
* cfg
)
5166 if (appdomain_tls_offset
== -1)
5169 MONO_INST_NEW (cfg
, ins
, OP_TLS_GET
);
5170 ins
->inst_offset
= appdomain_tls_offset
;
5174 /*========================= End of Function ========================*/
5176 /*------------------------------------------------------------------*/
5178 /* Name - mono_arch_get_thread_intrinsic */
5184 /*------------------------------------------------------------------*/
5187 mono_arch_get_thread_intrinsic (MonoCompile
* cfg
)
5191 if (thread_tls_offset
== -1)
5194 MONO_INST_NEW (cfg
, ins
, OP_TLS_GET
);
5195 ins
->inst_offset
= thread_tls_offset
;
5199 /*========================= End of Function ========================*/
5201 /*------------------------------------------------------------------*/
5203 /* Name - mono_arch_get_inst_for_method */
5205 /* Function - Check for opcodes we can handle directly in */
5208 /*------------------------------------------------------------------*/
5211 mono_arch_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
,
5212 MonoMethodSignature
*fsig
, MonoInst
**args
)
5214 MonoInst
*ins
= NULL
;
5216 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_get_inst_for_method");
5218 CFG_DEBUG(3) g_print("mono_arch_get_inst_for_method: %s\n", cmethod
->name
);
5223 /*========================= End of Function ========================*/
5225 /*------------------------------------------------------------------*/
5227 /* Name - mono_arch_create_class_init_trampoline */
5229 /* Function - Creates a trampoline function to run a type init- */
5230 /* ializer. If the trampoline is called, it calls */
5231 /* mono_runtime_class_init with the given vtable, */
5232 /* then patches the caller code so it does not get */
5233 /* called any more. */
5235 /* Parameter - vtable - The type to initialize */
5237 /* Returns - A pointer to the newly created code */
5239 /*------------------------------------------------------------------*/
5242 mono_arch_create_class_init_trampoline (MonoVTable
*vtable
)
5244 ALPHA_DEBUG("mono_arch_create_class_init_trampoline");
5251 /*------------------------------------------------------------------*/
5253 /* Name - mono_arch_instrument_prolog */
5255 /* Function - Create an "instrumented" prolog. */
5257 /*------------------------------------------------------------------*/
5260 mono_arch_instrument_prolog (MonoCompile
*cfg
, void *func
, void *p
,
5261 gboolean enable_arguments
)
5263 unsigned int *code
= p
;
5266 CallInfo
*cinfo
= NULL
;
5267 MonoMethodSignature
*sig
;
5269 int i
, n
, stack_area
= 0;
5270 AlphaGotData ge_data
;
5272 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_prolog");
5274 /* Keep this in sync with mono_arch_get_argument_info */
5275 if (enable_arguments
)
5277 /* Allocate a new area on the stack and save arguments there */
5278 sig
= mono_method_signature (cfg
->method
);
5280 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
, FALSE
);
5282 n
= sig
->param_count
+ sig
->hasthis
;
5284 stack_area
= ALIGN_TO (n
* 8, 8);
5286 // Correct stack by calculated value
5288 alpha_lda(code
, alpha_sp
, alpha_sp
, -stack_area
);
5290 for (i
= 0; i
< n
; ++i
)
5292 inst
= cfg
->args
[i
];
5294 if (inst
->opcode
== OP_REGVAR
)
5296 switch(cinfo
->args
[i
].storage
)
5298 case ArgInDoubleReg
:
5299 alpha_stt(code
, inst
->dreg
, alpha_sp
, (i
*8));
5302 alpha_sts(code
, inst
->dreg
, alpha_sp
, (i
*8));
5305 alpha_stq(code
, inst
->dreg
, alpha_sp
, (i
*8));
5310 alpha_ldq(code
, alpha_at
, inst
->inst_basereg
, inst
->inst_offset
);
5311 alpha_stq(code
, alpha_at
, alpha_sp
, (i
*8));
5316 offset
= (char *)code
- (char *)cfg
->native_code
;
5318 ge_data
.data
.p
= cfg
->method
;
5320 add_got_entry(cfg
, GT_PTR
, ge_data
,
5321 (char *)code
- (char *)cfg
->native_code
,
5322 MONO_PATCH_INFO_METHODCONST
, cfg
->method
);
5323 alpha_ldq(code
, alpha_a0
, alpha_gp
, 0);
5325 alpha_mov1(code
, alpha_sp
, alpha_a1
);
5327 code
= emit_call(cfg
, code
, MONO_PATCH_INFO_ABS
, (gpointer
)func
);
5329 if (enable_arguments
)
5331 // Correct stack back by calculated value
5333 alpha_lda(code
, alpha_sp
, alpha_sp
, stack_area
);
5341 /*========================= End of Function ========================*/
5351 /*------------------------------------------------------------------*/
5353 /* Name - mono_arch_instrument_epilog */
5355 /* Function - Create an epilog that will handle the returned */
5356 /* values used in instrumentation. */
5358 /*------------------------------------------------------------------*/
5361 mono_arch_instrument_epilog (MonoCompile
*cfg
, void *func
, void *p
,
5362 gboolean enable_arguments
)
5364 unsigned int *code
= p
;
5365 int save_mode
= SAVE_NONE
;
5367 MonoMethod
*method
= cfg
->method
;
5368 AlphaGotData ge_data
;
5369 int rtype
= mono_type_get_underlying_type (mono_method_signature (method
)->ret
)->type
;
5371 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_instrument_epilog");
5375 case MONO_TYPE_VOID
:
5376 /* special case string .ctor icall */
5377 if (strcmp (".ctor", method
->name
) &&
5378 method
->klass
== mono_defaults
.string_class
)
5379 save_mode
= SAVE_R0
;
5381 save_mode
= SAVE_NONE
;
5385 save_mode
= SAVE_R0
;
5389 save_mode
= SAVE_XMM
;
5391 case MONO_TYPE_VALUETYPE
:
5392 save_mode
= SAVE_STRUCT
;
5395 save_mode
= SAVE_R0
;
5399 /* Save the result and copy it into the proper argument register */
5403 alpha_lda(code
, alpha_sp
, alpha_sp
, -8);
5404 alpha_stq(code
, alpha_r0
, alpha_sp
, 0);
5406 if (enable_arguments
)
5407 alpha_mov1(code
, alpha_r0
, alpha_a1
);
5412 if (enable_arguments
)
5413 alpha_lda(code
, alpha_a1
, alpha_zero
, 0);
5417 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5418 //amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
5420 //amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
5422 * The result is already in the proper argument register so no copying
5429 g_assert_not_reached ();
5432 offset
= (char *)code
- (char *)cfg
->native_code
;
5434 ge_data
.data
.p
= cfg
->method
;
5436 add_got_entry(cfg
, GT_PTR
, ge_data
,
5437 (char *)code
- (char *)cfg
->native_code
,
5438 MONO_PATCH_INFO_METHODCONST
, cfg
->method
);
5440 alpha_ldq(code
, alpha_a0
, alpha_gp
, 0);
5442 code
= emit_call(cfg
, code
, MONO_PATCH_INFO_ABS
, (gpointer
)func
);
5444 /* Restore result */
5448 alpha_ldq(code
, alpha_r0
, alpha_sp
, 0);
5449 alpha_lda(code
, alpha_sp
, alpha_sp
, 8);
5455 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5456 //amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
5457 //amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
5462 g_assert_not_reached ();
5468 /*========================= End of Function ========================*/
5470 /*------------------------------------------------------------------*/
5472 /* Name - mono_arch_allocate_vars */
5474 /* Function - Set var information according to the calling */
5475 /* convention for Alpha. The local var stuff should */
5476 /* most likely be split in another method. */
5478 /* Parameter - @m - Compile unit. */
5480 * This method is called right before working with BBs. Conversion to
5481 * IR was done and some analises what registers would be used.
5482 * Collect info about registers we used - if we want to use a register
5483 * we need to allocate space for it and save on the stack in method
5486 * Alpha calling convertion:
5487 * FP -> Stack top <- SP
5488 * 0: Stack params to call others
5490 * RA <- arch.params_stack_size
5493 * [LMF info] <- arch.lmf_offset
5495 * [possible return values allocated on stack]
5499 * . caller saved regs <- arch.reg_save_area_offset
5500 * . a0 <- arch.args_save_area_offset
5506 * ------------------------
5507 * . a6 - passed args on stack
5510 /*------------------------------------------------------------------*/
5513 mono_arch_allocate_vars (MonoCompile
*cfg
)
5515 MonoMethodSignature
*sig
;
5516 MonoMethodHeader
*header
;
5518 int i
, offset
= 0, a_off
= 0;
5519 guint32 locals_stack_size
, locals_stack_align
= 0;
5523 CFG_DEBUG(2) ALPHA_DEBUG("mono_arch_allocate_vars");
5525 header
= mono_method_get_header (cfg
->method
);
5527 sig
= mono_method_signature (cfg
->method
);
5529 cinfo
= get_call_info (cfg
->generic_sharing_context
, sig
, FALSE
);
5531 /* if (cfg->arch.omit_fp) {
5532 cfg->flags |= MONO_CFG_HAS_SPILLUP;
5533 cfg->frame_reg = AMD64_RSP;
5538 /* Locals are allocated forwards from FP. After
5539 * RA (offset 0), FP (offset 8) and ret value, locals, A0-A5
5540 * (starting from offset 16).
5541 * FIXME: Check there Arg6...Argn are supposed to be
5543 cfg
->frame_reg
= alpha_fp
;
5544 // offset = MONO_ALPHA_VARS_OFFSET;
5547 CFG_DEBUG(3) g_print ("ALPHA: Size for call params is %d(%x)\n",
5548 cfg
->arch
.params_stack_size
, cfg
->arch
.params_stack_size
);
5549 offset
+= cfg
->arch
.params_stack_size
;
5551 offset
+= 16; // Size to save RA & FP
5553 if (cfg
->method
->save_lmf
)
5555 /* Reserve stack space for saving LMF + argument regs */
5556 guint32 size
= sizeof (MonoLMF
);
5558 //if (lmf_tls_offset == -1)
5559 // /* Need to save argument regs too */
5560 // size += (AMD64_NREG * 8) + (8 * 8);
5562 cfg
->arch
.lmf_offset
= offset
;
5565 CFG_DEBUG(3) g_print ("ALPHA: Method %s needs LMF. Offset: %x, Size: %x\n",
5566 cfg
->method
->name
, cfg
->arch
.lmf_offset
, size
);
5569 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
5571 switch (cinfo
->ret
.storage
)
5575 case ArgInDoubleReg
:
5576 if ((MONO_TYPE_ISSTRUCT (sig
->ret
) &&
5577 !mono_class_from_mono_type (sig
->ret
)->enumtype
) ||
5578 (sig
->ret
->type
== MONO_TYPE_TYPEDBYREF
))
5580 /* The register is volatile */
5581 cfg
->ret
->opcode
= OP_REGOFFSET
;
5582 cfg
->ret
->inst_basereg
= cfg
->frame_reg
;
5584 /*if (cfg->arch.omit_fp) {
5585 cfg->ret->inst_offset = offset;
5589 cfg
->ret
->inst_offset
= offset
;
5590 CFG_DEBUG(3) g_print ("ALPHA: Return offset is %x\n", offset
);
5596 cfg
->ret
->opcode
= OP_REGVAR
;
5597 cfg
->ret
->inst_c0
= cinfo
->ret
.reg
;
5600 case ArgValuetypeInReg
:
5601 /* Allocate a local to hold the result, the epilog will
5602 copy it to the correct place */
5603 // g_assert (!cfg->arch.omit_fp);
5605 cfg
->ret
->opcode
= OP_REGOFFSET
;
5606 cfg
->ret
->inst_basereg
= cfg
->frame_reg
;
5607 cfg
->ret
->inst_offset
= offset
;
5610 g_assert_not_reached ();
5612 cfg
->ret
->dreg
= cfg
->ret
->inst_c0
;
5615 /* Allocate locals */
5616 offsets
= mono_allocate_stack_slots_full (cfg
,
5617 /*cfg->arch.omit_fp ? FALSE:*/ TRUE
,
5619 &locals_stack_align
);
5621 //g_assert((locals_stack_size % 8) == 0);
5622 if (locals_stack_size
% 8)
5624 locals_stack_size
+= 8 - (locals_stack_size
% 8);
5627 /* if (locals_stack_align)
5629 offset += (locals_stack_align - 1);
5630 offset &= ~(locals_stack_align - 1);
5634 cfg
->arch
.localloc_offset
= offset
;
5636 CFG_DEBUG(3) g_print ("ALPHA: Locals start offset is %d(%x)\n", offset
, offset
);
5637 CFG_DEBUG(3) g_print ("ALPHA: Locals size is %d(%x)\n",
5638 locals_stack_size
, locals_stack_size
);
5640 for (i
= cfg
->locals_start
; i
< cfg
->num_varinfo
; i
++)
5642 if (offsets
[i
] != -1) {
5643 MonoInst
*inst
= cfg
->varinfo
[i
];
5644 inst
->opcode
= OP_REGOFFSET
;
5645 inst
->inst_basereg
= cfg
->frame_reg
;
5646 //if (cfg->arch.omit_fp)
5647 // inst->inst_offset = (offset + offsets [i]);
5649 inst
->inst_offset
= (offset
+ (locals_stack_size
- offsets
[i
]));
5651 CFG_DEBUG(3) g_print ("ALPHA: allocated local %d to ", i
);
5652 CFG_DEBUG(3) mono_print_tree_nl (inst
);
5656 // TODO check how offsets[i] are calculated
5657 // it seems they are points to the end on data. Like 8, but it actually - 0
5659 offset
+= locals_stack_size
; //+8;
5661 if (!sig
->pinvoke
&& (sig
->call_convention
== MONO_CALL_VARARG
)) {
5662 // g_assert (!cfg->arch.omit_fp);
5663 g_assert (cinfo
->sig_cookie
.storage
== ArgOnStack
);
5664 cfg
->sig_cookie
= cinfo
->sig_cookie
.offset
+ ARGS_OFFSET
;
5667 // Save offset for caller saved regs
5668 cfg
->arch
.reg_save_area_offset
= offset
;
5670 CFG_DEBUG(3) g_print ("ALPHA: reg_save_area_offset at %d(%x)\n", offset
, offset
);
5672 // Reserve space for caller saved registers
5673 for (i
= 0; i
< MONO_MAX_IREGS
; ++i
)
5674 if ((ALPHA_IS_CALLEE_SAVED_REG (i
)) &&
5675 (cfg
->used_int_regs
& (1 << i
)))
5677 offset
+= sizeof (gpointer
);
5680 // Save offset to args regs
5681 cfg
->arch
.args_save_area_offset
= offset
;
5683 CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset
, offset
);
5685 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
)
5687 ArgInfo
*ainfo
= &cinfo
->args
[i
];
5689 switch(ainfo
->storage
)
5693 case ArgInDoubleReg
:
5694 offset
+= sizeof (gpointer
);
5697 offset
+= ainfo
->nregs
* sizeof (gpointer
);
5704 CFG_DEBUG(3) g_print ("ALPHA: Stack size is %d(%x)\n",
5707 // Reserve space for method params
5708 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
)
5710 inst
= cfg
->args
[i
];
5712 if (inst
->opcode
!= OP_REGVAR
)
5714 ArgInfo
*ainfo
= &cinfo
->args
[i
];
5715 gboolean inreg
= TRUE
;
5718 if (sig
->hasthis
&& (i
== 0))
5719 arg_type
= &mono_defaults
.object_class
->byval_arg
;
5721 arg_type
= sig
->params
[i
- sig
->hasthis
];
5723 /* FIXME: Allocate volatile arguments to registers */
5724 if (inst
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
))
5728 * Under AMD64, all registers used to pass arguments to functions
5729 * are volatile across calls. For Alpha too.
5730 * FIXME: Optimize this.
5734 if (inreg
&& (ainfo
->storage
== ArgInIReg
)
5735 //&& cfg->used_int_regs & (1 << ainfo->reg)
5739 if (//(ainfo->storage == ArgInIReg) ||
5740 (ainfo
->storage
== ArgInFloatReg
) ||
5741 (ainfo
->storage
== ArgInDoubleReg
) ||
5742 (ainfo
->storage
== ArgValuetypeInReg
))
5745 inst
->opcode
= OP_REGOFFSET
;
5747 switch (ainfo
->storage
)
5751 case ArgInDoubleReg
:
5752 inst
->opcode
= OP_REGVAR
;
5753 inst
->dreg
= ainfo
->reg
;
5756 // g_assert (!cfg->arch.omit_fp);
5757 inst
->opcode
= OP_REGOFFSET
;
5758 inst
->inst_basereg
= cfg
->frame_reg
;
5760 // "offset" here will point to the end of
5761 // array of saved ret,locals, args
5762 // Ideally it would point to "a7"
5763 inst
->inst_offset
= ainfo
->offset
+ offset
;
5765 case ArgValuetypeInReg
:
5775 if (!inreg
&& (ainfo
->storage
!= ArgOnStack
))
5777 inst
->opcode
= OP_REGOFFSET
;
5778 inst
->inst_basereg
= cfg
->frame_reg
;
5780 /* These arguments are saved to the stack in the prolog */
5781 /*if (cfg->arch.omit_fp) {
5782 inst->inst_offset = offset;
5783 offset += (ainfo->storage == ArgValuetypeInReg) ?
5784 2 * sizeof (gpointer) : sizeof (gpointer);
5787 // offset += (ainfo->storage == ArgValuetypeInReg) ?
5788 // 2 * sizeof (gpointer) : sizeof (gpointer);
5790 inst
->inst_offset
= cfg
->arch
.args_save_area_offset
+ a_off
;
5791 switch(ainfo
->storage
)
5794 a_off
+= ainfo
->nslots
* 8;
5797 a_off
+= sizeof (gpointer
);
5799 // (/*(ainfo->reg - 16)*/ i * 8);
5805 cfg
->stack_offset
= offset
;
5810 /*========================= End of Function ========================*/
5812 /*------------------------------------------------------------------*/
5814 /* Name - mono_arch_print_tree */
5816 /* Function - Print platform-specific opcode details. */
5818 /* Returns - 1 - opcode details have been printed */
5819 /* 0 - opcode details have not been printed */
5821 /*------------------------------------------------------------------*/
5824 mono_arch_print_tree (MonoInst
*tree
, int arity
)
5828 ALPHA_DEBUG("mono_arch_print_tree");
5830 switch (tree
->opcode
) {
5837 /*========================= End of Function ========================*/
5841 ** mono_arch_get_vcall_slot_addr
5842 ** is called by mono_magic_trampoline to determine that the JIT compiled
5843 ** method is called via vtable slot. We need to analyze call sequence
5844 ** and determine that. In case it is true - we need to return address
5847 ** code - points to the next instruction after call
5848 ** reg - points to saved regs before the call (this is done
5849 ** by mono_magic_trampoline function
5853 mono_arch_get_vcall_slot_addr (guint8
* code
, gpointer
*regs
)
5855 unsigned int *pc
= (unsigned int *)code
;
5857 int start_index
= -2;
5859 ALPHA_PRINT
g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr] code: %p regs: %p",
5862 // Check if we have parameters on stack
5863 if ((pc
[-2] & 0xFFFF0000) == 0x23DE0000) // lda sp,-n(sp)
5866 // Check for (call_membase):
5867 // -4: mov v0,a0 - load this ???
5868 // -3: ldq v0,0(v0) - load vtable
5869 // -2: ldq t12,64(v0) - load method (object->vtable->vtable[method->slot])
5870 if ((pc
[start_index
-1] & 0xFC00FFFF) == 0xA4000000 &&
5871 (pc
[start_index
] & 0xFFFF0000) == 0xA7600000
5874 disp
= pc
[start_index
] & 0xFFFF;
5875 reg
= (pc
[start_index
-1] >> AXP_REG1_SHIFT
) & AXP_REG_MASK
;
5876 //reg = 0; // For now
5878 ALPHA_PRINT
g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr callvirt] call_membase");
5880 return (gpointer
)(((guint64
)(regs
[reg
])) + disp
);
5883 // Check for interface call
5886 // -3: ldq v0,-n(v0)
5887 // -2: ldq t12,0(v0)
5888 if ((pc
[start_index
-2] & 0xFC00FFFF) == 0xA4000000 &&
5889 (pc
[start_index
-1] & 0xFFFF0000) == 0xA4000000 &&
5890 (pc
[start_index
] & 0xFFFF0000) == 0xA7600000
5893 disp
= pc
[start_index
] & 0xFFFF;;
5896 ALPHA_PRINT
g_debug("ALPHA_CHECK: [mono_arch_get_vcall_slot_addr interf callvir] call_membase");
5898 return (gpointer
)(((guint64
)(regs
[reg
])) + disp
);
5905 mono_arch_get_this_arg_from_call (MonoGenericSharingContext
*gsctx
, MonoMethodSignature
*sig
, gssize
*regs
, guint8
*code
)
5907 unsigned int *pc
= (unsigned int *)code
;
5909 ALPHA_PRINT
g_debug("ALPHA_CHECK: [mono_arch_get_this_arg_from_call] code: %p regs: %p",
5912 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
5913 return (gpointer
)regs
[alpha_a1
];
5915 return (gpointer
)regs
[alpha_a0
];
5919 mono_arch_get_delegate_invoke_impl (MonoMethodSignature
*sig
, gboolean has_target
)
5921 unsigned int *code
, *start
;
5922 MonoDomain
*domain
= mono_domain_get ();
5925 ALPHA_PRINT
g_debug("ALPHA_CHECK: [mono_arch_get_delegate_invoke_impl]");
5927 /* FIXME: Support more cases */
5928 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
5935 mono_arch_get_patch_offset (guint8
*code
)
5941 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
5943 /* FIXME: implement */
5944 g_assert_not_reached ();