convopt.c 5.27 KB
Newer Older
Matthias Braun's avatar
Matthias Braun committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * Copyright (C) 1995-2007 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.
 */

/**
 * @file
 * @brief   conv node optimisation
 * @author  Matthias Braun, Christoph Mallon
24
 * @version $Id$
Matthias Braun's avatar
Matthias Braun committed
25
26
27
28
29
30
31
32
33
34
 *
 * Try to minimize the number of conv nodes by changing modes of operations.
 * The typical example is the following structure:
 *    (some node mode_Hs)
 *            |                                       (some node_Hs)
 *         Conv Is                                          |
 *            |                                          Add Hs
 *          Add Is            gets transformed to           |
 *            |
 *         Conv Hs
Matthias Braun's avatar
Matthias Braun committed
35
36
37
 *
 * TODO: * try to optimize cmp modes
 *       * decide when it is useful to move the convs through phis
Matthias Braun's avatar
Matthias Braun committed
38
39
40
41
42
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

43
44
#include "iroptimize.h"

Matthias Braun's avatar
Matthias Braun committed
45
46
47
48
#include <assert.h>
#include "debug.h"
#include "ircons.h"
#include "irgmod.h"
49
#include "irgopt.h"
Matthias Braun's avatar
Matthias Braun committed
50
51
52
53
54
55
56
57
58
59
#include "irnode_t.h"
#include "iredges_t.h"
#include "irgwalk.h"
#include "irprintf.h"

DEBUG_ONLY(static firm_dbg_module_t *dbg);

static
int is_optimizable_node(const ir_node *node)
{
60
61
62
63
64
65
66
67
68
69
	return
		is_Add(node) ||
		is_Sub(node) ||
		is_Mul(node) ||
		is_Phi(node);
}

static tarval* conv_const_tv(const ir_node* cnst, ir_mode* dest_mode)
{
	return tarval_convert_to(get_Const_tarval(cnst), dest_mode);
Matthias Braun's avatar
Matthias Braun committed
70
71
72
73
74
75
}

static
int get_conv_costs(const ir_node *node, ir_mode *dest_mode)
{
	ir_mode *mode = get_irn_mode(node);
76
77
78
	size_t arity;
	size_t i;
	int costs;
Matthias Braun's avatar
Matthias Braun committed
79

80
	if (mode == dest_mode)
Matthias Braun's avatar
Matthias Braun committed
81
82
		return 0;

83
84
85
86
87
88
	if (is_Const(node)) {
		/* TODO tarval module is incomplete and can't convert floats to ints */
		return conv_const_tv(node, dest_mode) == tarval_bad ? 1 : 0;
	}

	if (get_irn_n_edges(node) > 1) {
Matthias Braun's avatar
Matthias Braun committed
89
90
91
92
		DB((dbg, LEVEL_3, "multi outs at %+F\n", node));
		return 1;
	}

93
	if (is_Conv(node)) {
Matthias Braun's avatar
Matthias Braun committed
94
95
96
		return get_conv_costs(get_Conv_op(node), dest_mode) - 1;
	}

97
98
99
	if (!is_optimizable_node(node)) {
		return 1;
	}
Matthias Braun's avatar
Matthias Braun committed
100

101
102
103
104
105
	costs = 0;
	arity = get_irn_arity(node);
	for (i = 0; i < arity; ++i) {
		ir_node *pred = get_irn_n(node, i);
		costs += get_conv_costs(pred, dest_mode);
Matthias Braun's avatar
Matthias Braun committed
106
107
	}

108
109
110
111
112
113
114
115
	return costs;
}

static ir_node *place_conv(ir_node *node, ir_mode *dest_mode)
{
	ir_node *block = get_nodes_block(node);
	ir_node *conv = new_r_Conv(current_ir_graph, block, node, dest_mode);
	return conv;
Matthias Braun's avatar
Matthias Braun committed
116
117
118
119
120
121
122
123
124
125
126
127
}

static
ir_node *conv_transform(ir_node *node, ir_mode *dest_mode)
{
	size_t arity;
	size_t i;

	if (get_irn_mode(node) == dest_mode)
		return node;

	if (is_Const(node)) {
128
129
130
131
132
133
134
135
136
137
138
		/* TODO tarval module is incomplete and can't convert floats to ints */
		tarval *tv = conv_const_tv(node, dest_mode);
		if (tv == tarval_bad) {
			return place_conv(node, dest_mode);
		} else {
			return new_Const(dest_mode, tv);
		}
	}

	if (get_irn_n_edges(node) > 1) {
		return place_conv(node, dest_mode);
Matthias Braun's avatar
Matthias Braun committed
139
140
	}

Christoph Mallon's avatar
Christoph Mallon committed
141
142
143
144
	if (is_Conv(node)) {
		return conv_transform(get_Conv_op(node), dest_mode);
	}

145
146
	if (!is_optimizable_node(node)) {
		return place_conv(node, dest_mode);
Matthias Braun's avatar
Matthias Braun committed
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
	}

	arity = get_irn_arity(node);
	for (i = 0; i < arity; i++) {
		ir_node *pred = get_irn_n(node, i);
		ir_node *transformed = conv_transform(pred, dest_mode);
		set_irn_n(node, i, transformed);
	}
	set_irn_mode(node, dest_mode);
	return node;
}

static
int is_downconv(ir_mode *src_mode, ir_mode *dest_mode)
{
162
163
164
165
	return
		mode_is_int(src_mode) &&
		mode_is_int(dest_mode) &&
		get_mode_size_bits(dest_mode) < get_mode_size_bits(src_mode);
Matthias Braun's avatar
Matthias Braun committed
166
167
}

168
169
/* TODO, backends (at least ia23) can't handle it at the moment,
   and it's probably not more efficient on most
Matthias Braun's avatar
Matthias Braun committed
170
171
172
173
174
175
176
177
178
179
180
181
182
   archs */
#if 0
static
void try_optimize_cmp(ir_node *node)
{
	ir_node *left  = get_Cmp_left(node);
	ir_node *right = get_Cmp_right(node);
	ir_node *conv  = NULL;

	if(is_downconv
}
#endif

Christoph Mallon's avatar
Christoph Mallon committed
183
184
static char changed;

Matthias Braun's avatar
Matthias Braun committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
static
void conv_opt_walker(ir_node *node, void *data)
{
	ir_node *transformed;
	ir_node *pred;
	ir_mode *pred_mode;
	ir_mode *mode;
	int costs;

#if 0
	if(is_Cmp(node)) {
		try_optimize_cmp(node);
		return;
	}
#endif

201
	if (!is_Conv(node))
Matthias Braun's avatar
Matthias Braun committed
202
203
204
205
206
207
		return;

	pred      = get_Conv_op(node);
	mode      = get_irn_mode(node);
	pred_mode = get_irn_mode(pred);

Christoph Mallon's avatar
Christoph Mallon committed
208
	if (!is_Phi(pred) && !is_downconv(pred_mode, mode))
Matthias Braun's avatar
Matthias Braun committed
209
210
		return;

211
212
	/* - 1 for the initial conv */
	costs = get_conv_costs(pred, mode) - 1;
Matthias Braun's avatar
Matthias Braun committed
213
	DB((dbg, LEVEL_2, "Costs for %+F -> %+F: %d\n", node, pred, costs));
214
	if (costs >= 0) return;
Matthias Braun's avatar
Matthias Braun committed
215
216
217

	transformed = conv_transform(pred, mode);
	exchange(node, transformed);
Christoph Mallon's avatar
Christoph Mallon committed
218
	changed = 1;
Matthias Braun's avatar
Matthias Braun committed
219
220
221
222
223
224
225
226
227
}

void conv_opt(ir_graph *irg)
{
	FIRM_DBG_REGISTER(dbg, "firm.opt.conv");

	DB((dbg, LEVEL_1, "===> Performing conversion optimization on %+F\n", irg));

	edges_assure(irg);
228
	char invalidate = 0;
Christoph Mallon's avatar
Christoph Mallon committed
229
230
231
232
	do {
		changed = 0;
		irg_walk_graph(irg, NULL, conv_opt_walker, NULL);
		local_optimize_graph(irg);
233
234
		if(changed)
			invalidate = 1;
Christoph Mallon's avatar
Christoph Mallon committed
235
	} while (changed);
236
237
238
239

	if(invalidate) {
		set_irg_outs_inconsistent(irg);
	}
Matthias Braun's avatar
Matthias Braun committed
240
}