Merge branch 'master' into mono4-continuations_fix
[mono.git] / mono / arch / ia64 / ia64-codegen.h
index 558e05298a7e7fccc1396f8373a25bebbbaa5f12..17935800a2e7c80baa6610d545809614ad397f02 100644 (file)
 #define _IA64_CODEGEN_H_
 
 #include <glib.h>
+#include <string.h>
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
 
 typedef enum {
        IA64_INS_TYPE_A,
@@ -111,6 +115,7 @@ typedef enum {
 } Ia64BranchRegister;
 
 typedef enum {
+       IA64_CCV = 32,
        IA64_PFS = 64
 } Ia64ApplicationRegister;
 
@@ -176,15 +181,19 @@ typedef enum {
  */
 
 #define IA64_INS_BUFFER_SIZE 4
+#define MAX_UNW_OPS 8
 
 typedef struct {
        guint8 *buf;
-    guint automatic : 1;
        guint one_ins_per_bundle : 1;
+       int nins, template, dep_info_pos, unw_op_pos, unw_op_count;
        guint64 instructions [IA64_INS_BUFFER_SIZE];
-       int itypes [IA64_INS_BUFFER_SIZE], stops [IA64_INS_BUFFER_SIZE];
+       int itypes [IA64_INS_BUFFER_SIZE];
+       guint8 *region_start;
        guint8 dep_info [128];
-       int nins, template, dep_info_pos;
+       unw_dyn_op_t unw_ops [MAX_UNW_OPS];
+       /* The index of the instruction to which the given unw op belongs */
+    guint8 unw_ops_pos [MAX_UNW_OPS];
 } Ia64CodegenState;
 
 #ifdef IA64_SIMPLE_EMIT_BUNDLE
@@ -193,22 +202,14 @@ G_GNUC_UNUSED static void ia64_emit_bundle (Ia64CodegenState *code, gboolean flu
 void ia64_emit_bundle (Ia64CodegenState *code, gboolean flush);
 #endif
 
-/*
- * There are two code generation modes:
- * - in automatic mode, bundling and stops are handled automatically by the
- *   code generation macros.
- *   FIXME: In order to simplify things, we emit a stop after every instruction for
- *   now.
- * - in non-automatic mode, the caller is responsible for handling bundling and
- *   stops using the appropriate macros.
- */
-
 #define ia64_codegen_init(code, codegen_buf) do { \
     code.buf = codegen_buf; \
+    code.region_start = code.buf; \
     code.nins = 0; \
-    code.automatic = 1; \
     code.one_ins_per_bundle = 0; \
     code.dep_info_pos = 0; \
+    code.unw_op_count = 0; \
+    code.unw_op_pos = 0; \
 } while (0)
 
 #define ia64_codegen_close(code) do { \
@@ -219,25 +220,47 @@ void ia64_emit_bundle (Ia64CodegenState *code, gboolean flush);
     ia64_emit_bundle (&code, TRUE); \
 } while (0)
 
-#define ia64_codegen_set_automatic(code, is_automatic) do { \
-    code.automatic = (is_automatic); \
-} while (0)
-
 #define ia64_codegen_set_one_ins_per_bundle(code, is_one) do { \
     ia64_begin_bundle (code); \
     code.one_ins_per_bundle = (is_one); \
 } while (0)
 
-#define ia64_stop(code) do { \
-    g_assert ((code.nins > 0)); \
-    code.stops [code.nins - 1] = 1; \
-} while (0)
-
 #define ia64_begin_bundle_template(code, bundle_template) do { \
     ia64_emit_bundle (&code, TRUE); \
     code.template = (bundle_template); \
 } while (0)
 
+#define ia64_unw_save_reg(code, reg, dreg) do { \
+    g_assert (code.unw_op_count <= MAX_UNW_OPS); \
+    code.unw_ops_pos [code.unw_op_count] = code.nins; \
+       _U_dyn_op_save_reg (&(code.unw_ops [code.unw_op_count ++]), _U_QP_TRUE, -1, reg, dreg); \
+} while (0)
+
+#define ia64_unw_add(code, reg, val) do { \
+    g_assert (code.unw_op_count <= MAX_UNW_OPS); \
+    code.unw_ops_pos [code.unw_op_count] = code.nins; \
+       _U_dyn_op_add (&(code.unw_ops [code.unw_op_count ++]), _U_QP_TRUE, code.nins, reg, val); \
+} while (0)
+
+#define ia64_unw_pop_frames(code, nframes) do { \
+    g_assert (code.unw_op_count <= MAX_UNW_OPS); \
+    code.unw_ops_pos [code.unw_op_count] = code.nins; \
+       _U_dyn_op_pop_frames (&(code.unw_ops [code.unw_op_count ++]), _U_QP_TRUE, code.nins, (nframes)); \
+} while (0)
+
+#define ia64_unw_label_state(code, id) do { \
+    g_assert (code.unw_op_count <= MAX_UNW_OPS); \
+    code.unw_ops_pos [code.unw_op_count] = code.nins; \
+       _U_dyn_op_label_state (&(code.unw_ops [code.unw_op_count ++]), (id)); \
+} while (0)
+
+
+#define ia64_unw_copy_state(code, id) do { \
+    g_assert (code.unw_op_count <= MAX_UNW_OPS); \
+    code.unw_ops_pos [code.unw_op_count] = code.nins; \
+       _U_dyn_op_copy_state (&(code.unw_ops [code.unw_op_count ++]), (id)); \
+} while (0)
+
 #if 0
 /* To ease debugging, emit instructions immediately */
 #define EMIT_BUNDLE(itype, code) ((itype != IA64_INS_TYPE_LX) || (code.nins == 2)) ia64_emit_bundle (&code, FALSE);
@@ -246,21 +269,14 @@ void ia64_emit_bundle (Ia64CodegenState *code, gboolean flush);
 #endif
 
 #define ia64_emit_ins(code, itype, ins) do { \
-    if (G_LIKELY (code.automatic)) { \
-               code.instructions [code.nins] = ins; \
-        code.itypes [code.nins] = itype; \
-        code.nins ++; \
-        code.dep_info [code.dep_info_pos ++] = IA64_END_OF_INS; \
-        code.dep_info [code.dep_info_pos ++] = 0; \
-        EMIT_BUNDLE (itype, code); \
-        if (code.nins == IA64_INS_BUFFER_SIZE) \
-           ia64_emit_bundle (&code, FALSE); \
-    } else { \
-        g_assert (code.nins < 3); \
-        code.instructions [code.nins] = ins; \
-        code.itypes [code.nins] = itype; \
-        code.nins ++; \
-    } \
+    code.instructions [code.nins] = ins; \
+    code.itypes [code.nins] = itype; \
+    code.nins ++; \
+    code.dep_info [code.dep_info_pos ++] = IA64_END_OF_INS; \
+    code.dep_info [code.dep_info_pos ++] = 0; \
+    EMIT_BUNDLE (itype, code); \
+    if (code.nins == IA64_INS_BUFFER_SIZE) \
+        ia64_emit_bundle (&code, FALSE); \
 } while (0)
 
 #define ia64_no_stop(code) do { \
@@ -1546,10 +1562,10 @@ typedef enum {
 
 #define encode_inc3(inc3) ((inc3) == 16 ? 0 : ((inc3) == 8 ? 1 : ((inc3) == 4 ? 2 : 3)))
 
-#define ia64_m17(code, qp, r1, r3, imm, hint, m, x, x6) do { read_pr ((code), (qp)); write_gr ((code), (r1)); read_gr ((code), (r3)); int aimm = (imm) < 0 ? - (imm) : (imm); check_assert ((aimm) == 16 || (aimm) == 8 || (aimm) == 4 || (aimm) == 1); ia64_emit_ins_10 ((code), IA64_INS_TYPE_M, (qp), 0, (r1), 6, encode_inc3 (aimm), 13, sign_bit ((imm)), 15, (r3), 20, (x), 27, (hint), 28, (x6), 30, (m), 36, (4), 37); } while (0)
+#define ia64_m17(code, qp, r1, r3, imm, hint, m, x, x6) do { int aimm; read_pr ((code), (qp)); write_gr ((code), (r1)); read_gr ((code), (r3)); aimm = (imm) < 0 ? - (imm) : (imm); check_assert ((aimm) == 16 || (aimm) == 8 || (aimm) == 4 || (aimm) == 1); ia64_emit_ins_10 ((code), IA64_INS_TYPE_M, (qp), 0, (r1), 6, encode_inc3 (aimm), 13, sign_bit ((imm)), 15, (r3), 20, (x), 27, (hint), 28, (x6), 30, (m), 36, (4), 37); } while (0)
 
 #define ia64_fetchadd4_acq_hint_pred(code, qp, r1, r3, inc, hint) ia64_m17 ((code), (qp), (r1), (r3), (inc), (hint), 0, 1, 0x12)
-#define ia64_fetchadd8_acq_hint_pred(code, qp, r1, r3, inc, hint) ia64_m17 ((code), (qp), (r1), (r3), (inc), (hint), 0, 1, 0x12)
+#define ia64_fetchadd8_acq_hint_pred(code, qp, r1, r3, inc, hint) ia64_m17 ((code), (qp), (r1), (r3), (inc), (hint), 0, 1, 0x13)
 #define ia64_fetchadd4_rel_hint_pred(code, qp, r1, r3, inc, hint) ia64_m17 ((code), (qp), (r1), (r3), (inc), (hint), 0, 1, 0x16)
 #define ia64_fetchadd8_rel_hint_pred(code, qp, r1, r3, inc, hint) ia64_m17 ((code), (qp), (r1), (r3), (inc), (hint), 0, 1, 0x17)
 
@@ -1691,7 +1707,7 @@ typedef enum {
 
 #define ia64_br_call_hint_pred(code, qp, b1, disp, bwh, ph, dh) ia64_b3 ((code), (qp), (b1), (disp), (bwh), (ph), (dh))
 
-#define ia64_b4(code, qp, b2, bwh, ph, dh, x6, btype) do { read_pr ((code), (qp)); read_br ((code), (b2)); check_bwh ((bwh)); check_ph ((ph)); check_dh ((dh)); ia64_emit_ins_8 ((code), IA64_INS_TYPE_B, (qp), 0, (btype), 6, (ph), 12, (b2), 13, (x6), 27, (bwh), 33, (dh), 35, (0), 37); } while (0)
+#define ia64_b4(code, qp, b2, bwh, ph, dh, x6, btype) do { read_pr ((code), (qp)); read_br_branch ((code), (b2)); check_bwh ((bwh)); check_ph ((ph)); check_dh ((dh)); ia64_emit_ins_8 ((code), IA64_INS_TYPE_B, (qp), 0, (btype), 6, (ph), 12, (b2), 13, (x6), 27, (bwh), 33, (dh), 35, (0), 37); } while (0)
 
 #define ia64_br_cond_reg_hint_pred(code, qp, b1, bwh, ph, dh) ia64_b4 ((code), (qp), (b1), (bwh), (ph), (dh), 0x20, 0)
 #define ia64_br_ia_reg_hint_pred(code, qp, b1, bwh, ph, dh) ia64_b4 ((code), (qp), (b1), (bwh), (ph), (dh), 0x20, 1)
@@ -1775,6 +1791,12 @@ typedef enum {
 #define ia64_xma_h_pred(code, qp, f1, f3, f4, f2) ia64_f2 ((code), (qp), (f1), (f3), (f4), (f2), 0xE, 1, 3)
 #define ia64_xma_hu_pred(code, qp, f1, f3, f4, f2) ia64_f2 ((code), (qp), (f1), (f3), (f4), (f2), 0xE, 1, 2)
 
+/* Pseudo ops */
+#define ia64_xmpy_l_pred(code, qp, f1, f3, f4) ia64_xma_l_pred ((code), (qp), (f1), (f3), (f4), 0)
+#define ia64_xmpy_lu_pred(code, qp, f1, f3, f4) ia64_xma_l_pred ((code), (qp), (f1), (f3), (f4), 0)
+#define ia64_xmpy_h_pred(code, qp, f1, f3, f4) ia64_xma_h_pred ((code), (qp), (f1), (f3), (f4), 0)
+#define ia64_xmpy_hu_pred(code, qp, f1, f3, f4) ia64_xma_hu_pred ((code), (qp), (f1), (f3), (f4), 0)
+
 #define ia64_f3(code, qp, f1, f3, f4, f2, opcode, x) do { read_pr ((code), (qp)); write_fr ((code), (f1)); read_fr ((code), (f3)); read_fr ((code), (f4)); read_fr ((code), (f2)); ia64_emit_ins_7 ((code), IA64_INS_TYPE_F, (qp), 0, (f1), 6, (f2), 13, (f3), 20, (f4), 27, (x), 36, (opcode), 37); } while (0)
 
 #define ia64_fselect_pred(code, qp, f1, f3, f4, f2) ia64_f3 ((code), (qp), (f1), (f3), (f4), (f2), 0xE, 0)
@@ -1898,7 +1920,7 @@ typedef enum {
 
 #define ia64_break_x_pred(code, qp, imm) ia64_x1 ((code), (qp), (imm), 0, 0x00)
 
-#define ia64_x2(code, qp, r1, imm, vc) do { if (code.automatic && (code.nins > IA64_INS_BUFFER_SIZE - 2)) ia64_emit_bundle (&(code), FALSE); read_pr ((code), (qp)); write_gr ((code), (r1)); ia64_emit_ins_1 ((code), IA64_INS_TYPE_LX, ((gint64)(imm) >> 22) & 0x1ffffffffffULL, 0); ia64_emit_ins_9 ((code), IA64_INS_TYPE_LX, (qp), 0, (r1), 6, (gint64)(imm) & 0x7f, (13), (vc), 20, ((gint64)(imm) >> 21) & 0x1, 21, ((gint64)(imm) >> 16) & 0x1f, 22, ((gint64)(imm) >> 7) & 0x1ff, 27, ((gint64)(imm) >> 63) & 0x1, 36, (6), 37); } while (0)
+#define ia64_x2(code, qp, r1, imm, vc) do { if (code.nins > IA64_INS_BUFFER_SIZE - 2) ia64_emit_bundle (&(code), FALSE); read_pr ((code), (qp)); write_gr ((code), (r1)); ia64_emit_ins_1 ((code), IA64_INS_TYPE_LX, ((gint64)(imm) >> 22) & 0x1ffffffffffULL, 0); ia64_emit_ins_9 ((code), IA64_INS_TYPE_LX, (qp), 0, (r1), 6, (gint64)(imm) & 0x7f, (13), (vc), 20, ((gint64)(imm) >> 21) & 0x1, 21, ((gint64)(imm) >> 16) & 0x1f, 22, ((gint64)(imm) >> 7) & 0x1ff, 27, ((gint64)(imm) >> 63) & 0x1, 36, (6), 37); } while (0)
 
 #define ia64_movl_pred(code, qp, r1, imm) ia64_x2 ((code), (qp), (r1), (imm), 0)
 
@@ -3062,6 +3084,12 @@ typedef enum {
 #define ia64_xma_h(code, f1, f3, f4, f2) ia64_xma_h_pred ((code), 0, f1, f3, f4, f2)
 #define ia64_xma_hu(code, f1, f3, f4, f2) ia64_xma_hu_pred ((code), 0, f1, f3, f4, f2)
 
+/* Pseudo ops */
+#define ia64_xmpy_l(code, f1, f3, f4) ia64_xmpy_l_pred ((code), 0, (f1), (f3), (f4))
+#define ia64_xmpy_lu(code, f1, f3, f4) ia64_xmpy_lu_pred ((code), 0, (f1), (f3), (f4))
+#define ia64_xmpy_h(code, f1, f3, f4) ia64_xmpy_h_pred ((code), 0, (f1), (f3), (f4))
+#define ia64_xmpy_hu(code, f1, f3, f4) ia64_xmpy_hu_pred ((code), 0, (f1), (f3), (f4))
+
 #define ia64_fselect(code, f1, f3, f4, f2) ia64_fselect_pred ((code), 0, f1, f3, f4, f2)
 
 #define ia64_fcmp_eq_sf(code, p1, p2, f2, f3, sf) ia64_fcmp_eq_sf_pred ((code), 0, p1, p2, f2, f3, sf)