sparc_finish.c 25.8 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 "iredges_t.h"
33
#include "irgwalk.h"
34
#include "heights.h"
35
#include "beirg.h"
36
37
38
39
40
#include "bepeephole.h"
#include "benode.h"
#include "besched.h"
#include "bespillslots.h"
#include "bestack.h"
41
#include "beutil.h"
Matthias Braun's avatar
Matthias Braun committed
42
#include "panic.h"
Christoph Mallon's avatar
Christoph Mallon committed
43
#include "util.h"
44
45
46

static int get_first_same(const arch_register_req_t *req)
{
47
	const unsigned other = req->should_be_same;
48
49
50
51
52
53
54
55
	for (int i = 0; i < 32; ++i) {
		if (other & (1U << i))
			return i;
	}
	panic("same position not found");
}

/**
yb9976's avatar
yb9976 committed
56
 * Insert copies for all SPARC nodes where the should_be_same requirement
57
58
59
60
61
62
63
64
 * is not fulfilled.
 * Transform Sub into Neg -- Add if IN2 == OUT
 */
static void assure_should_be_same_requirements(ir_node *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);
65
		if (req->should_be_same == 0)
66
67
68
69
70
71
72
73
74
75
76
77
			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;
78
		assert(in_reg->cls == out_reg->cls);
79
80
81
82

		/* 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
			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) {
102
			ir_node *const copy = be_new_Copy_before_reg(in_node, node, out_reg);
103
104
105
106
107
			/* set copy as in */
			set_irn_n(node, same_pos, copy);
			continue;
		}

108
		panic("unresolved should_be_same constraint");
109
110
	}
}
111

112
113
static ir_heights_t *heights;

114
115
116
117
118
119
120
121
122
123
124
125
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
126
		MEMCPY(ins, get_irn_in(node), arity);
127
128
		kill_node(node);

Matthias Braun's avatar
Matthias Braun committed
129
		for (int i = 0; i < arity; ++i)
130
131
132
133
			kill_unused_stacknodes(ins[i]);
	}
}

134
static void introduce_epilog(ir_node *ret, bool omit_fp)
135
{
136
	arch_register_t const *const sp_reg = &sparc_registers[REG_SP];
137
	assert(arch_get_irn_register_req_in(ret, n_sparc_Return_sp) == sp_reg->single_req);
138

139
140
141
142
	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);
	if (!omit_fp) {
143
		arch_register_t const *const fp_reg  = &sparc_registers[REG_FP];
Christoph Mallon's avatar
Christoph Mallon committed
144
145
		ir_node               *const fp      = be_get_Start_proj(irg, fp_reg);
		ir_node               *const new_sp  = be_get_Start_proj(irg, sp_reg);
146
		ir_node               *const restore = new_bd_sparc_RestoreZero(NULL, block, new_sp, fp);
147
148
		sched_add_before(ret, restore);
		arch_set_irn_register(restore, sp_reg);
149
		set_irn_n(ret, n_sparc_Return_sp, restore);
150
151
		kill_unused_stacknodes(sp);
	} else {
152
		ir_type *const frame_type = get_irg_frame_type(irg);
153
		unsigned const frame_size = get_type_size(frame_type);
154
		ir_node *const incsp      = be_new_IncSP(sp_reg, block, sp, -frame_size, 0);
155
		set_irn_n(ret, n_sparc_Return_sp, incsp);
156
157
158
159
		sched_add_before(ret, incsp);
	}
}

160
static void sparc_introduce_prolog_epilog(ir_graph *irg, bool omit_fp)
161
162
163
164
{
	const arch_register_t *sp_reg     = &sparc_registers[REG_SP];
	ir_node               *start      = get_irg_start(irg);
	ir_node               *block      = get_nodes_block(start);
Christoph Mallon's avatar
Christoph Mallon committed
165
	ir_node               *initial_sp = be_get_Start_proj(irg, sp_reg);
166
	ir_type               *frame_type = get_irg_frame_type(irg);
167
	unsigned               frame_size = get_type_size(frame_type);
168
169

	/* introduce epilog for every return node */
170
	foreach_irn_in(get_irg_end_block(irg), i, ret) {
Matthias Braun's avatar
Matthias Braun committed
171
		assert(is_sparc_Return(ret));
172
		introduce_epilog(ret, omit_fp);
173
174
	}

175
	if (!omit_fp) {
176
		ir_node *const save = new_bd_sparc_Save_imm(NULL, block, initial_sp, NULL, -(SPARC_MIN_STACKSIZE + frame_size));
177
		arch_set_irn_register(save, sp_reg);
178
		sched_add_after(start, save);
179

180
		edges_reroute_except(initial_sp, save, save);
181

182
		/* we still need the Save even if noone is explicitely using the
183
		 * value. (TODO: this isn't 100% correct yet, something at the end of
184
		 * the function should hold the Save, even if we use a restore
185
186
		 * which just overrides it instead of using the value)
		 */
187
		be_keep_if_unused(save);
188
	} else {
189
190
		ir_node *const incsp = be_new_IncSP(sp_reg, block, initial_sp, frame_size, 0);
		edges_reroute_except(initial_sp, incsp, incsp);
191
		sched_add_after(start, incsp);
192
193
194
	}
}

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/**
 * 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;
}

219
220
221
222
223
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
224
	if (!sparc_is_value_imm_encodeable(offset)) {
225
226
227
228
229
230
231
232
233
234
235
		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);

		arch_set_irn_register(new_save, reg);
236
		be_peephole_replace(node, new_save);
237
238
239
240
	}
}

/**
241
 * SPARC immediates are limited. Split IncSP with bigger immediates if
242
243
244
245
 * necessary.
 */
static void finish_be_IncSP(ir_node *node)
{
246
247
248
	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
249
250
251
252
253
254
	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);
255
256

		arch_set_irn_register(sub, &sparc_registers[REG_SP]);
257
		be_peephole_replace(node, sub);
258
259
260
261
	}
}

/**
yb9976's avatar
yb9976 committed
262
263
264
 * Adjust sp-relative offsets.
 *
 * Split into multiple instructions if offset exceeds SPARC immediate range.
265
266
267
268
269
270
 */
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
271
	if (!sparc_is_value_imm_encodeable(offset)) {
272
273
274
275
276
277
		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);
278
279

		arch_set_irn_register(new_frameaddr, reg);
280
		be_peephole_replace(node, new_frameaddr);
281
282
283
	}
}

284
285
286
287
288
289
290
291
292
static void finish_load_store(ir_node *const old, ir_node *const nw, sparc_load_store_attr_t const *const ldst_attr)
{
	sparc_load_store_attr_t *const new_ldst_attr = get_sparc_load_store_attr(nw);
	new_ldst_attr->is_frame_entity = ldst_attr->is_frame_entity;
	new_ldst_attr->is_reg_reg      = ldst_attr->is_reg_reg;

	be_foreach_out(old, i) {
		arch_set_irn_register_out(nw, i, arch_get_irn_register_out(old, i));
	}
293
	be_peephole_replace(old, nw);
294
295
}

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

Matthias Braun's avatar
Matthias Braun committed
305
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
306
307
308
309
310
311
312
		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);
313
		finish_load_store(node, new_load, load_store_attr);
yb9976's avatar
yb9976 committed
314
315
316
	}
}

317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
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);
332
		ir_node  *const new_mem = be_new_Proj(new_load, pn_sparc_Ldf_M);
333
334
335
336
337
338
339
340
341
342
343
344
345
346

		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
347
348
349
350
351
352
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
353
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
354
355
		return;

Matthias Braun's avatar
Matthias Braun committed
356
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
357
358
359
360
361
362
363
364
		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);
365
		finish_load_store(node, new_load, load_store_attr);
yb9976's avatar
yb9976 committed
366
367
368
369
370
371
372
373
374
	}
}

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
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
		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);
387
		finish_load_store(node, new_load, load_store_attr);
yb9976's avatar
yb9976 committed
388
389
390
391
392
393
394
395
396
	}
}

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

Matthias Braun's avatar
Matthias Braun committed
400
401
402
403
404
405
406
407
408
409
	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);
410
		finish_load_store(node, new_load, load_store_attr);
yb9976's avatar
yb9976 committed
411
412
413
	}
}

414
415
static void peephole_be_IncSP(ir_node *node)
{
416
	if (be_peephole_IncSP_IncSP(node))
417
418
		return;

Matthias Braun's avatar
Matthias Braun committed
419
	ir_node *pred = be_get_IncSP_pred(node);
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
	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;
}

435
436
437
/* 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) */
438
439
440
441
442
443
444
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);
}

445
446
static void replace_with_restore(ir_node *const restore, ir_node *const node, ir_node *const replaced)
{
447
	sched_add_before(node, restore);
448

449
450
451
	arch_register_t const *const sp    = &sparc_registers[REG_SP];
	ir_node               *const stack = be_new_Proj_reg(restore, pn_sparc_Restore_stack, sp);
	be_peephole_exchange(node, stack);
452

453
454
455
	arch_register_t const *const reg = arch_get_irn_register(replaced);
	ir_node               *const res = be_new_Proj_reg(restore, pn_sparc_Restore_res, reg);
	be_peephole_exchange(replaced, res);
456
457
}

458
static void replace_with_restore_reg(ir_node *node, ir_node *replaced,
yb9976's avatar
yb9976 committed
459
                                     ir_node *op0, ir_node *op1)
460
461
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
462
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
463
464
	ir_node  *fp       = get_irn_n(node, n_sparc_RestoreZero_frame_pointer);
	ir_node  *block    = get_nodes_block(node);
465
466
	ir_node  *new_node = new_bd_sparc_Restore_reg(dbgi, block, stack_in, fp, op0, op1);
	replace_with_restore(new_node, node, replaced);
467
468
469
}

static void replace_with_restore_imm(ir_node *node, ir_node *replaced,
yb9976's avatar
yb9976 committed
470
471
                                     ir_node *op, ir_entity *imm_entity,
                                     int32_t immediate)
472
473
{
	dbg_info *dbgi     = get_irn_dbg_info(node);
474
	ir_node  *stack_in = get_irn_n(node, n_sparc_RestoreZero_stack);
475
476
	ir_node  *fp       = get_irn_n(node, n_sparc_RestoreZero_frame_pointer);
	ir_node  *block    = get_nodes_block(node);
477
478
	ir_node  *new_node = new_bd_sparc_Restore_imm(dbgi, block, stack_in, fp, op, imm_entity, immediate);
	replace_with_restore(new_node, node, replaced);
479
480
}

481
482
483
484
485
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);
}

486
487
488
static void peephole_sparc_RestoreZero(ir_node *node)
{
	/* restore gives us a free "add" instruction, let's try to use that to fold
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
	 * 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 */

504
	sched_foreach_reverse_before(node, schedpoint) {
505
506
507
508
509
510
511
		if (--n_tries == 0)
			break;

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

		if (!mode_is_data(get_irn_mode(schedpoint)))
512
513
			return;

514
		arch_register_t const *const reg = arch_get_irn_register(schedpoint);
515
516
517
		if (!is_restorezeroopt_reg(reg))
			continue;

518
		if (be_is_Copy(schedpoint) && can_move_down(schedpoint, node)) {
Christoph Mallon's avatar
Christoph Mallon committed
519
			ir_node *const op = be_get_Copy_op(schedpoint);
520
521
522
523
			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] &&
524
		           can_move_down(schedpoint, node)) {
525
526
527
528
529
530
531
			/* 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) &&
532
		           can_move_down(schedpoint, node)) {
533
534
535
536
537
538
539
540
541
542
543
544
545
546
			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] &&
547
		           can_move_down(schedpoint, node)) {
548
549
550
551
552
553
554
555
556
557
558
559
560
			/* 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;
561
562
563
	}
}

564
static void finish_sparc_Return(ir_node *node)
565
{
566
	/* Ensure that the restore is directly before the return. */
567
	sched_foreach_reverse_before(node, restore) {
568
569
570
		if (is_sparc_Restore(restore) || is_sparc_RestoreZero(restore)) {
			sched_remove(restore);
			sched_add_before(node, restore);
571
			break;
572
		}
573
574
575
	}
}

576
577
578
579
580
/**
 * Check whether the flags of the node are used.
 */
static bool has_flags_user(ir_node *node)
{
Christoph Mallon's avatar
Christoph Mallon committed
581
	return get_Proj_for_pn(node, pn_sparc_AddCC_flags) != NULL;
582
583
}

584
585
586
587
588
589
590
591
592
593
static void remove_unused_CC(ir_node *const node, ir_op *const op)
{
	assert((int)pn_sparc_AddCC_flags == (int)pn_sparc_SubCC_flags);
	if (has_flags_user(node))
		return;
	set_irn_op(node, op);
	backend_info_t *const info = be_get_info(node);
	ARR_SHRINKLEN(info->out_infos, 1);
}

594
595
596
597
598
/*
 * Transform AddCC into Add if flags output is unused.
 */
static void peephole_sparc_AddCC(ir_node *node)
{
599
	remove_unused_CC(node, op_sparc_Add);
600
601
602
603
604
605
606
}

/*
 * Transform SubCC into Sub if flags output is unused.
 */
static void peephole_sparc_SubCC(ir_node *node)
{
607
	remove_unused_CC(node, op_sparc_Sub);
608
609
}

610
611
612
613
614
static bool is_frame_load(const ir_node *node)
{
	return is_sparc_Ld(node) || is_sparc_Ldf(node);
}

615
616
static void sparc_collect_frame_entity_nodes(ir_node *node, void *data)
{
617
618
619
620
621
622
623
624
625
626
627
628
629
	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;
	}
630

631
	if (!is_frame_load(node))
632
633
		return;

Matthias Braun's avatar
Matthias Braun committed
634
635
636
	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;
637
638
639
640
	if (entity != NULL)
		return;
	if (!attr->is_frame_entity)
		return;
641
	if (arch_get_irn_flags(node) & sparc_arch_irn_flag_needs_64bit_spillslot)
642
		mode = mode_Lu;
643
644
	const ir_type *type = get_type_for_mode(mode);
	be_load_needs_frame_entity(env, node, type);
645
646
}

647
648
static void sparc_set_frame_entity(ir_node *node, ir_entity *entity,
                                   const ir_type *type)
649
{
650
	(void)type;
651
652
653
654
655
656
	/* 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;
657
658
}

659
660
661
662
/** returns true if the should_be_same constraints of a node must be
 * fulfilled */
static bool has_must_be_same(const ir_node *node)
{
663
	return is_sparc_Cas(node) || be_is_Asm(node);
664
665
666
667
668
669
670
671
672
673
674
675
}

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
676
void sparc_finish_graph(ir_graph *irg)
677
{
678
679
	bool          omit_fp = sparc_get_irg_data(irg)->omit_fp;
	be_fec_env_t *fec_env = be_new_frame_entity_coalescer(irg);
680
681

	irg_walk_graph(irg, NULL, sparc_collect_frame_entity_nodes, fec_env);
682
	be_assign_entities(fec_env, sparc_set_frame_entity, omit_fp);
683
	be_free_frame_entity_coalescer(fec_env);
684
	sparc_adjust_stack_entity_offsets(irg, omit_fp);
685

686
	sparc_introduce_prolog_epilog(irg, omit_fp);
687
688

	/* fix stack entity offsets */
689
	be_fix_stack_nodes(irg, &sparc_registers[REG_SP]);
690
	be_birg_from_irg(irg)->non_ssa_regs = NULL;
691
	sparc_fix_stack_bias(irg);
692

693
694
	heights = heights_new(irg);

695
	/* perform peephole optimizations */
Matthias Braun's avatar
Matthias Braun committed
696
	ir_clear_opcodes_generic_func();
697
698
699
	register_peephole_optimization(op_be_IncSP,        peephole_be_IncSP);
	register_peephole_optimization(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
	register_peephole_optimization(op_sparc_RestoreZero,
700
	                               peephole_sparc_RestoreZero);
701
702
703
	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);
704
705
	be_peephole_opt(irg);

706
	/* perform legalizations (mostly fix nodes with too big immediates) */
Matthias Braun's avatar
Matthias Braun committed
707
	ir_clear_opcodes_generic_func();
708
709
710
711
712
713
714
715
	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);
716
	be_peephole_opt(irg);
717

718
719
	heights_free(heights);

720
721
	irg_block_walk_graph(irg, NULL, fix_constraints_walker, NULL);

722
	be_remove_dead_nodes_from_schedule(irg);
723
}