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"
42
43
44
45
46
47
48
49
50
51
52
53

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
54
 * Insert copies for all SPARC nodes where the should_be_same requirement
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
 * 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;
83
		foreach_irn_in(node, i2, in) {
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
			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");
	}
}
121

122
123
static ir_heights_t *heights;

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
139
		for (int i = 0; i < arity; ++i)
140
141
142
143
144
145
			kill_unused_stacknodes(ins[i]);
	}
}

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

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

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

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

197
		edges_reroute_except(initial_sp, save, save);
198

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

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

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

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

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

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

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

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

Matthias Braun's avatar
Matthias Braun committed
317
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
318
319
320
321
322
323
324
325
326
327
328
329
330
		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);
331
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
332
333
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
334
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
335
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
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
369
370
371
372
373
374
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
375
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
376
377
		return;

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

}

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

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

}

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

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	sparc_introduce_prolog_epilog(irg);

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

763
764
	heights = heights_new(irg);

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

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

788
789
	heights_free(heights);

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

792
	be_remove_dead_nodes_from_schedule(irg);
793
}