amd64_finish.c 8.79 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
/*
 * Copyright (C) 1995-2012 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   This file implements functions to finalize the irg for emit.
 */
24
#include "amd64_common_transform.h"
25
#include "amd64_finish.h"
Matthias Braun's avatar
Matthias Braun committed
26
27
#include "amd64_new_nodes.h"
#include "amd64_nodes_attr.h"
28
29
30
31
#include "bearch.h"
#include "benode.h"
#include "besched.h"
#include "debug.h"
Matthias Braun's avatar
Matthias Braun committed
32
#include "panic.h"
33
34
#include "gen_amd64_new_nodes.h"
#include "irgwalk.h"
Matthias Braun's avatar
Matthias Braun committed
35
#include "util.h"
36
#include "irgmod.h"
37
38
39
40
41
42

DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

/**
 * Returns the index of the first "same" register.
 */
Matthias Braun's avatar
Matthias Braun committed
43
static unsigned get_first_same(arch_register_req_t const *const req)
44
45
{
	unsigned const other = req->other_same;
Matthias Braun's avatar
Matthias Braun committed
46
	for (unsigned i = 0; i != 32; ++i) {
47
48
49
50
51
52
		if (other & (1U << i))
			return i;
	}
	panic("same position not found");
}

Matthias Braun's avatar
Matthias Braun committed
53
54
55
56
static bool try_swap_inputs(ir_node *node)
{
	/* commutative operation, just switch the inputs */
	if (is_amd64_Add(node) || is_amd64_And(node) || is_amd64_Or(node)
Tobias Rapp's avatar
Tobias Rapp committed
57
58
	 || is_amd64_Xor(node) || is_amd64_IMul(node) || is_amd64_xAdds(node)
	 || is_amd64_xMuls(node)) {
Matthias Braun's avatar
Matthias Braun committed
59
60
61
62
63
64
65
66
67
68
		/* TODO: support Cmp input swapping */
		ir_node *in0 = get_irn_n(node, 0);
		ir_node *in1 = get_irn_n(node, 1);
		set_irn_n(node, 0, in1);
		set_irn_n(node, 1, in0);
		return true;
	}
	return false;
}

69
70
71
72
73
74
75
76
77
78
/**
  * Transforms a Sub to a Neg + Add, which subsequently allows swapping
  * of the inputs. The swapping is also (implicitly) done here.
  */
static void transform_sub_to_neg_add(ir_node *node,
                                     const arch_register_t *out_reg)
{
	ir_node  *block = get_nodes_block(node);
	dbg_info *dbgi  = get_irn_dbg_info(node);

79
80
81
	ir_graph *irg = get_irn_irg(node);
	ir_node  *in1 = get_irn_n(node, 0);
	ir_node  *in2 = get_irn_n(node, 1);
82

83
	const arch_register_t *in2_reg = arch_get_irn_register(in2);
84

85
86
87
88
89
90
91
92
93
94
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
125
126
127
128
129
130
131
132
	const amd64_binop_addr_attr_t *attr = get_amd64_binop_addr_attr(node);
	ir_node *add, *add_res;

	if (is_amd64_xSubs(node)) {
		ir_mode *mode = get_irn_mode(in2);
		ir_tarval *tv;
		if (get_mode_size_bits(mode) <= 32)
			tv = create_sign_tv(mode_Iu);
		else
			tv = create_sign_tv(mode_Lu);

		ir_entity *sign_bit_const = create_float_const_entity(irg, tv);

		/* xXorp needs a 128-bit memory address since it's a vector instruction.
		 * Setting the alignment works in this case, but is not the nice way.
		 * TODO: Create and set correct mode/type for the entity.
		 */
		set_entity_alignment(sign_bit_const, 16);

		amd64_binop_addr_attr_t xor_attr;
		memset(&xor_attr, 0, sizeof(xor_attr));
		xor_attr.base.addr.base_input       = NO_INPUT;
		xor_attr.base.addr.index_input      = NO_INPUT;
		xor_attr.base.addr.immediate.entity = sign_bit_const;
		xor_attr.base.base.op_mode          = AMD64_OP_ADDR_REG;

		ir_node *xor_in[] = { in2 };
		ir_node *xor = new_bd_amd64_xXorp(dbgi, block, ARRAY_SIZE(xor_in),
		                                  xor_in, &xor_attr);
		ir_node *neg = new_r_Proj(xor, mode_D, pn_amd64_xXorp_res);

		sched_add_before(node, xor);
		arch_set_irn_register(neg, in2_reg);

		ir_node *in[] = { neg, in1 };
		add     = new_bd_amd64_xAdds(dbgi, block, ARRAY_SIZE(in), in, attr);
		add_res = new_r_Proj(add, mode_D, pn_amd64_xAdds_res);
	} else {
		assert(is_amd64_Sub(node));
		ir_node *neg  = new_bd_amd64_Neg(dbgi, block, in2,
		                                 attr->base.insn_mode);
		arch_set_irn_register(neg, out_reg);
		sched_add_before(node, neg);

		ir_node *in[2] = { neg, in1 };
		add     = new_bd_amd64_Add(dbgi, block, ARRAY_SIZE(in), in, attr);
		add_res = new_r_Proj(add, mode_Lu, pn_amd64_Add_res);
	}
133
134
135
136
137
138
139
140
141
	arch_set_irn_register(add_res, out_reg);

	/* exchange the add and the sub */
	edges_reroute(node, add);
	sched_replace(node, add);

	kill_node(node);
}

Matthias Braun's avatar
Matthias Braun committed
142
143
static ir_node *amd64_turn_back_am(ir_node *node)
{
Matthias Braun's avatar
Matthias Braun committed
144
145
146
	dbg_info          *dbgi  = get_irn_dbg_info(node);
	ir_node           *block = get_nodes_block(node);
	amd64_addr_attr_t *attr  = get_amd64_addr_attr(node);
Matthias Braun's avatar
Matthias Braun committed
147

Matthias Braun's avatar
Matthias Braun committed
148
	amd64_addr_t new_addr = attr->addr;
Matthias Braun's avatar
Matthias Braun committed
149
150
	ir_node *load_in[3];
	int      load_arity = 0;
Matthias Braun's avatar
Matthias Braun committed
151
152
153
154
	if (attr->addr.base_input != NO_INPUT
	 && attr->addr.base_input != RIP_INPUT) {
		new_addr.base_input = load_arity;
		load_in[load_arity++] = get_irn_n(node, attr->addr.base_input);
Matthias Braun's avatar
Matthias Braun committed
155
	}
Matthias Braun's avatar
Matthias Braun committed
156
157
158
	if (attr->addr.index_input != NO_INPUT) {
		new_addr.index_input = load_arity;
		load_in[load_arity++] = get_irn_n(node, attr->addr.index_input);
Matthias Braun's avatar
Matthias Braun committed
159
	}
Matthias Braun's avatar
Matthias Braun committed
160
161
162
	assert(attr->addr.mem_input != NO_INPUT);
	new_addr.mem_input = load_arity;
	load_in[load_arity++] = get_irn_n(node, attr->addr.mem_input);
Matthias Braun's avatar
Matthias Braun committed
163

Matthias Braun's avatar
Matthias Braun committed
164
	ir_node *load = new_bd_amd64_Mov(dbgi, block, load_arity, load_in,
165
	                                 attr->insn_mode, AMD64_OP_ADDR, new_addr);
Matthias Braun's avatar
Matthias Braun committed
166
	ir_node *load_res = new_r_Proj(load, mode_Lu, pn_amd64_Mov_res);
Matthias Braun's avatar
Matthias Braun committed
167
168

	/* change operation */
Matthias Braun's avatar
Matthias Braun committed
169
170
	const amd64_binop_addr_attr_t *binop_attr
		= (const amd64_binop_addr_attr_t*)attr;
Matthias Braun's avatar
Matthias Braun committed
171
	ir_node *new_in[2];
Matthias Braun's avatar
Matthias Braun committed
172
	new_in[0] = get_irn_n(node, binop_attr->u.reg_input);
Matthias Braun's avatar
Matthias Braun committed
173
174
	new_in[1] = load_res;
	set_irn_in(node, ARRAY_SIZE(new_in), new_in);
Matthias Braun's avatar
Matthias Braun committed
175
176
177
	attr->base.op_mode     = AMD64_OP_REG_REG;
	attr->addr.base_input  = NO_INPUT;
	attr->addr.index_input = NO_INPUT;
Matthias Braun's avatar
Matthias Braun committed
178
179
180
181
182
183

	/* rewire mem-proj */
	foreach_out_edge(node, edge) {
		ir_node *out = get_edge_src_irn(edge);
		if (get_irn_mode(out) == mode_M) {
			set_Proj_pred(out, load);
184
			set_Proj_num(out, pn_amd64_Mov_M);
Matthias Braun's avatar
Matthias Braun committed
185
186
187
188
189
190
191
192
193
			break;
		}
	}

	if (sched_is_scheduled(node))
		sched_add_before(node, load);
	return load_res;
}

194
195
196
197
198
199
/**
 * Insert copies for all amd64 nodes where the should_be_same requirement is
 * not fulfilled.
 */
static void assure_should_be_same_requirements(ir_node *const node)
{
Matthias Braun's avatar
Matthias Braun committed
200
	unsigned const n_res = arch_get_irn_n_outs(node);
201
202

	/* Check all OUT requirements, if there is a should_be_same. */
Matthias Braun's avatar
Matthias Braun committed
203
204
205
206
207
208
209
210
211
212
213
214
	for (unsigned i = 0; i < n_res; ++i) {
		arch_register_req_t const *const req
			= arch_get_irn_register_req_out(node, i);
		if (!arch_register_req_is(req, should_be_same))
			continue;
		unsigned               const same_pos = get_first_same(req);
		ir_node               *const in_node  = get_irn_n(node, same_pos);
		arch_register_t const *const in_reg   = arch_get_irn_register(in_node);
		arch_register_t const *const out_reg
			= arch_get_irn_register_out(node, i);
		if (in_reg == out_reg)
			continue;
215

Matthias Braun's avatar
Matthias Braun committed
216
217
218
219
220
		/* test if any other input is using the out register */
		for (int i2 = 0, arity = get_irn_arity(node); i2 < arity; ++i2) {
			const arch_register_t *reg = arch_get_irn_register_in(node, i2);
			if (reg == out_reg && (unsigned)i2 != same_pos) {
				if (!is_amd64_irn(node))
yb9976's avatar
yb9976 committed
221
					panic("Cannot fulfill should_be_same on non-amd64 node");
Matthias Braun's avatar
Matthias Braun committed
222
223
				/* see what role this register has */
				const amd64_attr_t *attr = get_amd64_attr_const(node);
Matthias Braun's avatar
Matthias Braun committed
224
225
226
				if (attr->op_mode == AMD64_OP_ADDR
				 || attr->op_mode == AMD64_OP_REG
				 || attr->op_mode == AMD64_OP_REG_IMM) {
Matthias Braun's avatar
Matthias Braun committed
227
					panic("unexpected op_mode");
Matthias Braun's avatar
Matthias Braun committed
228
				} else if (attr->op_mode == AMD64_OP_REG_REG) {
Matthias Braun's avatar
Matthias Braun committed
229
230
231
232
swap:;
					bool res = try_swap_inputs(node);
					if (res)
						return;
233

234
					if (is_amd64_Sub(node) || is_amd64_xSubs(node)) {
235
236
237
						transform_sub_to_neg_add(node, out_reg);
						return;
					}
Matthias Braun's avatar
Matthias Braun committed
238
239
					panic("couldn't swap inputs of %+F", node);
				} else {
Matthias Braun's avatar
Matthias Braun committed
240
					assert(attr->op_mode == AMD64_OP_ADDR_REG);
Matthias Braun's avatar
Matthias Braun committed
241
242
243
244
245
246
247
248
					/* extract load into an own instruction */
					ir_node *res = amd64_turn_back_am(node);
					arch_set_irn_register(res, out_reg);
					goto swap;
				}
			}
		}

Matthias Braun's avatar
Matthias Braun committed
249
250
		ir_node *const block = get_nodes_block(node);
		ir_node *const copy  = be_new_Copy(block, in_node);
251

Matthias Braun's avatar
Matthias Braun committed
252
253
254
255
256
257
258
259
		/* Destination is the out register. */
		arch_set_irn_register(copy, out_reg);
		/* Insert copy before the node into the schedule. */
		sched_add_before(node, copy);
		/* Set copy as in. */
		set_irn_n(node, same_pos, copy);

		DBG((dbg, LEVEL_1, "created copy %+F for should be same argument at input %d of %+F\n", copy, same_pos, node));
260
261
262
263
264
265
266
267
268
269
270
	}
}

/**
 * Block walker: finishes a block.
 */
static void amd64_finish_irg_walker(ir_node *const block, void *const env)
{
	(void) env;

	/* Insert should_be_same copies. */
Matthias Braun's avatar
Matthias Braun committed
271
272
	for (ir_node *irn = sched_first(block), *next; !sched_is_end(irn);
	     irn = next) {
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
		next = sched_next(irn);
		if (is_amd64_irn(irn)) {
			assure_should_be_same_requirements(irn);
		}
	}
}

/**
 * Add Copy nodes for not fulfilled should_be_same constraints.
 */
void amd64_finish_irg(ir_graph *const irg)
{
	irg_block_walk_graph(irg, 0, amd64_finish_irg_walker, 0);
}

void amd64_init_finish(void)
{
	FIRM_DBG_REGISTER(dbg, "firm.be.amd64.finish");
}