rm_bads.c 3.41 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

/**
 * @brief    Remove all Bad nodes from ir graph
 * @author   Andreas Zwinkau
 */
#include "config.h"

#include <assert.h>

#include "irnode_t.h"

#include "irgopt.h"
#include "irgmod.h"
#include "irgwalk.h"

#include "irtools.h"

/**
 * Return the number of non-Bad predecessors of the given node.
 */
static int count_non_bads(ir_node *node)
{
	int arity = get_irn_arity(node);
	int count = 0;
	int i;
	for (i = 0; i < arity; ++i) {
		if (!is_Bad(get_irn_n(node, i)))
			++count;
	}
	return count;
}

/**
 * Block-walker, remove Bad block predecessors and shorten Phis.
 * Phi links must be uptodate.
 */
static void block_remove_bads(ir_node *block, void *env)
{
	int *changed = (int *)env;
	int i, j;
	ir_node **new_in, *new_block, *phi;
Andreas Zwinkau's avatar
Andreas Zwinkau committed
60
	ir_entity *block_entity;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
	const int max = get_irn_arity(block);
	const int new_max = count_non_bads(block);
	assert(max >= new_max);

	if (is_Bad(block) || max == new_max)
		return;

	new_in = ALLOCAN(ir_node*, new_max);
	*changed = 1;

	assert(get_Block_dom_depth(block) >= 0);

	/* 1. Create a new block without Bad inputs */
	for (i = j = 0; i < max; ++i) {
		ir_node *block_pred = get_irn_n(block, i);
		if (!is_Bad(block_pred)) {
			new_in[j++] = block_pred;
		}
	}
	assert(j == new_max);

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

	new_block = new_r_Block(get_irn_irg(block), new_max, new_in);
92
93
94
	block_entity = get_Block_entity(block);
	if (block_entity)
		set_Block_entity(new_block, block_entity);
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

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

				for (i = j = 0; i < max; ++i) {
					ir_node *block_pred = get_irn_n(block, i);

					if (!is_Bad(block_pred)) {
						ir_node *pred = get_irn_n(phi, i);
						new_in[j++] = pred;
					}
				}
				assert(j == new_max);

				new_phi = new_r_Phi(new_block, new_max, new_in, get_irn_mode(phi));
				exchange(phi, new_phi);
			}
			phi = next;
		} while (phi != NULL);
	}

	exchange(block, new_block);
}

/* Remove Bad nodes from Phi and Block inputs.
Andreas Zwinkau's avatar
Andreas Zwinkau committed
125
126
 *
 * This does NOT remove unreachable code.
127
128
129
130
131
132
133
134
135
136
137
138
139
140
 *
 * Postcondition: No Bad nodes.
 */
int remove_bads(ir_graph *irg)
{
	int changed = 0;
	/* build phi list per block */
	irg_walk_graph(irg, firm_clear_block_phis, firm_collect_block_phis, NULL);

	/* actually remove Bads */
	irg_block_walk_graph(irg, NULL, block_remove_bads, (void *)&changed);

	if (changed) {
		edges_deactivate(irg);
Andreas Zwinkau's avatar
Andreas Zwinkau committed
141
		clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_OUTS);
142
143
144
145
	}

	return changed;
}