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;)
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.
*
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 =
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));
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);
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);
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);