sparc_finish.c 27.9 KB
Newer Older
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
4
5
6
7
 */

/**
 * @file
yb9976's avatar
yb9976 committed
8
 * @brief    Peephole optimization and legalization of a SPARC function
9
10
 * @author   Matthias Braun
 *
yb9976's avatar
yb9976 committed
11
 * A note on SPARC stack pointer (sp) behavior:
12
 * The ABI expects SPARC_MIN_STACKSIZE bytes to be available at the
yb9976's avatar
yb9976 committed
13
 * stack pointer. This space will be used to spill register windows,
14
15
16
17
 * 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
yb9976's avatar
yb9976 committed
18
 * stack frame. Instead you should rather imagine the space as always being the
19
20
21
22
23
24
25
26
27
 * 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 "bearch_sparc_t.h"
#include "gen_sparc_regalloc_if.h"
#include "sparc_new_nodes.h"
28
#include "sparc_transform.h"
29
30
#include "irprog.h"
#include "irgmod.h"
31
#include "ircons.h"
32
#include "irgwalk.h"
33
#include "heights.h"
34
#include "beirg.h"
35
36
37
38
39
#include "bepeephole.h"
#include "benode.h"
#include "besched.h"
#include "bespillslots.h"
#include "bestack.h"
40
#include "beutil.h"
Matthias Braun's avatar
Matthias Braun committed
41
#include "panic.h"
Christoph Mallon's avatar
Christoph Mallon committed
42
#include "util.h"
43
44
45
46
47
48
49
50
51
52
53
54

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");
}

/**
yb9976's avatar
yb9976 committed
55
 * Insert copies for all SPARC nodes where the should_be_same requirement
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 * 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;
79
		assert(in_reg->cls == out_reg->cls);
80
81
82
83

		/* check if any other input operands uses the out register */
		ir_node *uses_out_reg     = NULL;
		int      uses_out_reg_pos = -1;
84
		foreach_irn_in(node, i2, in) {
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
			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;
		}

116
		panic("unresolved should_be_same constraint");
117
118
	}
}
119

120
121
static ir_heights_t *heights;

122
123
124
125
126
127
128
129
130
131
132
133
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);
Christoph Mallon's avatar
Christoph Mallon committed
134
		MEMCPY(ins, get_irn_in(node), arity);
135
136
		kill_node(node);

Matthias Braun's avatar
Matthias Braun committed
137
		for (int i = 0; i < arity; ++i)
138
139
140
141
142
143
			kill_unused_stacknodes(ins[i]);
	}
}

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

147
148
149
150
	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);
151
	if (!layout->sp_relative) {
152
		arch_register_t const *const fp_reg  = &sparc_registers[REG_FP];
153
154
155
		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);
156
157
		sched_add_before(ret, restore);
		arch_set_irn_register(restore, sp_reg);
158
		set_irn_n(ret, n_sparc_Return_sp, restore);
159
160
		kill_unused_stacknodes(sp);
	} else {
161
162
163
		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);
164
		set_irn_n(ret, n_sparc_Return_sp, incsp);
165
166
167
168
		sched_add_before(ret, incsp);
	}
}

169
static void sparc_introduce_prolog_epilog(ir_graph *irg)
170
171
172
173
174
175
176
177
178
179
{
	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_type               *frame_type = get_irg_frame_type(irg);
	unsigned               frame_size = get_type_size_bytes(frame_type);

	/* introduce epilog for every return node */
180
	foreach_irn_in(get_irg_end_block(irg), i, ret) {
Matthias Braun's avatar
Matthias Braun committed
181
182
		assert(is_sparc_Return(ret));
		introduce_epilog(ret);
183
184
185
	}

	if (!layout->sp_relative) {
186
		ir_node *const save = new_bd_sparc_Save_imm(NULL, block, initial_sp, NULL, -(SPARC_MIN_STACKSIZE + frame_size));
187
		arch_set_irn_register(save, sp_reg);
188
		sched_add_after(start, save);
189

190
		edges_reroute_except(initial_sp, save, save);
191

192
		/* we still need the Save even if noone is explicitely using the
193
		 * value. (TODO: this isn't 100% correct yet, something at the end of
194
		 * the function should hold the Save, even if we use a restore
195
196
		 * which just overrides it instead of using the value)
		 */
197
		be_keep_if_unused(save);
198
	} else {
199
200
		ir_node *const incsp = be_new_IncSP(sp_reg, block, initial_sp, frame_size, 0);
		edges_reroute_except(initial_sp, incsp, incsp);
201
		sched_add_after(start, incsp);
202
203
204
	}
}

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/**
 * 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;
}

229
230
231
232
233
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
234
	if (!sparc_is_value_imm_encodeable(offset)) {
235
236
237
238
239
240
241
242
243
244
245
246
247
		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);
248
249
250
251
	}
}

/**
252
 * SPARC immediates are limited. Split IncSP with bigger immediates if
253
254
255
256
 * necessary.
 */
static void finish_be_IncSP(ir_node *node)
{
257
258
259
	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
260
261
262
263
264
265
	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);
266
267
268
269

		sched_add_before(node, sub);
		arch_set_irn_register(sub, &sparc_registers[REG_SP]);
		be_peephole_exchange(node, sub);
270
271
272
273
	}
}

/**
yb9976's avatar
yb9976 committed
274
275
276
 * Adjust sp-relative offsets.
 *
 * Split into multiple instructions if offset exceeds SPARC immediate range.
277
278
279
280
281
282
 */
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
283
	if (!sparc_is_value_imm_encodeable(offset)) {
284
285
286
287
288
289
		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);
290

291
		sched_add_before(node, new_frameaddr);
292
		arch_set_irn_register(new_frameaddr, reg);
293
		be_peephole_exchange(node, new_frameaddr);
294
295
296
	}
}

yb9976's avatar
yb9976 committed
297
298
299
300
301
302
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
303
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
304
305
		return;

Matthias Braun's avatar
Matthias Braun committed
306
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
307
308
309
310
311
312
313
314
315
316
317
318
319
		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);
320
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
321
322
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
323
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
324
325
326
327
	}

}

328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
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
358
359
360
361
362
363
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
364
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
365
366
		return;

Matthias Braun's avatar
Matthias Braun committed
367
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
368
369
370
371
372
373
374
375
376
377
378
379
380
381
		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);
382
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
383
384
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
385
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
386
387
388
389
390
391
392
393
394
395
	}

}

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
396
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
397
398
		return;

Matthias Braun's avatar
Matthias Braun committed
399
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
		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);
414
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
415
416
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
417
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
418
419
420
421
422
423
424
425
426
427
	}

}

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
428
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
429
430
		return;

Matthias Braun's avatar
Matthias Braun committed
431
432
433
434
435
436
437
438
439
440
441
	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
442
443
444
445
446

		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);
447
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
448
449
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
450
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
451
452
453
454
	}

}

455
456
457
458
459
460
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
461
	ir_node *pred = be_get_IncSP_pred(node);
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
	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;
}

477
478
479
/* 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) */
480
481
482
483
484
485
486
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);
}

487
static void replace_with_restore_reg(ir_node *node, ir_node *replaced,
yb9976's avatar
yb9976 committed
488
                                     ir_node *op0, ir_node *op1)
489
490
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
491
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
492
493
494
	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);
495
496
	ir_node  *new_node = new_bd_sparc_Restore_reg(dbgi, block, stack_in, fp,
	                                              op0, op1);
497
498
499
500
501
502
503
504
505
506
507
508
509
	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
510
511
                                     ir_node *op, ir_entity *imm_entity,
                                     int32_t immediate)
512
513
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
514
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
515
516
517
	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);
518
519
	ir_node  *new_node = new_bd_sparc_Restore_imm(dbgi, block, stack_in, fp,
	                                              op, imm_entity, immediate);
520
521
522
523
524
525
526
527
528
529
530
531
	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);
}

532
533
534
535
536
static bool can_move_down(const ir_node *schedpoint, const ir_node *node)
{
	return be_can_move_down(heights, schedpoint, node, sparc_get_frame_entity);
}

537
538
539
static void peephole_sparc_RestoreZero(ir_node *node)
{
	/* restore gives us a free "add" instruction, let's try to use that to fold
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
	 * 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 */

555
	sched_foreach_reverse_before(node, schedpoint) {
556
557
558
559
560
561
562
		if (--n_tries == 0)
			break;

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

		if (!mode_is_data(get_irn_mode(schedpoint)))
563
564
			return;

565
		arch_register_t const *const reg = arch_get_irn_register(schedpoint);
566
567
568
		if (!is_restorezeroopt_reg(reg))
			continue;

569
		if (be_is_Copy(schedpoint) && can_move_down(schedpoint, node)) {
Christoph Mallon's avatar
Christoph Mallon committed
570
			ir_node *const op = be_get_Copy_op(schedpoint);
571
572
573
574
			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] &&
575
		           can_move_down(schedpoint, node)) {
576
577
578
579
580
581
582
			/* 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) &&
583
		           can_move_down(schedpoint, node)) {
584
585
586
587
588
589
590
591
592
593
594
595
596
597
			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] &&
598
		           can_move_down(schedpoint, node)) {
599
600
601
602
603
604
605
606
607
608
609
610
611
			/* 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;
612
613
614
	}
}

615
static void finish_sparc_Return(ir_node *node)
616
{
617
	/* Ensure that the restore is directly before the return. */
618
	sched_foreach_reverse_before(node, restore) {
619
620
621
		if (is_sparc_Restore(restore) || is_sparc_RestoreZero(restore)) {
			sched_remove(restore);
			sched_add_before(node, restore);
622
			break;
623
		}
624
625
626
	}
}

627
628
629
630
631
/**
 * Check whether the flags of the node are used.
 */
static bool has_flags_user(ir_node *node)
{
Christoph Mallon's avatar
Christoph Mallon committed
632
	return get_Proj_for_pn(node, pn_sparc_AddCC_flags) != NULL;
633
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
}

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

661
static void register_peephole_optimization(ir_op *op, peephole_opt_func func)
662
663
664
665
666
{
	assert(op->ops.generic == NULL);
	op->ops.generic = (op_func) func;
}

667
668
669
670
671
static bool is_frame_load(const ir_node *node)
{
	return is_sparc_Ld(node) || is_sparc_Ldf(node);
}

672
673
static void sparc_collect_frame_entity_nodes(ir_node *node, void *data)
{
674
675
676
677
678
679
680
681
682
683
684
685
686
	be_fec_env_t *env = (be_fec_env_t*)data;

	/* Disable coalescing for "returns twice" calls: In case of setjmp/longjmp
	 * our control flow graph isn't completely correct: There are no backedges
	 * from longjmp to the setjmp => coalescing would produce wrong results. */
	if (is_sparc_Call(node)) {
		const sparc_call_attr_t   *attrs = get_sparc_call_attr_const(node);
		const ir_type             *type  = attrs->call_type;
		mtp_additional_properties  mtp   = get_method_additional_properties(type);
		if (mtp & mtp_property_returns_twice)
			be_forbid_coalescing(env);
		return;
	}
687

688
	if (!is_frame_load(node))
689
690
		return;

Matthias Braun's avatar
Matthias Braun committed
691
692
693
	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;
694
695
696
697
	if (entity != NULL)
		return;
	if (!attr->is_frame_entity)
		return;
698
	if (arch_get_irn_flags(node) & sparc_arch_irn_flag_needs_64bit_spillslot)
699
		mode = mode_Lu;
700
701
	const ir_type *type = get_type_for_mode(mode);
	be_load_needs_frame_entity(env, node, type);
702
703
}

704
705
static void sparc_set_frame_entity(ir_node *node, ir_entity *entity,
                                   const ir_type *type)
706
{
707
	(void)type;
708
709
710
711
712
713
	/* 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;
714
715
}

716
717
718
719
/** returns true if the should_be_same constraints of a node must be
 * fulfilled */
static bool has_must_be_same(const ir_node *node)
{
720
	return is_sparc_Cas(node) || is_sparc_ASM(node);
721
722
723
724
725
726
727
728
729
730
731
732
}

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
733
void sparc_finish_graph(ir_graph *irg)
734
{
735
	be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
736
	bool               at_begin     = stack_layout->sp_relative;
737
738
739
	be_fec_env_t      *fec_env      = be_new_frame_entity_coalescer(irg);

	irg_walk_graph(irg, NULL, sparc_collect_frame_entity_nodes, fec_env);
740
	be_assign_entities(fec_env, sparc_set_frame_entity, at_begin);
741
	be_free_frame_entity_coalescer(fec_env);
742
	sparc_adjust_stack_entity_offsets(irg);
743
744
745
746

	sparc_introduce_prolog_epilog(irg);

	/* fix stack entity offsets */
747
	be_fix_stack_nodes(irg, &sparc_registers[REG_SP]);
748
	sparc_fix_stack_bias(irg);
749

750
751
	heights = heights_new(irg);

752
	/* perform peephole optimizations */
Matthias Braun's avatar
Matthias Braun committed
753
	ir_clear_opcodes_generic_func();
754
755
756
	register_peephole_optimization(op_be_IncSP,        peephole_be_IncSP);
	register_peephole_optimization(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
	register_peephole_optimization(op_sparc_RestoreZero,
757
	                               peephole_sparc_RestoreZero);
758
759
760
	register_peephole_optimization(op_sparc_Ldf, split_sparc_ldf);
	register_peephole_optimization(op_sparc_AddCC, peephole_sparc_AddCC);
	register_peephole_optimization(op_sparc_SubCC, peephole_sparc_SubCC);
761
762
	be_peephole_opt(irg);

763
	/* perform legalizations (mostly fix nodes with too big immediates) */
Matthias Braun's avatar
Matthias Braun committed
764
	ir_clear_opcodes_generic_func();
765
766
767
768
769
770
771
772
	register_peephole_optimization(op_be_IncSP,        finish_be_IncSP);
	register_peephole_optimization(op_sparc_FrameAddr, finish_sparc_FrameAddr);
	register_peephole_optimization(op_sparc_Ld,        finish_sparc_Ld);
	register_peephole_optimization(op_sparc_Ldf,       finish_sparc_Ldf);
	register_peephole_optimization(op_sparc_Return,    finish_sparc_Return);
	register_peephole_optimization(op_sparc_Save,      finish_sparc_Save);
	register_peephole_optimization(op_sparc_St,        finish_sparc_St);
	register_peephole_optimization(op_sparc_Stf,       finish_sparc_Stf);
773
	be_peephole_opt(irg);
774

775
776
	heights_free(heights);

777
778
	irg_block_walk_graph(irg, NULL, fix_constraints_walker, NULL);

779
	be_remove_dead_nodes_from_schedule(irg);
780
}