Exemplo n.º 1
0
/**
 * Check, whether a Return can be moved on block upwards.
 *
 * In a block with a Return, all live nodes must be linked
 * with the Return, otherwise they are dead (because the Return leaves
 * the graph, so no more users of the other nodes can exists.
 *
 * We can move a Return, if its predecessors are Phi nodes or
 * comes from another block. In the later case, it is always possible
 * to move the Return one block up, because the predecessor block must
 * dominate the Return block (SSA) and then it dominates the predecessor
 * block of the Return block as well.
 *
 * All predecessors of the Return block must be Jmp's of course, or we
 * cannot move it up, so we add blocks if needed.
 */
static bool can_move_ret(ir_node *ret)
{
    ir_node *retbl = get_nodes_block(ret);
    int i, n = get_irn_arity(ret);

    for (i = 0; i < n; ++i) {
        ir_node *pred = get_irn_n(ret, i);

        if (! is_Phi(pred) && retbl == get_nodes_block(pred)) {
            /* first condition failed, found a non-Phi predecessor
             * then is in the Return block */
            return false;
        }
    }

    /* check, that predecessors are Jmps */
    n = get_Block_n_cfgpreds(retbl);
    /* we cannot move above a labeled block, as this might kill the block */
    if (n <= 1 || get_Block_entity(retbl) != NULL)
        return false;
    for (i = 0; i < n; ++i) {
        ir_node *pred = get_Block_cfgpred(retbl, i);

        pred = skip_Tuple(pred);
        if (! is_Jmp(pred) && !is_Bad(pred)) {
            /* simply place a new block here */
            ir_graph *irg  = get_irn_irg(retbl);
            ir_node *block = new_r_Block(irg, 1, &pred);
            ir_node *jmp   = new_r_Jmp(block);
            set_Block_cfgpred(retbl, i, jmp);
        }
    }
    return true;
}
Exemplo n.º 2
0
/**
 * Block-walker, remove Bad block predecessors and shorten Phis.
 * Phi links must be up-to-date.
 */
static void block_remove_bads(ir_node *block)
{
	/* 1. Create a new block without Bad inputs */
	ir_graph  *irg     = get_irn_irg(block);
	const int  max     = get_Block_n_cfgpreds(block);
	ir_node  **new_in  = ALLOCAN(ir_node*, max);
	unsigned   new_max = 0;
	for (int i = 0; i < max; ++i) {
		ir_node *const block_pred = get_Block_cfgpred(block, i);
		if (!is_Bad(block_pred)) {
			new_in[new_max++] = block_pred;
		}
	}

	/* If the end block is unreachable, it might have zero predecessors. */
	if (new_max == 0) {
		ir_node *end_block = get_irg_end_block(irg);
		if (block == end_block) {
			set_irn_in(block, new_max, new_in);
			return;
		}
	}

	dbg_info  *dbgi         = get_irn_dbg_info(block);
	ir_node   *new_block    = new_rd_Block(dbgi, irg, new_max, new_in);
	ir_entity *block_entity = get_Block_entity(block);
	set_Block_entity(new_block, block_entity);

	/* 2. Remove inputs on Phis, where the block input is Bad. */
	for (ir_node *phi = get_Block_phis(block), *next; phi != NULL; phi = next) {
		next = get_Phi_next(phi);

		assert(get_irn_arity(phi) == max);

		unsigned j = 0;
		foreach_irn_in(phi, i, pred) {
			ir_node *const block_pred = get_Block_cfgpred(block, i);
			if (!is_Bad(block_pred)) {
				new_in[j++] = pred;
			}
		}
		assert(j == new_max);

		/* shortcut if only 1 phi input is left */
		if (new_max == 1) {
			ir_node *new_node = new_in[0];
			/* can happen inside unreachable endless loops */
			if (new_node == phi)
				return;
			if (get_Phi_loop(phi))
				remove_keep_alive(phi);
			exchange(phi, new_node);
		} else {
			set_irn_in(phi, new_max, new_in);
		}
	}
Exemplo n.º 3
0
/**
 * Pre-block-walker: calculate the control dependence
 */
static void cdep_pre(ir_node *node, void *ctx)
{
	(void)ctx;
	for (int i = get_Block_n_cfgpreds(node); i-- > 0; ) {
		ir_node *pred = get_Block_cfgpred_block(node, i);
		if (is_Bad(pred))
			continue;

		ir_node *pdom = get_Block_ipostdom(pred);
		for (ir_node *dependee = node; dependee != pdom;
		     dependee = get_Block_ipostdom(dependee)) {
			assert(!is_Bad(pdom));
			add_cdep(dependee, pred);
		}
	}
}
Exemplo n.º 4
0
/*
 * Normalize the Returns of a graph by moving
 * the Returns upwards as much as possible.
 * This might be preferred for code generation.
 *
 * In pseudocode, it means:
 *
 * if (a)
 *   res = b;
 * else
 *   res = c;
 * return res;
 *
 * is transformed into
 *
 * if (a)
 *   return b;
 * else
 *   return c;
 */
void normalize_n_returns(ir_graph *irg)
{
    int i, j, n;
    ir_node  *list     = NULL;
    ir_node  *final    = NULL;
    unsigned  n_rets   = 0;
    unsigned  n_finals = 0;
    ir_node  *endbl    = get_irg_end_block(irg);
    int       n_ret_vals;
    ir_node **in;
    ir_node  *end;

    /*
     * First, link all returns:
     * These must be predecessors of the endblock.
     * Place Returns that can be moved on list, all others
     * on final.
     */
    n = get_Block_n_cfgpreds(endbl);
    for (i = 0; i < n; ++i) {
        ir_node *ret = get_Block_cfgpred(endbl, i);

        if (is_Bad(ret)) {
            continue;
        } else if (is_Return(ret) && can_move_ret(ret)) {
            /*
             * Ok, all conditions met, we can move this Return, put it
             * on our work list.
             */
            set_irn_link(ret, list);
            list = ret;
            ++n_rets;
        } else {
            /* Put all nodes that are not changed on the final list. */
            set_irn_link(ret, final);
            final = ret;
            ++n_finals;
        }
    }
Exemplo n.º 5
0
/*
 * Normalize the Returns of a graph by creating a new End block
 * with One Return(Phi).
 * This is the preferred input for the if-conversion.
 *
 * In pseudocode, it means:
 *
 * if (a)
 *   return b;
 * else
 *   return c;
 *
 * is transformed into
 *
 * if (a)
 *   res = b;
 * else
 *   res = c;
 * return res;
 */
void normalize_one_return(ir_graph *irg)
{
    ir_node   *endbl         = get_irg_end_block(irg);
    ir_entity *entity        = get_irg_entity(irg);
    ir_type   *type          = get_entity_type(entity);
    int        n_ret_vals    = get_method_n_ress(type) + 1;
    int        n_rets        = 0;
    bool       filter_dbgi   = false;
    dbg_info  *combined_dbgi = NULL;
    int i, j, k, n, last_idx;
    ir_node **in, **retvals, **endbl_in;
    ir_node *block;

    /* look, if we have more than one return */
    n = get_Block_n_cfgpreds(endbl);
    if (n <= 0) {
        /* The end block has no predecessors, we have an endless
           loop. In that case, no returns exists. */
        confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_ALL);
        add_irg_properties(irg, IR_GRAPH_PROPERTY_ONE_RETURN);
        return;
    }

    unsigned *const returns = rbitset_alloca(n);
    for (i = 0; i < n; ++i) {
        ir_node *node = get_Block_cfgpred(endbl, i);

        if (is_Return(node)) {
            dbg_info *dbgi = get_irn_dbg_info(node);

            if (dbgi != NULL && dbgi != combined_dbgi) {
                if (filter_dbgi) {
                    combined_dbgi = NULL;
                } else {
                    combined_dbgi = dbgi;
                    filter_dbgi   = true;
                }
            }

            ++n_rets;
            rbitset_set(returns, i);
        }
    }

    if (n_rets <= 1) {
        confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_ALL);
        add_irg_properties(irg, IR_GRAPH_PROPERTY_ONE_RETURN);
        return;
    }

    in       = ALLOCAN(ir_node*, MAX(n_rets, n_ret_vals));
    retvals  = ALLOCAN(ir_node*, n_rets * n_ret_vals);
    endbl_in = ALLOCAN(ir_node*, n);

    last_idx = 0;
    for (j = i = 0; i < n; ++i) {
        ir_node *ret = get_Block_cfgpred(endbl, i);

        if (rbitset_is_set(returns, i)) {
            ir_node *block = get_nodes_block(ret);

            /* create a new Jmp for every Ret and place the in in */
            in[j] = new_r_Jmp(block);

            /* save the return values and shuffle them */
            for (k = 0; k < n_ret_vals; ++k)
                retvals[j + k*n_rets] = get_irn_n(ret, k);

            ++j;
        } else {
            endbl_in[last_idx++] = ret;
        }
    }

    /* ok, create a new block with all created in's */
    block = new_r_Block(irg, n_rets, in);

    /* now create the Phi nodes */
    for (j = i = 0; i < n_ret_vals; ++i, j += n_rets) {
        ir_mode *mode = get_irn_mode(retvals[j]);
        in[i] = new_r_Phi(block, n_rets, &retvals[j], mode);
    }

    endbl_in[last_idx++] = new_rd_Return(combined_dbgi, block, in[0], n_ret_vals-1, &in[1]);

    set_irn_in(endbl, last_idx, endbl_in);

    /* invalidate analysis information:
     * a new Block was added, so dominator, outs and loop are inconsistent,
     * trouts and callee-state should be still valid */
    confirm_irg_properties(irg,
                           IR_GRAPH_PROPERTY_NO_BADS
                           | IR_GRAPH_PROPERTY_NO_TUPLES
                           | IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES
                           | IR_GRAPH_PROPERTY_NO_UNREACHABLE_CODE
                           | IR_GRAPH_PROPERTY_CONSISTENT_ENTITY_USAGE);
    add_irg_properties(irg, IR_GRAPH_PROPERTY_ONE_RETURN);
}