sparc_finish.c 28 KB
Newer Older
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
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
 */

/**
 * @file
 * @brief    Peephole optimization and legalization of a sparc function
 * @author   Matthias Braun
 *
 * A note on sparc stackpointer (sp) behaviour:
 * The ABI expects SPARC_MIN_STACKSIZE bytes to be available at the
 * stackpointer. This space will be used to spill register windows,
 * and for spilling va_arg arguments (maybe we can optimize this away for
 * statically known not-va-arg-functions...)
 * This in effect means that we allocate that extra space at the function begin
 * which is easy. But this space isn't really fixed at the beginning of the
 * stackframe. Instead you should rather imagine the space as always being the
 * last-thing on the stack.
 * So when addressing anything stack-specific we have to account for this
 * area, while our compiler thinks the space is occupied at the beginning
 * of the stack frame. The code here among other things adjusts these offsets
 * accordingly.
 */
#include "config.h"

#include "bearch_sparc_t.h"
#include "gen_sparc_regalloc_if.h"
#include "sparc_new_nodes.h"
30
#include "sparc_transform.h"
31
32
#include "irprog.h"
#include "irgmod.h"
33
#include "ircons.h"
34
#include "irgwalk.h"
35
#include "heights.h"
36
#include "beirg.h"
37
38
39
40
41
42
#include "bepeephole.h"
#include "benode.h"
#include "besched.h"
#include "bespillslots.h"
#include "bestack.h"
#include "beirgmod.h"
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
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
#include "error.h"

static int get_first_same(const arch_register_req_t *req)
{
	const unsigned other = req->other_same;
	for (int i = 0; i < 32; ++i) {
		if (other & (1U << i))
			return i;
	}
	panic("same position not found");
}

/**
 * Insert copies for all ia32 nodes where the should_be_same requirement
 * is not fulfilled.
 * Transform Sub into Neg -- Add if IN2 == OUT
 */
static void assure_should_be_same_requirements(ir_node *node)
{
	ir_node *block = get_nodes_block(node);

	/* check all OUT requirements, if there is a should_be_same */
	be_foreach_out(node, i) {
		const arch_register_req_t *req = arch_get_irn_register_req_out(node, i);
		if (!arch_register_req_is(req, should_be_same))
			continue;

		int same_pos = get_first_same(req);

		/* get in and out register */
		const arch_register_t *out_reg = arch_get_irn_register_out(node, i);
		ir_node               *in_node = get_irn_n(node, same_pos);
		const arch_register_t *in_reg  = arch_get_irn_register(in_node);

		/* requirement already fulfilled? */
		if (in_reg == out_reg)
			continue;
		assert(in_reg->reg_class == out_reg->reg_class);

		/* check if any other input operands uses the out register */
		ir_node *uses_out_reg     = NULL;
		int      uses_out_reg_pos = -1;
		for (int i2 = 0, arity = get_irn_arity(node); i2 < arity; ++i2) {
			ir_node *in = get_irn_n(node, i2);
			if (!mode_is_data(get_irn_mode(in)))
				continue;

			const arch_register_t *other_in_reg = arch_get_irn_register(in);
			if (other_in_reg != out_reg)
				continue;

			if (uses_out_reg != NULL && in != uses_out_reg) {
				panic("invalid register allocation");
			}
			uses_out_reg = in;
			if (uses_out_reg_pos >= 0)
				uses_out_reg_pos = -1; /* multiple inputs... */
			else
				uses_out_reg_pos = i2;
		}

		/* no-one else is using the out reg, we can simply copy it
		 * (the register can't be live since the operation will override it
		 *  anyway) */
		if (uses_out_reg == NULL) {
			ir_node *copy = be_new_Copy(block, in_node);

			/* 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);
			continue;
		}

		panic("Unresolved should_be_same constraint");
	}
}
124

125
126
static ir_heights_t *heights;

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
static void kill_unused_stacknodes(ir_node *node)
{
	if (get_irn_n_edges(node) > 0)
		return;

	if (be_is_IncSP(node)) {
		sched_remove(node);
		kill_node(node);
	} else if (is_Phi(node)) {
		int       arity = get_irn_arity(node);
		ir_node **ins   = ALLOCAN(ir_node*, arity);
		sched_remove(node);
		memcpy(ins, get_irn_in(node), arity*sizeof(ins[0]));
		kill_node(node);

Matthias Braun's avatar
Matthias Braun committed
142
		for (int i = 0; i < arity; ++i)
143
144
145
146
147
148
			kill_unused_stacknodes(ins[i]);
	}
}

static void introduce_epilog(ir_node *ret)
{
149
	arch_register_t const *const sp_reg = &sparc_registers[REG_SP];
150
	assert(arch_get_irn_register_req_in(ret, n_sparc_Return_sp) == sp_reg->single_req);
151

152
153
154
155
	ir_node           *const sp     = get_irn_n(ret, n_sparc_Return_sp);
	ir_node           *const block  = get_nodes_block(ret);
	ir_graph          *const irg    = get_irn_irg(ret);
	be_stack_layout_t *const layout = be_get_irg_stack_layout(irg);
156
	if (!layout->sp_relative) {
157
158
159
160
		arch_register_t const *const fp_reg  = &sparc_registers[REG_FRAME_POINTER];
		ir_node               *const fp      = be_get_initial_reg_value(irg, fp_reg);
		ir_node               *const new_sp  = be_get_initial_reg_value(irg, sp_reg);
		ir_node               *const restore = new_bd_sparc_RestoreZero(NULL, block, new_sp, fp);
161
162
		sched_add_before(ret, restore);
		arch_set_irn_register(restore, sp_reg);
163
		set_irn_n(ret, n_sparc_Return_sp, restore);
164
165
		kill_unused_stacknodes(sp);
	} else {
166
167
168
		ir_type *const frame_type = get_irg_frame_type(irg);
		unsigned const frame_size = get_type_size_bytes(frame_type);
		ir_node *const incsp      = be_new_IncSP(sp_reg, block, sp, -frame_size, 0);
169
		set_irn_n(ret, n_sparc_Return_sp, incsp);
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
		sched_add_before(ret, incsp);
	}
}

void sparc_introduce_prolog_epilog(ir_graph *irg)
{
	const arch_register_t *sp_reg     = &sparc_registers[REG_SP];
	ir_node               *start      = get_irg_start(irg);
	be_stack_layout_t     *layout     = be_get_irg_stack_layout(irg);
	ir_node               *block      = get_nodes_block(start);
	ir_node               *initial_sp = be_get_initial_reg_value(irg, sp_reg);
	ir_node               *schedpoint = start;
	ir_type               *frame_type = get_irg_frame_type(irg);
	unsigned               frame_size = get_type_size_bytes(frame_type);

	/* introduce epilog for every return node */
Matthias Braun's avatar
Matthias Braun committed
186
187
188
189
190
	ir_node *end_block = get_irg_end_block(irg);
	for (int i = 0, arity = get_irn_arity(end_block); i < arity; ++i) {
		ir_node *ret = get_irn_n(end_block, i);
		assert(is_sparc_Return(ret));
		introduce_epilog(ret);
191
192
193
194
195
196
	}

	while (be_is_Keep(sched_next(schedpoint)))
		schedpoint = sched_next(schedpoint);

	if (!layout->sp_relative) {
197
		ir_node *const save = new_bd_sparc_Save_imm(NULL, block, initial_sp, NULL, -(SPARC_MIN_STACKSIZE + frame_size));
198
199
200
201
		arch_set_irn_register(save, sp_reg);
		sched_add_after(schedpoint, save);
		schedpoint = save;

202
		edges_reroute_except(initial_sp, save, save);
203

204
		/* we still need the Save even if noone is explicitely using the
205
		 * value. (TODO: this isn't 100% correct yet, something at the end of
206
		 * the function should hold the Save, even if we use a restore
207
208
		 * which just overrides it instead of using the value)
		 */
209
210
		if (get_irn_n_edges(save) == 0) {
			ir_node *in[] = { save };
211
212
213
214
			ir_node *keep = be_new_Keep(block, 1, in);
			sched_add_after(schedpoint, keep);
		}
	} else {
215
216
		ir_node *const incsp = be_new_IncSP(sp_reg, block, initial_sp, frame_size, 0);
		edges_reroute_except(initial_sp, incsp, incsp);
217
218
219
220
		sched_add_after(schedpoint, incsp);
	}
}

221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/**
 * Creates a constant from an immediate value.
 */
static ir_node *create_constant_from_immediate(ir_node *node, int offset)
{
	dbg_info *dbgi  = get_irn_dbg_info(node);
	ir_node  *block = get_nodes_block(node);
	ir_node  *high  = new_bd_sparc_SetHi(dbgi, block, NULL, offset);

	sched_add_before(node, high);
	arch_set_irn_register(high, &sparc_registers[REG_G4]);

	if ((offset & 0x3ff) != 0) {
		ir_node *low = new_bd_sparc_Or_imm(dbgi, block, high, NULL, offset & 0x3ff);

		sched_add_before(node, low);
		arch_set_irn_register(low, &sparc_registers[REG_G4]);

		return low;
	}

	return high;
}

245
246
247
248
249
static void finish_sparc_Save(ir_node *node)
{
	sparc_attr_t *attr = get_sparc_attr(node);
	int offset = attr->immediate_value;

Matthias Braun's avatar
Matthias Braun committed
250
	if (!sparc_is_value_imm_encodeable(offset)) {
251
252
253
254
255
256
257
258
259
260
261
262
263
		ir_node               *base     = get_irn_n(node, n_sparc_Save_stack);
		dbg_info              *dbgi     = get_irn_dbg_info(node);
		ir_node               *block    = get_nodes_block(node);
		ir_node               *constant = create_constant_from_immediate(node, offset);
		ir_node               *new_save = new_bd_sparc_Save_reg(dbgi, block, base, constant);
		const arch_register_t *reg      = arch_get_irn_register(node);

		/* we have a Save with immediate */
		assert(get_irn_arity(node) == 1);

		sched_add_before(node, new_save);
		arch_set_irn_register(new_save, reg);
		be_peephole_exchange(node, new_save);
264
265
266
267
	}
}

/**
268
 * SPARC immediates are limited. Split IncSP with bigger immediates if
269
270
271
272
 * necessary.
 */
static void finish_be_IncSP(ir_node *node)
{
273
274
275
	int offset = be_get_IncSP_offset(node);

	/* we might have to break the IncSP apart if the constant has become too big */
Matthias Braun's avatar
Matthias Braun committed
276
277
278
279
280
281
	if (!sparc_is_value_imm_encodeable(offset) && !sparc_is_value_imm_encodeable(-offset)) {
		ir_node  *sp       = be_get_IncSP_pred(node);
		dbg_info *dbgi     = get_irn_dbg_info(node);
		ir_node  *block    = get_nodes_block(node);
		ir_node  *constant = create_constant_from_immediate(node, offset);
		ir_node  *sub      = new_bd_sparc_Sub_reg(dbgi, block, sp, constant);
282
283
284
285

		sched_add_before(node, sub);
		arch_set_irn_register(sub, &sparc_registers[REG_SP]);
		be_peephole_exchange(node, sub);
286
287
288
289
	}
}

/**
yb9976's avatar
yb9976 committed
290
291
292
 * Adjust sp-relative offsets.
 *
 * Split into multiple instructions if offset exceeds SPARC immediate range.
293
294
295
296
297
298
 */
static void finish_sparc_FrameAddr(ir_node *node)
{
	sparc_attr_t *attr   = get_sparc_attr(node);
	int           offset = attr->immediate_value;

Matthias Braun's avatar
Matthias Braun committed
299
	if (!sparc_is_value_imm_encodeable(offset)) {
300
301
302
303
304
305
		ir_node               *base          = get_irn_n(node, n_sparc_FrameAddr_base);
		dbg_info              *dbgi          = get_irn_dbg_info(node);
		ir_node               *block         = get_nodes_block(node);
		ir_node               *constant      = create_constant_from_immediate(node, offset);
		ir_node               *new_frameaddr = new_bd_sparc_Add_reg(dbgi, block, base, constant);
		const arch_register_t *reg           = arch_get_irn_register(node);
306

307
		sched_add_before(node, new_frameaddr);
308
		arch_set_irn_register(new_frameaddr, reg);
309
		be_peephole_exchange(node, new_frameaddr);
310
311
312
	}
}

yb9976's avatar
yb9976 committed
313
314
315
316
317
318
static void finish_sparc_Ld(ir_node *node)
{
	sparc_attr_t                  *attr            = get_sparc_attr(node);
	int                            offset          = attr->immediate_value;
	const sparc_load_store_attr_t *load_store_attr = get_sparc_load_store_attr_const(node);

Matthias Braun's avatar
Matthias Braun committed
319
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
320
321
		return;

Matthias Braun's avatar
Matthias Braun committed
322
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
323
324
325
326
327
328
329
330
331
332
333
334
335
		ir_node                 *ptr             = get_irn_n(node, n_sparc_Ld_ptr);
		dbg_info                *dbgi            = get_irn_dbg_info(node);
		ir_node                 *block           = get_nodes_block(node);
		ir_node                 *mem             = get_irn_n(node, n_sparc_Ld_mem);
		ir_mode                 *load_store_mode = load_store_attr->load_store_mode;
		ir_node                 *constant        = create_constant_from_immediate(node, offset);
		ir_node                 *new_load        = new_bd_sparc_Ld_reg(dbgi, block, ptr, constant, mem, load_store_mode);
		sparc_load_store_attr_t *new_load_attr   = get_sparc_load_store_attr(new_load);

		new_load_attr->is_frame_entity = load_store_attr->is_frame_entity;
		new_load_attr->is_reg_reg      = load_store_attr->is_reg_reg;

		sched_add_before(node, new_load);
336
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
337
338
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
339
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
340
341
342
343
	}

}

344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
static void split_sparc_ldf(ir_node *node)
{
	sparc_load_store_attr_t *attr = get_sparc_load_store_attr(node);
	unsigned                 bits = get_mode_size_bits(attr->load_store_mode);
	/* split 128bit loads into 2 64bit loads */
	if (bits == 128) {
		dbg_info *dbgi  = get_irn_dbg_info(node);
		ir_node  *block = get_nodes_block(node);
		ir_node  *ptr   = get_irn_n(node, n_sparc_Ldf_ptr);
		ir_node  *mem   = get_irn_n(node, n_sparc_Ldf_mem);
		ir_node  *new_load
			= new_bd_sparc_Ldf_d(dbgi, block, ptr, mem, mode_D,
			                     attr->base.immediate_value_entity,
			                     attr->base.immediate_value + 8,
			                     attr->is_frame_entity);
		ir_node  *new_mem = new_r_Proj(new_load, mode_M, pn_sparc_Ldf_M);

		const arch_register_t *reg
			= arch_get_irn_register_out(node, pn_sparc_Ldf_res);
		unsigned reg_index = reg->global_index;

		arch_set_irn_register_out(new_load, pn_sparc_Ldf_res,
		                          &sparc_registers[reg_index+2]);

		attr->load_store_mode = mode_D;
		set_irn_n(node, n_sparc_Ldf_mem, new_mem);
		sched_add_before(node, new_load);
	}
}

yb9976's avatar
yb9976 committed
374
375
376
377
378
379
static void finish_sparc_Ldf(ir_node *node)
{
	sparc_attr_t                  *attr            = get_sparc_attr(node);
	int                            offset          = attr->immediate_value;
	const sparc_load_store_attr_t *load_store_attr = get_sparc_load_store_attr_const(node);

Matthias Braun's avatar
Matthias Braun committed
380
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
381
382
		return;

Matthias Braun's avatar
Matthias Braun committed
383
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
384
385
386
387
388
389
390
391
392
393
394
395
396
397
		ir_node                 *ptr             = get_irn_n(node, n_sparc_Ldf_ptr);
		dbg_info                *dbgi            = get_irn_dbg_info(node);
		ir_node                 *block           = get_nodes_block(node);
		ir_node                 *mem             = get_irn_n(node, n_sparc_Ldf_mem);
		ir_mode                 *load_store_mode = load_store_attr->load_store_mode;
		ir_node                 *constant        = create_constant_from_immediate(node, offset);
		ir_node                 *new_ptr         = new_bd_sparc_Add_reg(dbgi, block, ptr, constant);
		ir_node                 *new_load        = new_bd_sparc_Ldf_s(dbgi, block, new_ptr, mem, load_store_mode, NULL, 0, true);
		sparc_load_store_attr_t *new_load_attr   = get_sparc_load_store_attr(new_load);

		new_load_attr->is_frame_entity = load_store_attr->is_frame_entity;
		new_load_attr->is_reg_reg      = load_store_attr->is_reg_reg;

		sched_add_before(node, new_load);
398
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
399
400
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
401
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
402
403
404
405
406
407
408
409
410
411
	}

}

static void finish_sparc_St(ir_node *node)
{
	sparc_attr_t                  *attr            = get_sparc_attr(node);
	int                            offset          = attr->immediate_value;
	const sparc_load_store_attr_t *load_store_attr = get_sparc_load_store_attr_const(node);

Matthias Braun's avatar
Matthias Braun committed
412
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
413
414
		return;

Matthias Braun's avatar
Matthias Braun committed
415
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
416
417
418
419
420
421
422
423
424
425
426
427
428
429
		ir_node                 *ptr             = get_irn_n(node, n_sparc_St_ptr);
		dbg_info                *dbgi            = get_irn_dbg_info(node);
		ir_node                 *block           = get_nodes_block(node);
		ir_node                 *mem             = get_irn_n(node, n_sparc_St_mem);
		ir_node                 *value           = get_irn_n(node, n_sparc_St_val);
		ir_mode                 *load_store_mode = load_store_attr->load_store_mode;
		ir_node                 *constant        = create_constant_from_immediate(node, offset);
		ir_node                 *new_load        = new_bd_sparc_St_reg(dbgi, block, value, ptr, constant, mem, load_store_mode);
		sparc_load_store_attr_t *new_load_attr   = get_sparc_load_store_attr(new_load);

		new_load_attr->is_frame_entity = load_store_attr->is_frame_entity;
		new_load_attr->is_reg_reg      = load_store_attr->is_reg_reg;

		sched_add_before(node, new_load);
430
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
431
432
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
433
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
434
435
436
437
438
439
440
441
442
443
	}

}

static void finish_sparc_Stf(ir_node *node)
{
	sparc_attr_t                  *attr            = get_sparc_attr(node);
	int                            offset          = attr->immediate_value;
	const sparc_load_store_attr_t *load_store_attr = get_sparc_load_store_attr_const(node);

Matthias Braun's avatar
Matthias Braun committed
444
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
445
446
		return;

Matthias Braun's avatar
Matthias Braun committed
447
448
449
450
451
452
453
454
455
456
457
	if (!sparc_is_value_imm_encodeable(offset)) {
		ir_node  *ptr             = get_irn_n(node, n_sparc_Stf_ptr);
		dbg_info *dbgi            = get_irn_dbg_info(node);
		ir_node  *block           = get_nodes_block(node);
		ir_node  *mem             = get_irn_n(node, n_sparc_Stf_mem);
		ir_node  *value           = get_irn_n(node, n_sparc_Stf_val);
		ir_mode  *load_store_mode = load_store_attr->load_store_mode;
		ir_node  *constant        = create_constant_from_immediate(node, offset);
		ir_node  *new_ptr         = new_bd_sparc_Add_reg(dbgi, block, ptr, constant);
		ir_node  *new_load        = new_bd_sparc_Stf_s(dbgi, block, value, new_ptr, mem, load_store_mode, NULL, 0, true);
		sparc_load_store_attr_t *new_load_attr = get_sparc_load_store_attr(new_load);
yb9976's avatar
yb9976 committed
458
459
460
461
462

		new_load_attr->is_frame_entity = load_store_attr->is_frame_entity;
		new_load_attr->is_reg_reg      = load_store_attr->is_reg_reg;

		sched_add_before(node, new_load);
463
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
464
465
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
466
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
467
468
469
470
	}

}

471
472
473
474
475
476
static void peephole_be_IncSP(ir_node *node)
{
	node = be_peephole_IncSP_IncSP(node);
	if (!be_is_IncSP(node))
		return;

Matthias Braun's avatar
Matthias Braun committed
477
	ir_node *pred = be_get_IncSP_pred(node);
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
	if (is_sparc_Save(pred) && be_has_only_one_user(pred)) {
		int offset = -be_get_IncSP_offset(node);
		sparc_attr_t *attr = get_sparc_attr(pred);
		attr->immediate_value += offset;
		be_peephole_exchange(node, pred);
	}
}

static void peephole_sparc_FrameAddr(ir_node *node)
{
	/* the peephole code currently doesn't allow this since it changes
	 * the register. Find out why and how to workaround this... */
	(void) node;
}

493
494
495
/* output must not be local, or out reg. Since the destination of the restore
 * is the rotated register-file where only the old in-registers are still
 * visible (as out-registers) */
496
497
498
499
500
501
502
static bool is_restorezeroopt_reg(const arch_register_t *reg)
{
	unsigned index = reg->global_index;
	return (index >= REG_G0 && index <= REG_G7)
	    || (index >= REG_I0 && index <= REG_I7);
}

503
static void replace_with_restore_reg(ir_node *node, ir_node *replaced,
yb9976's avatar
yb9976 committed
504
                                     ir_node *op0, ir_node *op1)
505
506
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
507
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
508
509
510
	ir_node  *fp       = get_irn_n(node, n_sparc_RestoreZero_frame_pointer);
	ir_node  *block    = get_nodes_block(node);
	ir_mode  *mode     = get_irn_mode(node);
511
512
	ir_node  *new_node = new_bd_sparc_Restore_reg(dbgi, block, stack_in, fp,
	                                              op0, op1);
513
514
515
516
517
518
519
520
521
522
523
524
525
	ir_node  *stack    = new_r_Proj(new_node, mode, pn_sparc_Restore_stack);
	ir_node  *res      = new_r_Proj(new_node, mode, pn_sparc_Restore_res);
	const arch_register_t *reg = arch_get_irn_register(replaced);
	const arch_register_t *sp  = &sparc_registers[REG_SP];
	arch_set_irn_register_out(new_node, pn_sparc_Restore_stack, sp);
	arch_set_irn_register_out(new_node, pn_sparc_Restore_res, reg);

	sched_add_before(node, new_node);
	be_peephole_exchange(node, stack);
	be_peephole_exchange(replaced, res);
}

static void replace_with_restore_imm(ir_node *node, ir_node *replaced,
yb9976's avatar
yb9976 committed
526
527
                                     ir_node *op, ir_entity *imm_entity,
                                     int32_t immediate)
528
529
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
530
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
531
532
533
	ir_node  *fp       = get_irn_n(node, n_sparc_RestoreZero_frame_pointer);
	ir_node  *block    = get_nodes_block(node);
	ir_mode  *mode     = get_irn_mode(node);
534
535
	ir_node  *new_node = new_bd_sparc_Restore_imm(dbgi, block, stack_in, fp,
	                                              op, imm_entity, immediate);
536
537
538
539
540
541
542
543
544
545
546
547
	ir_node  *stack    = new_r_Proj(new_node, mode, pn_sparc_Restore_stack);
	ir_node  *res      = new_r_Proj(new_node, mode, pn_sparc_Restore_res);
	const arch_register_t *reg = arch_get_irn_register(replaced);
	const arch_register_t *sp  = &sparc_registers[REG_SP];
	arch_set_irn_register_out(new_node, pn_sparc_Restore_stack, sp);
	arch_set_irn_register_out(new_node, pn_sparc_Restore_res, reg);

	sched_add_before(node, new_node);
	be_peephole_exchange(node, stack);
	be_peephole_exchange(replaced, res);
}

548
549
550
static void peephole_sparc_RestoreZero(ir_node *node)
{
	/* restore gives us a free "add" instruction, let's try to use that to fold
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
	 * an instruction in. We can do the following:
	 *
	 * - Copy values                  (g0 + reg)
	 * - Produce constants            (g0 + immediate)
	 * - Perform an add               (reg + reg)
	 * - Perform a sub with immediate (reg + (-immediate))
	 *
	 * Note: In an ideal world, this would not be a peephole optimization but
	 * already performed during code selection. Since about all foldable ops are
	 * arguments of the return node. However we have a hard time doing this
	 * since we construct epilogue code only after register allocation
	 * (and therefore after code selection).
	 */
	int n_tries = 10; /* limit our search */

566
	sched_foreach_reverse_before(node, schedpoint) {
567
568
569
570
571
572
573
		if (--n_tries == 0)
			break;

		if (arch_get_irn_n_outs(schedpoint) == 0)
			continue;

		if (!mode_is_data(get_irn_mode(schedpoint)))
574
575
			return;

576
		arch_register_t const *const reg = arch_get_irn_register(schedpoint);
577
578
579
		if (!is_restorezeroopt_reg(reg))
			continue;

580
		if (be_is_Copy(schedpoint) && be_can_move_down(heights, schedpoint, node)) {
Christoph Mallon's avatar
Christoph Mallon committed
581
			ir_node *const op = be_get_Copy_op(schedpoint);
582
583
584
585
			replace_with_restore_imm(node, schedpoint, op, NULL, 0);
		} else if (is_sparc_Or(schedpoint) &&
		           arch_get_irn_flags(schedpoint) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form) &&
		           arch_get_irn_register_in(schedpoint, 0) == &sparc_registers[REG_G0] &&
586
		           be_can_move_down(heights, schedpoint, node)) {
587
588
589
590
591
592
593
			/* it's a constant */
			const sparc_attr_t *attr      = get_sparc_attr_const(schedpoint);
			ir_entity          *entity    = attr->immediate_value_entity;
			int32_t             immediate = attr->immediate_value;
			ir_node            *g0        = get_irn_n(schedpoint, 0);
			replace_with_restore_imm(node, schedpoint, g0, entity, immediate);
		} else if (is_sparc_Add(schedpoint) &&
594
		           be_can_move_down(heights, schedpoint, node)) {
595
596
597
598
599
600
601
602
603
604
605
606
607
608
			if (arch_get_irn_flags(schedpoint) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form)) {
				ir_node            *op     = get_irn_n(schedpoint, 0);
				const sparc_attr_t *attr   = get_sparc_attr_const(schedpoint);
				ir_entity          *entity = attr->immediate_value_entity;
				int32_t             imm    = attr->immediate_value;
				replace_with_restore_imm(node, schedpoint, op, entity, imm);
			} else {
				ir_node *op0 = get_irn_n(schedpoint, 0);
				ir_node *op1 = get_irn_n(schedpoint, 1);
				replace_with_restore_reg(node, schedpoint, op0, op1);
			}
		} else if (is_sparc_Sub(schedpoint) &&
		           arch_get_irn_flags(schedpoint) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form) &&
		           arch_get_irn_register_in(schedpoint, 0) == &sparc_registers[REG_G0] &&
609
		           be_can_move_down(heights, schedpoint, node)) {
610
611
612
613
614
615
616
617
618
619
620
621
622
			/* it's a constant */
			const sparc_attr_t *attr   = get_sparc_attr_const(schedpoint);
			ir_entity          *entity = attr->immediate_value_entity;
			int32_t             imm    = attr->immediate_value;
			if (entity == NULL && sparc_is_value_imm_encodeable(-imm)) {
				ir_node *g0 = get_irn_n(schedpoint, 0);
				replace_with_restore_imm(node, schedpoint, g0, NULL, -imm);
			} else {
				continue;
			}
		}
		/* when we're here then we performed a folding and are done */
		return;
623
624
625
	}
}

626
static void finish_sparc_Return(ir_node *node)
627
{
628
	/* Ensure that the restore is directly before the return. */
629
	sched_foreach_reverse_before(node, restore) {
630
631
632
		if (is_sparc_Restore(restore) || is_sparc_RestoreZero(restore)) {
			sched_remove(restore);
			sched_add_before(node, restore);
633
			break;
634
		}
635
636
637
	}
}

638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
/**
 * Check whether the flags of the node are used.
 */
static bool has_flags_user(ir_node *node)
{
	foreach_out_edge(node, edge) {
		ir_node *src = get_edge_src_irn(edge);

		if (is_Proj(src) && get_Proj_proj(src) == pn_sparc_AddCC_flags)
			return true;
	}

	return false;
}

/*
 * Transform AddCC into Add if flags output is unused.
 */
static void peephole_sparc_AddCC(ir_node *node)
{
	if (has_flags_user(node))
		return;

	set_irn_op(node, op_sparc_Add);
	arch_set_irn_register_out(node, pn_sparc_AddCC_flags, NULL);
}

/*
 * Transform SubCC into Sub if flags output is unused.
 */
static void peephole_sparc_SubCC(ir_node *node)
{
	assert((int)pn_sparc_AddCC_flags == (int)pn_sparc_SubCC_flags);

	if (has_flags_user(node))
		return;

	set_irn_op(node, op_sparc_Sub);
	arch_set_irn_register_out(node, pn_sparc_SubCC_flags, NULL);
}

679
680
681
682
683
684
static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
{
	assert(op->ops.generic == NULL);
	op->ops.generic = (op_func) func;
}

685
686
687
688
689
static void sparc_collect_frame_entity_nodes(ir_node *node, void *data)
{
	be_fec_env_t  *env = (be_fec_env_t*)data;

	if (be_is_Reload(node) && be_get_frame_entity(node) == NULL) {
Matthias Braun's avatar
Matthias Braun committed
690
691
		ir_mode *mode  = get_irn_mode(node);
		unsigned align = get_mode_size_bytes(mode);
692
693
694
695
696
697
698
		be_node_needs_frame_entity(env, node, mode, align);
		return;
	}

	if (!is_sparc_Ld(node) && !is_sparc_Ldf(node))
		return;

Matthias Braun's avatar
Matthias Braun committed
699
700
701
	const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
	ir_entity *entity = attr->base.immediate_value_entity;
	ir_mode   *mode   = attr->load_store_mode;
702
703
704
705
	if (entity != NULL)
		return;
	if (!attr->is_frame_entity)
		return;
706
	if (arch_get_irn_flags(node) & sparc_arch_irn_flag_needs_64bit_spillslot)
707
		mode = mode_Lu;
Matthias Braun's avatar
Matthias Braun committed
708
	unsigned align = get_mode_size_bytes(mode);
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
	be_node_needs_frame_entity(env, node, mode, align);
}

static void sparc_set_frame_entity(ir_node *node, ir_entity *entity)
{
	if (is_be_node(node)) {
		be_node_set_frame_entity(node, entity);
	} else {
		/* we only say be_node_needs_frame_entity on nodes with load_store
		 * attributes, so this should be fine */
		sparc_load_store_attr_t *attr = get_sparc_load_store_attr(node);
		assert(attr->is_frame_entity);
		assert(attr->base.immediate_value_entity == NULL);
		attr->base.immediate_value_entity = entity;
	}
}

726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
/** returns true if the should_be_same constraints of a node must be
 * fulfilled */
static bool has_must_be_same(const ir_node *node)
{
	return is_sparc_Cas(node);
}

static void fix_constraints_walker(ir_node *block, void *env)
{
	(void)env;
	sched_foreach_safe(block, irn) {
		if (!has_must_be_same(irn))
			continue;
		assure_should_be_same_requirements(irn);
	}
}

Matthias Braun's avatar
Matthias Braun committed
743
void sparc_finish_graph(ir_graph *irg)
744
{
745
746
747
748
749
750
751
	be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
	bool               at_begin     = stack_layout->sp_relative ? true : false;
	be_fec_env_t      *fec_env      = be_new_frame_entity_coalescer(irg);

	irg_walk_graph(irg, NULL, sparc_collect_frame_entity_nodes, fec_env);
	be_assign_entities(fec_env, sparc_set_frame_entity, at_begin);
	be_free_frame_entity_coalescer(fec_env);
752
	sparc_adjust_stack_entity_offsets(irg);
753
754
755
756
757

	sparc_introduce_prolog_epilog(irg);

	/* fix stack entity offsets */
	be_abi_fix_stack_nodes(irg);
758
	sparc_fix_stack_bias(irg);
759

760
761
	heights = heights_new(irg);

762
	/* perform peephole optimizations */
Matthias Braun's avatar
Matthias Braun committed
763
	ir_clear_opcodes_generic_func();
764
765
	register_peephole_optimisation(op_be_IncSP,        peephole_be_IncSP);
	register_peephole_optimisation(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
766
767
	register_peephole_optimisation(op_sparc_RestoreZero,
	                               peephole_sparc_RestoreZero);
768
	register_peephole_optimisation(op_sparc_Ldf, split_sparc_ldf);
769
770
	register_peephole_optimisation(op_sparc_AddCC, peephole_sparc_AddCC);
	register_peephole_optimisation(op_sparc_SubCC, peephole_sparc_SubCC);
771
772
	be_peephole_opt(irg);

773
	/* perform legalizations (mostly fix nodes with too big immediates) */
Matthias Braun's avatar
Matthias Braun committed
774
	ir_clear_opcodes_generic_func();
775
776
	register_peephole_optimisation(op_be_IncSP,        finish_be_IncSP);
	register_peephole_optimisation(op_sparc_FrameAddr, finish_sparc_FrameAddr);
yb9976's avatar
yb9976 committed
777
778
	register_peephole_optimisation(op_sparc_Ld,        finish_sparc_Ld);
	register_peephole_optimisation(op_sparc_Ldf,       finish_sparc_Ldf);
779
	register_peephole_optimisation(op_sparc_Return,    finish_sparc_Return);
780
	register_peephole_optimisation(op_sparc_Save,      finish_sparc_Save);
yb9976's avatar
yb9976 committed
781
782
	register_peephole_optimisation(op_sparc_St,        finish_sparc_St);
	register_peephole_optimisation(op_sparc_Stf,       finish_sparc_Stf);
783
	be_peephole_opt(irg);
784

785
786
	heights_free(heights);

787
788
	irg_block_walk_graph(irg, NULL, fix_constraints_walker, NULL);

789
	be_remove_dead_nodes_from_schedule(irg);
790
}