sparc_finish.c 28.2 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
79
80
81
82
83
 * 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;
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
116
117
118
119
120
121
			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");
	}
}
122

123
124
static ir_heights_t *heights;

125
126
127
128
129
130
131
132
133
134
135
136
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
137
		MEMCPY(ins, get_irn_in(node), arity);
138
139
		kill_node(node);

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

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

150
151
152
153
	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);
154
	if (!layout->sp_relative) {
155
156
157
158
		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);
159
160
		sched_add_before(ret, restore);
		arch_set_irn_register(restore, sp_reg);
161
		set_irn_n(ret, n_sparc_Return_sp, restore);
162
163
		kill_unused_stacknodes(sp);
	} else {
164
165
166
		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);
167
		set_irn_n(ret, n_sparc_Return_sp, incsp);
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
		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 */
184
	foreach_irn_in(get_irg_end_block(irg), i, ret) {
Matthias Braun's avatar
Matthias Braun committed
185
186
		assert(is_sparc_Return(ret));
		introduce_epilog(ret);
187
188
189
190
191
192
	}

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

	if (!layout->sp_relative) {
193
		ir_node *const save = new_bd_sparc_Save_imm(NULL, block, initial_sp, NULL, -(SPARC_MIN_STACKSIZE + frame_size));
194
195
196
197
		arch_set_irn_register(save, sp_reg);
		sched_add_after(schedpoint, save);
		schedpoint = save;

198
		edges_reroute_except(initial_sp, save, save);
199

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

217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/**
 * 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;
}

241
242
243
244
245
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
246
	if (!sparc_is_value_imm_encodeable(offset)) {
247
248
249
250
251
252
253
254
255
256
257
258
259
		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);
260
261
262
263
	}
}

/**
264
 * SPARC immediates are limited. Split IncSP with bigger immediates if
265
266
267
268
 * necessary.
 */
static void finish_be_IncSP(ir_node *node)
{
269
270
271
	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
272
273
274
275
276
277
	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);
278
279
280
281

		sched_add_before(node, sub);
		arch_set_irn_register(sub, &sparc_registers[REG_SP]);
		be_peephole_exchange(node, sub);
282
283
284
285
	}
}

/**
yb9976's avatar
yb9976 committed
286
287
288
 * Adjust sp-relative offsets.
 *
 * Split into multiple instructions if offset exceeds SPARC immediate range.
289
290
291
292
293
294
 */
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
295
	if (!sparc_is_value_imm_encodeable(offset)) {
296
297
298
299
300
301
		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);
302

303
		sched_add_before(node, new_frameaddr);
304
		arch_set_irn_register(new_frameaddr, reg);
305
		be_peephole_exchange(node, new_frameaddr);
306
307
308
	}
}

yb9976's avatar
yb9976 committed
309
310
311
312
313
314
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
315
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
316
317
		return;

Matthias Braun's avatar
Matthias Braun committed
318
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
319
320
321
322
323
324
325
326
327
328
329
330
331
		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);
332
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
333
334
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
335
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
336
337
338
339
	}

}

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
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
370
371
372
373
374
375
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
376
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
377
378
		return;

Matthias Braun's avatar
Matthias Braun committed
379
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
		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);
394
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
395
396
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
397
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
398
399
400
401
402
403
404
405
406
407
	}

}

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
408
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
409
410
		return;

Matthias Braun's avatar
Matthias Braun committed
411
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
412
413
414
415
416
417
418
419
420
421
422
423
424
425
		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);
426
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
427
428
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
429
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
430
431
432
433
434
435
436
437
438
439
	}

}

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
440
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
441
442
		return;

Matthias Braun's avatar
Matthias Braun committed
443
444
445
446
447
448
449
450
451
452
453
	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
454
455
456
457
458

		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);
459
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
460
461
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
462
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
463
464
465
466
	}

}

467
468
469
470
471
472
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
473
	ir_node *pred = be_get_IncSP_pred(node);
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
	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;
}

489
490
491
/* 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) */
492
493
494
495
496
497
498
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);
}

499
static void replace_with_restore_reg(ir_node *node, ir_node *replaced,
yb9976's avatar
yb9976 committed
500
                                     ir_node *op0, ir_node *op1)
501
502
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
503
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
504
505
506
	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);
507
508
	ir_node  *new_node = new_bd_sparc_Restore_reg(dbgi, block, stack_in, fp,
	                                              op0, op1);
509
510
511
512
513
514
515
516
517
518
519
520
521
	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
522
523
                                     ir_node *op, ir_entity *imm_entity,
                                     int32_t immediate)
524
525
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
526
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
527
528
529
	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);
530
531
	ir_node  *new_node = new_bd_sparc_Restore_imm(dbgi, block, stack_in, fp,
	                                              op, imm_entity, immediate);
532
533
534
535
536
537
538
539
540
541
542
543
	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);
}

544
545
546
static void peephole_sparc_RestoreZero(ir_node *node)
{
	/* restore gives us a free "add" instruction, let's try to use that to fold
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
	 * 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 */

562
	sched_foreach_reverse_before(node, schedpoint) {
563
564
565
566
567
568
569
		if (--n_tries == 0)
			break;

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

		if (!mode_is_data(get_irn_mode(schedpoint)))
570
571
			return;

572
		arch_register_t const *const reg = arch_get_irn_register(schedpoint);
573
574
575
		if (!is_restorezeroopt_reg(reg))
			continue;

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

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

634
635
636
637
638
639
640
641
/**
 * 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);

642
		if (is_Proj(src) && get_Proj_num(src) == pn_sparc_AddCC_flags)
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
			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);
}

675
static void register_peephole_optimization(ir_op *op, peephole_opt_func func)
676
677
678
679
680
{
	assert(op->ops.generic == NULL);
	op->ops.generic = (op_func) func;
}

681
682
683
684
685
static bool is_frame_load(const ir_node *node)
{
	return is_sparc_Ld(node) || is_sparc_Ldf(node);
}

686
687
static void sparc_collect_frame_entity_nodes(ir_node *node, void *data)
{
688
689
690
691
692
693
694
695
696
697
698
699
700
	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;
	}
701

702
	if (!is_frame_load(node))
703
704
		return;

Matthias Braun's avatar
Matthias Braun committed
705
706
707
	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;
708
709
710
711
	if (entity != NULL)
		return;
	if (!attr->is_frame_entity)
		return;
712
	if (arch_get_irn_flags(node) & sparc_arch_irn_flag_needs_64bit_spillslot)
713
		mode = mode_Lu;
714
715
	const ir_type *type = get_type_for_mode(mode);
	be_load_needs_frame_entity(env, node, type);
716
717
}

718
719
static void sparc_set_frame_entity(ir_node *node, ir_entity *entity,
                                   const ir_type *type)
720
{
721
	(void)type;
722
723
724
725
726
727
	/* 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;
728
729
}

730
731
732
733
/** returns true if the should_be_same constraints of a node must be
 * fulfilled */
static bool has_must_be_same(const ir_node *node)
{
734
	return is_sparc_Cas(node) || is_sparc_ASM(node);
735
736
737
738
739
740
741
742
743
744
745
746
}

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
747
void sparc_finish_graph(ir_graph *irg)
748
{
749
	be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
750
	bool               at_begin     = stack_layout->sp_relative;
751
752
753
	be_fec_env_t      *fec_env      = be_new_frame_entity_coalescer(irg);

	irg_walk_graph(irg, NULL, sparc_collect_frame_entity_nodes, fec_env);
754
	be_assign_entities(fec_env, sparc_set_frame_entity, at_begin);
755
	be_free_frame_entity_coalescer(fec_env);
756
	sparc_adjust_stack_entity_offsets(irg);
757
758
759
760
761

	sparc_introduce_prolog_epilog(irg);

	/* fix stack entity offsets */
	be_abi_fix_stack_nodes(irg);
762
	sparc_fix_stack_bias(irg);
763

764
765
	heights = heights_new(irg);

766
	/* perform peephole optimizations */
Matthias Braun's avatar
Matthias Braun committed
767
	ir_clear_opcodes_generic_func();
768
769
770
	register_peephole_optimization(op_be_IncSP,        peephole_be_IncSP);
	register_peephole_optimization(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
	register_peephole_optimization(op_sparc_RestoreZero,
771
	                               peephole_sparc_RestoreZero);
772
773
774
	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);
775
776
	be_peephole_opt(irg);

777
	/* perform legalizations (mostly fix nodes with too big immediates) */
Matthias Braun's avatar
Matthias Braun committed
778
	ir_clear_opcodes_generic_func();
779
780
781
782
783
784
785
786
	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);
787
	be_peephole_opt(irg);
788

789
790
	heights_free(heights);

791
792
	irg_block_walk_graph(irg, NULL, fix_constraints_walker, NULL);

793
	be_remove_dead_nodes_from_schedule(irg);
794
}