+ if (mode == env->high_signed ||
+ mode == env->high_unsigned)
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Determine which modes need to be lowered */
+static void setup_modes(lower_env_t *env)
+{
+ unsigned size_bits = env->params->doubleword_size;
+ ir_mode *doubleword_signed = NULL;
+ ir_mode *doubleword_unsigned = NULL;
+ int n_modes = get_irp_n_modes();
+ ir_mode_arithmetic arithmetic;
+ unsigned modulo_shift;
+ int i;
+
+ /* search for doubleword modes... */
+ for (i = 0; i < n_modes; ++i) {
+ ir_mode *mode = get_irp_mode(i);
+ if (!mode_is_int(mode))
+ continue;
+ if (get_mode_size_bits(mode) != size_bits)
+ continue;
+ if (mode_is_signed(mode)) {
+ if (doubleword_signed != NULL) {
+ /* sigh - the lowerer should really just lower all mode with
+ * size_bits it finds. Unfortunately this required a bigger
+ * rewrite. */
+ panic("multiple double word signed modes found");
+ }
+ doubleword_signed = mode;
+ } else {
+ if (doubleword_unsigned != NULL) {
+ /* sigh - the lowerer should really just lower all mode with
+ * size_bits it finds. Unfortunately this required a bigger
+ * rewrite. */
+ panic("multiple double word unsigned modes found");
+ }
+ doubleword_unsigned = mode;
+ }
+ }
+ if (doubleword_signed == NULL || doubleword_unsigned == NULL) {
+ panic("Couldn't find doubleword modes");
+ }
+
+ arithmetic = get_mode_arithmetic(doubleword_signed);
+ modulo_shift = get_mode_modulo_shift(doubleword_signed);
+
+ assert(get_mode_size_bits(doubleword_unsigned) == size_bits);
+ assert(size_bits % 2 == 0);
+ assert(get_mode_sign(doubleword_signed) == 1);
+ assert(get_mode_sign(doubleword_unsigned) == 0);
+ assert(get_mode_sort(doubleword_signed) == irms_int_number);
+ assert(get_mode_sort(doubleword_unsigned) == irms_int_number);
+ assert(get_mode_arithmetic(doubleword_unsigned) == arithmetic);
+ assert(get_mode_modulo_shift(doubleword_unsigned) == modulo_shift);
+
+ /* try to guess a sensible modulo shift for the new mode.
+ * (This is IMO another indication that this should really be a node
+ * attribute instead of a mode thing) */
+ if (modulo_shift == size_bits) {
+ modulo_shift = modulo_shift / 2;
+ } else if (modulo_shift == 0) {
+ /* fine */
+ } else {
+ panic("Don't know what new modulo shift to use for lowered doubleword mode");
+ }
+ size_bits /= 2;
+
+ /* produce lowered modes */
+ env->high_signed = doubleword_signed;
+ env->high_unsigned = doubleword_unsigned;
+ env->low_signed = new_ir_mode("WS", irms_int_number, size_bits, 1,
+ arithmetic, modulo_shift);
+ env->low_unsigned = new_ir_mode("WU", irms_int_number, size_bits, 0,
+ arithmetic, modulo_shift);
+}
+
+static void enqueue_preds(lower_env_t *env, ir_node *node)
+{
+ int arity = get_irn_arity(node);
+ int i;
+
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ pdeq_putr(env->waitq, pred);
+ }
+}
+
+static void lower_node(lower_env_t *env, ir_node *node)
+{
+ int arity;
+ int i;
+ lower_func func;
+ ir_op *op;
+ ir_mode *mode;
+ unsigned idx;
+ node_entry_t *entry;
+
+ if (irn_visited(node))
+ return;
+ mark_irn_visited(node);
+
+ /* cycles are always broken at Phi and Block nodes. So we don't need special
+ * magic in all the other lower functions */
+ if (is_Block(node)) {
+ enqueue_preds(env, node);
+ return;
+ } else if (is_Phi(node)) {
+ lower_Phi(env, node);
+ return;
+ }
+
+ /* depth-first: descend into operands */
+ if (!is_Block(node)) {
+ ir_node *block = get_nodes_block(node);
+ lower_node(env, block);
+ }
+
+ arity = get_irn_arity(node);
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ lower_node(env, pred);
+ }
+
+ op = get_irn_op(node);
+ func = (lower_func) op->ops.generic;
+ if (func == NULL)
+ return;
+
+ idx = get_irn_idx(node);
+ entry = idx < env->n_entries ? env->entries[idx] : NULL;
+ if (entry != NULL || always_lower(get_irn_opcode(node))) {
+ mode = get_irn_op_mode(node);
+ if (mode == env->high_signed) {
+ mode = env->low_signed;
+ } else {
+ mode = env->low_unsigned;
+ }
+ DB((dbg, LEVEL_1, " %+F\n", node));
+ func(node, mode, env);
+ }
+}
+
+static void lower_irg(lower_env_t *env, ir_graph *irg)
+{
+ ir_entity *ent;
+ ir_type *mtp;
+ unsigned n_idx;
+
+ obstack_init(&env->obst);
+
+ n_idx = get_irg_last_idx(irg);
+ n_idx = n_idx + (n_idx >> 2); /* add 25% */
+ env->n_entries = n_idx;
+ env->entries = NEW_ARR_F(node_entry_t*, n_idx);
+ memset(env->entries, 0, sizeof(env->entries[0]) * n_idx);
+
+ env->irg = irg;
+ env->l_mtp = NULL;
+ env->flags = 0;
+ env->proj_2_block = pmap_create();
+ env->value_param_tp = NULL;
+
+ ent = get_irg_entity(irg);
+ mtp = get_entity_type(ent);
+
+ if (mtp_must_be_lowered(env, mtp)) {
+ ir_type *ltp = lower_mtp(env, mtp);
+ env->flags |= MUST_BE_LOWERED;
+ set_entity_type(ent, ltp);
+ env->l_mtp = ltp;
+ env->value_param_tp = get_method_value_param_type(mtp);
+ }
+
+ /* first step: link all nodes and allocate data */
+ ir_reserve_resources(irg, IR_RESOURCE_PHI_LIST | IR_RESOURCE_IRN_LINK);
+ irg_walk_graph(irg, firm_clear_node_and_phi_links,
+ prepare_links_and_handle_rotl, env);
+
+ if (env->flags & MUST_BE_LOWERED) {
+ int i;
+ ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
+ inc_irg_visited(irg);
+
+ assert(pdeq_empty(env->waitq));
+ pdeq_putr(env->waitq, get_irg_end(irg));
+
+ env->lowered_phis = NEW_ARR_F(ir_node*, 0);
+ while (!pdeq_empty(env->waitq)) {
+ ir_node *node = (ir_node*)pdeq_getl(env->waitq);
+ lower_node(env, node);
+ }
+
+ /* we need to fixup phis */
+ for (i = 0; i < ARR_LEN(env->lowered_phis); ++i) {
+ ir_node *phi = env->lowered_phis[i];
+ fixup_phi(env, phi);
+ }
+ DEL_ARR_F(env->lowered_phis);
+
+
+ ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
+
+ /* outs are invalid, we changed the graph */
+ set_irg_outs_inconsistent(irg);
+
+ if (env->flags & CF_CHANGED) {
+ /* control flow changed, dominance info is invalid */
+ set_irg_doms_inconsistent(irg);
+ set_irg_extblk_inconsistent(irg);
+ set_irg_loopinfo_inconsistent(irg);
+ }
+ }
+
+ ir_free_resources(irg, IR_RESOURCE_PHI_LIST | IR_RESOURCE_IRN_LINK);
+
+ pmap_destroy(env->proj_2_block);
+ DEL_ARR_F(env->entries);
+ obstack_free(&env->obst, NULL);
+}