+ env->entries[idx]->low_word = new_r_Proj(irg, block, irn, env->params->low_unsigned, 0);
+ env->entries[idx]->high_word = new_r_Proj(irg, block, irn, mode, 1);
+} /* lower_Binop */
+
+/**
+ * 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;
+ ir_graph *irg;
+ 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;
+ } /* if */
+
+ 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);
+ irg = current_ir_graph;
+
+ 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, irg, block, get_irg_no_mem(current_ir_graph),
+ irn, 3, in, mtp);
+ set_irn_pinned(irn, get_irn_pinned(node));
+ irn = new_r_Proj(irg, 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(irg, block, irn, env->params->low_unsigned, 0);
+ env->entries[idx]->high_word = new_r_Proj(irg, block, irn, mode, 1);
+} /* lower_Shiftop */
+
+/**
+ * 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);
+ ir_graph *irg = current_ir_graph;
+
+ 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) >= (long)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(irg, block, mode_Iu, shf_cnt);
+ env->entries[idx]->low_word = new_r_Shr(irg, block, left, c, mode);
+ } else {
+ env->entries[idx]->low_word = left;
+ } /* if */
+ env->entries[idx]->high_word = new_r_Const(irg, block, mode, get_mode_null(mode));
+
+ return;
+ } /* if */
+ } /* if */
+ lower_Shiftop(node, mode, env);
+} /* lower_Shr */
+
+/**
+ * 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);
+ ir_graph *irg = current_ir_graph;
+
+ 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) >= (long)get_mode_size_bits(mode)) {
+ ir_mode *mode_l;
+ 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 = new_r_Conv(irg, block, env->entries[idx]->low_word, mode);
+ idx = get_irn_idx(node);
+
+ if (shf_cnt > 0) {
+ c = new_r_Const_long(irg, block, mode_Iu, shf_cnt);
+ env->entries[idx]->high_word = new_r_Shl(irg, block, left, c, mode);
+ } else {
+ env->entries[idx]->high_word = left;
+ } /* if */
+ mode_l = env->params->low_unsigned;
+ env->entries[idx]->low_word = new_r_Const(irg, block, mode_l, get_mode_null(mode_l));
+
+ return;
+ } /* if */
+ } /* if */
+ lower_Shiftop(node, mode, env);
+} /* lower_Shl */
+
+/**
+ * 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);
+ ir_graph *irg = current_ir_graph;
+
+ 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) >= (long)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) {
+ ir_node *tmp;
+ c = new_r_Const_long(irg, block, mode_Iu, shf_cnt);
+ tmp = new_r_Shrs(irg, block, left, c, mode);
+ /* low word is expected to have mode_Iu */
+ env->entries[idx]->low_word = new_r_Conv(irg, block, tmp, mode_Iu);
+ } else {
+ env->entries[idx]->low_word = left;
+ } /* if */
+ c = new_r_Const_long(irg, block, mode_Iu, get_mode_size_bits(mode) - 1);
+ env->entries[idx]->high_word = new_r_Shrs(irg, block, left, c, mode);
+
+ return;
+ } /* if */
+ } /* if */
+ lower_Shiftop(node, mode, env);
+} /* lower_Shrs */
+
+/**
+ * Rebuild Rotl nodes into Or(Shl, Shr) and prepare all nodes.
+ */
+static void prepare_links_and_handle_rotl(ir_node *node, void *env) {
+ lower_env_t *lenv = env;
+
+ if (is_Rotl(node)) {
+ ir_mode *mode = get_irn_op_mode(node);
+ if (mode == lenv->params->high_signed ||
+ mode == lenv->params->high_unsigned) {
+ ir_node *right = get_Rotl_right(node);
+ ir_node *left, *shl, *shr, *or, *block, *sub, *c;
+ ir_mode *omode, *rmode;
+ ir_graph *irg;
+ dbg_info *dbg;
+ optimization_state_t state;
+
+ 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) == (long)get_mode_size_bits(mode)) {
+ /* will be optimized in lower_Rotl() */
+ return;
+ }
+ }
+
+ /* replace the Rotl(x,y) by an Or(Shl(x,y), Shr(x,64-y)) and lower those */
+ dbg = get_irn_dbg_info(node);
+ omode = get_irn_mode(node);
+ left = get_Rotl_left(node);
+ irg = current_ir_graph;
+ block = get_nodes_block(node);
+ shl = new_rd_Shl(dbg, irg, block, left, right, omode);
+ rmode = get_irn_mode(right);
+ c = new_Const_long(rmode, get_mode_size_bits(omode));
+ sub = new_rd_Sub(dbg, irg, block, c, right, rmode);
+ shr = new_rd_Shr(dbg, irg, block, left, sub, omode);
+
+ /* optimization must be switched off here, or we will get the Rotl back */
+ save_optimization_state(&state);
+ set_opt_algebraic_simplification(0);
+ or = new_rd_Or(dbg, irg, block, shl, shr, omode);
+ restore_optimization_state(&state);
+
+ exchange(node, or);
+
+ /* do lowering on the new nodes */
+ prepare_links(shl, env);
+ prepare_links(c, env);
+ prepare_links(sub, env);
+ prepare_links(shr, env);
+ prepare_links(or, env);
+ }
+ } else {
+ prepare_links(node, env);
+ }