Fixed typos, improved docu
[libfirm] / ir / lower / lower_dw.c
index f19f3cf..1c4644a 100644 (file)
@@ -59,7 +59,7 @@ static set *conv_types;
 static pmap *lowered_type;
 
 /** The types for the binop and unop intrinsics. */
-static ir_type *binop_tp_u, *binop_tp_s, *unop_tp_u, *unop_tp_s, *tp_s, *tp_u;
+static ir_type *binop_tp_u, *binop_tp_s, *unop_tp_u, *unop_tp_s, *shiftop_tp_u, *shiftop_tp_s, *tp_s, *tp_u;
 
 /** the debug handle */
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
@@ -851,6 +851,183 @@ static void lower_Binop(ir_node *node, ir_mode *mode, lower_env_t *env) {
        env->entries[idx]->high_word = new_r_Proj(current_ir_graph, block, irn, mode, 1);
 }
 
+/**
+ * Translate a Shiftop.
+ *
+ * Create an intrinsic Call.
+ */
+static void lower_Shiftop(ir_node *node, ir_mode *mode, lower_env_t *env) {
+       ir_node  *block, *irn;
+       ir_node  *in[3];
+       dbg_info *dbg;
+       ir_type  *mtp;
+       int      idx;
+       node_entry_t *entry;
+
+       irn   = get_binop_left(node);
+       entry = env->entries[get_irn_idx(irn)];
+       assert(entry);
+
+       if (! entry->low_word) {
+               /* not ready yet, wait */
+               pdeq_putr(env->waitq, node);
+               return;
+       }
+
+       in[0] = entry->low_word;
+       in[1] = entry->high_word;
+
+       /* The shift count is always mode_Iu in firm, so there is no need for lowering */
+       in[2] = get_binop_right(node);
+
+       dbg   = get_irn_dbg_info(node);
+       block = get_nodes_block(node);
+
+       mtp = mode_is_signed(mode) ? shiftop_tp_s : shiftop_tp_u;
+       irn = get_intrinsic_address(mtp, get_irn_op(node), mode, mode, block, env);
+       irn = new_rd_Call(dbg, current_ir_graph, block, get_irg_no_mem(current_ir_graph),
+               irn, 3, in, mtp);
+       set_irn_pinned(irn, get_irn_pinned(node));
+       irn = new_r_Proj(current_ir_graph, block, irn, mode_T, pn_Call_T_result);
+
+       idx = get_irn_idx(node);
+       assert(idx < env->n_entries);
+       env->entries[idx]->low_word  = new_r_Proj(current_ir_graph, block, irn, mode, 0);
+       env->entries[idx]->high_word = new_r_Proj(current_ir_graph, block, irn, mode, 1);
+}
+
+/**
+ * Translate a Shr and handle special cases.
+ */
+static void lower_Shr(ir_node *node, ir_mode *mode, lower_env_t *env) {
+       ir_node *right = get_Shr_right(node);
+
+       if (get_mode_arithmetic(mode) == irma_twos_complement && is_Const(right)) {
+               tarval *tv = get_Const_tarval(right);
+
+               if (tarval_is_long(tv) &&
+                       get_tarval_long(tv) >= get_mode_size_bits(mode)) {
+                       ir_node *block = get_nodes_block(node);
+                       ir_node *left = get_Shr_left(node);
+                       ir_node *c;
+                       long shf_cnt = get_tarval_long(tv) - get_mode_size_bits(mode);
+                       int idx = get_irn_idx(left);
+
+                       left = env->entries[idx]->high_word;
+                       idx = get_irn_idx(node);
+
+                       if (shf_cnt > 0) {
+                               c = new_r_Const_long(current_ir_graph, block, mode_Iu, shf_cnt);
+                               env->entries[idx]->low_word = new_r_Shr(current_ir_graph, block, left, c, mode);
+                       }
+                       else
+                               env->entries[idx]->low_word = left;
+                       env->entries[idx]->high_word = new_r_Const(current_ir_graph, block, mode, get_mode_null(mode));
+
+                       return;
+               }
+       }
+       lower_Shiftop(node, mode, env);
+}
+
+/**
+ * Translate a Shl and handle special cases.
+ */
+static void lower_Shl(ir_node *node, ir_mode *mode, lower_env_t *env) {
+       ir_node *right = get_Shl_right(node);
+
+       if (get_mode_arithmetic(mode) == irma_twos_complement && is_Const(right)) {
+               tarval *tv = get_Const_tarval(right);
+
+               if (tarval_is_long(tv) &&
+                       get_tarval_long(tv) >= get_mode_size_bits(mode)) {
+                       ir_node *block = get_nodes_block(node);
+                       ir_node *left = get_Shl_left(node);
+                       ir_node *c;
+                       long shf_cnt = get_tarval_long(tv) - get_mode_size_bits(mode);
+                       int idx = get_irn_idx(left);
+
+                       left = env->entries[idx]->low_word;
+                       idx = get_irn_idx(node);
+
+                       if (shf_cnt > 0) {
+                               c = new_r_Const_long(current_ir_graph, block, mode_Iu, shf_cnt);
+                               env->entries[idx]->high_word = new_r_Shl(current_ir_graph, block, left, c, mode);
+                       }
+                       else
+                               env->entries[idx]->high_word = left;
+                       env->entries[idx]->low_word  = new_r_Const(current_ir_graph, block, mode, get_mode_null(mode));
+
+                       return;
+               }
+       }
+       lower_Shiftop(node, mode, env);
+}
+
+/**
+ * Translate a Shrs and handle special cases.
+ */
+static void lower_Shrs(ir_node *node, ir_mode *mode, lower_env_t *env) {
+       ir_node *right = get_Shrs_right(node);
+
+       if (get_mode_arithmetic(mode) == irma_twos_complement && is_Const(right)) {
+               tarval *tv = get_Const_tarval(right);
+
+               if (tarval_is_long(tv) &&
+                       get_tarval_long(tv) >= get_mode_size_bits(mode)) {
+                       ir_node *block = get_nodes_block(node);
+                       ir_node *left = get_Shrs_left(node);
+                       long shf_cnt = get_tarval_long(tv) - get_mode_size_bits(mode);
+                       ir_node *c;
+                       int idx = get_irn_idx(left);
+
+                       left = env->entries[idx]->high_word;
+                       idx = get_irn_idx(node);
+
+                       if (shf_cnt > 0) {
+                               c = new_r_Const_long(current_ir_graph, block, mode_Iu, shf_cnt);
+                               env->entries[idx]->low_word = new_r_Shrs(current_ir_graph, block, left, c, mode);
+                       }
+                       else
+                               env->entries[idx]->low_word = left;
+
+                       c = new_r_Const_long(current_ir_graph, block, mode_Iu, get_mode_size_bits(mode) - 1);
+                       env->entries[idx]->high_word = new_r_Shrs(current_ir_graph, block, left, c, mode);
+
+                       return;
+               }
+       }
+       lower_Shiftop(node, mode, env);
+}
+
+/**
+ * Translate a Rot and handle special cases.
+ */
+static void lower_Rot(ir_node *node, ir_mode *mode, lower_env_t *env) {
+       ir_node *right = get_Rot_right(node);
+
+       if (get_mode_arithmetic(mode) == irma_twos_complement && is_Const(right)) {
+               tarval *tv = get_Const_tarval(right);
+
+               if (tarval_is_long(tv) &&
+                       get_tarval_long(tv) == get_mode_size_bits(mode)) {
+                       ir_node *block = get_nodes_block(node);
+                       ir_node *left = get_Rot_left(node);
+                       ir_node *h, *l;
+                       int idx = get_irn_idx(left);
+
+                       l = env->entries[idx]->low_word;
+                       h = env->entries[idx]->high_word;
+                       idx = get_irn_idx(node);
+
+                       env->entries[idx]->low_word  = h;
+                       env->entries[idx]->high_word = l;
+
+                       return;
+               }
+       }
+       lower_Shiftop(node, mode, env);
+}
 /**
  * Translate an Unop.
  *
@@ -1597,7 +1774,7 @@ static void lower_Start(ir_node *node, ir_mode *mode, lower_env_t *env) {
                        if (mode == env->params->high_signed)
                                mode = env->params->low_signed;
                        else
-                               mode = env->params->high_signed;
+                               mode = env->params->low_unsigned;
 
                        dbg = get_irn_dbg_info(proj);
                        env->entries[idx]->low_word  =
@@ -1902,7 +2079,6 @@ void lower_dw_ops(const lwrdw_param_t *param)
                return;
 
        FIRM_DBG_REGISTER(dbg, "firm.lower.dw");
-       firm_dbg_set_mask(dbg, SET_LEVEL_2);
 
        assert(2 * get_mode_size_bits(param->low_signed)   == get_mode_size_bits(param->high_signed));
        assert(2 * get_mode_size_bits(param->low_unsigned) == get_mode_size_bits(param->high_unsigned));
@@ -1925,7 +2101,6 @@ void lower_dw_ops(const lwrdw_param_t *param)
 
        if (! binop_tp_u) {
                binop_tp_u = new_type_method(IDENT("binop_u_intrinsic"), 4, 2);
-
                set_method_param_type(binop_tp_u, 0, tp_u);
                set_method_param_type(binop_tp_u, 1, tp_u);
                set_method_param_type(binop_tp_u, 2, tp_u);
@@ -1942,6 +2117,23 @@ void lower_dw_ops(const lwrdw_param_t *param)
                set_method_res_type(binop_tp_s, 0, tp_s);
                set_method_res_type(binop_tp_s, 1, tp_s);
        }
+       if (! shiftop_tp_u) {
+               shiftop_tp_u = new_type_method(IDENT("shiftop_u_intrinsic"), 3, 2);
+               set_method_param_type(shiftop_tp_u, 0, tp_u);
+               set_method_param_type(shiftop_tp_u, 1, tp_u);
+               set_method_param_type(shiftop_tp_u, 2, tp_u);
+               set_method_res_type(shiftop_tp_u, 0, tp_u);
+               set_method_res_type(shiftop_tp_u, 1, tp_u);
+       }
+       if (! shiftop_tp_s) {
+               shiftop_tp_s = new_type_method(IDENT("shiftop_s_intrinsic"), 3, 2);
+               set_method_param_type(shiftop_tp_s, 0, tp_s);
+               set_method_param_type(shiftop_tp_s, 1, tp_s);
+               /* beware: shift count is always mode_Iu */
+               set_method_param_type(shiftop_tp_s, 2, tp_u);
+               set_method_res_type(shiftop_tp_s, 0, tp_s);
+               set_method_res_type(shiftop_tp_s, 1, tp_s);
+       }
        if (! unop_tp_u) {
                unop_tp_u = new_type_method(IDENT("unop_u_intrinsic"), 2, 2);
                set_method_param_type(unop_tp_u, 0, tp_u);
@@ -1987,10 +2179,10 @@ void lower_dw_ops(const lwrdw_param_t *param)
        LOWER_BIN(Add);
        LOWER_BIN(Sub);
        LOWER_BIN(Mul);
-       LOWER_BIN(Shl);
-       LOWER_BIN(Shr);
-       LOWER_BIN(Shrs);
-       LOWER_BIN(Rot);
+       LOWER(Shl);
+       LOWER(Shr);
+       LOWER(Shrs);
+       LOWER(Rot);
        LOWER_UN(Minus);
        LOWER(DivMod);
        LOWER(Div);