sparc_finish.c 27.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 "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

static int get_first_same(const arch_register_req_t *req)
{
46
	const unsigned other = req->should_be_same;
47
48
49
50
51
52
53
54
	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
 * 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);
66
		if (req->should_be_same == 0)
67
68
69
70
71
72
73
74
75
76
77
78
			continue;

		int same_pos = get_first_same(req);

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

		/* requirement already fulfilled? */
		if (in_reg == out_reg)
			continue;
79
		assert(in_reg->cls == out_reg->cls);
80
81
82
83

		/* check if any other input operands uses the out register */
		ir_node *uses_out_reg     = NULL;
		int      uses_out_reg_pos = -1;
84
		foreach_irn_in(node, i2, in) {
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
			const arch_register_t *other_in_reg = arch_get_irn_register(in);
			if (other_in_reg != out_reg)
				continue;

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

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

			/* destination is the out register */
			arch_set_irn_register(copy, out_reg);

			/* insert copy before the node into the schedule */
			sched_add_before(node, copy);

			/* set copy as in */
			set_irn_n(node, same_pos, copy);
			continue;
		}

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

120
121
static ir_heights_t *heights;

122
123
124
125
126
127
128
129
130
131
132
133
static void kill_unused_stacknodes(ir_node *node)
{
	if (get_irn_n_edges(node) > 0)
		return;

	if (be_is_IncSP(node)) {
		sched_remove(node);
		kill_node(node);
	} else if (is_Phi(node)) {
		int       arity = get_irn_arity(node);
		ir_node **ins   = ALLOCAN(ir_node*, arity);
		sched_remove(node);
Christoph Mallon's avatar
Christoph Mallon committed
134
		MEMCPY(ins, get_irn_in(node), arity);
135
136
		kill_node(node);

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

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

147
148
149
150
	ir_node           *const sp     = get_irn_n(ret, n_sparc_Return_sp);
	ir_node           *const block  = get_nodes_block(ret);
	ir_graph          *const irg    = get_irn_irg(ret);
	be_stack_layout_t *const layout = be_get_irg_stack_layout(irg);
151
	if (!layout->sp_relative) {
152
		arch_register_t const *const fp_reg  = &sparc_registers[REG_FP];
153
154
155
		ir_node               *const fp      = be_get_initial_reg_value(irg, fp_reg);
		ir_node               *const new_sp  = be_get_initial_reg_value(irg, sp_reg);
		ir_node               *const restore = new_bd_sparc_RestoreZero(NULL, block, new_sp, fp);
156
157
		sched_add_before(ret, restore);
		arch_set_irn_register(restore, sp_reg);
158
		set_irn_n(ret, n_sparc_Return_sp, restore);
159
160
		kill_unused_stacknodes(sp);
	} else {
161
162
163
		ir_type *const frame_type = get_irg_frame_type(irg);
		unsigned const frame_size = get_type_size_bytes(frame_type);
		ir_node *const incsp      = be_new_IncSP(sp_reg, block, sp, -frame_size, 0);
164
		set_irn_n(ret, n_sparc_Return_sp, incsp);
165
166
167
168
		sched_add_before(ret, incsp);
	}
}

169
static void sparc_introduce_prolog_epilog(ir_graph *irg)
170
171
172
173
174
175
176
177
178
179
{
	const arch_register_t *sp_reg     = &sparc_registers[REG_SP];
	ir_node               *start      = get_irg_start(irg);
	be_stack_layout_t     *layout     = be_get_irg_stack_layout(irg);
	ir_node               *block      = get_nodes_block(start);
	ir_node               *initial_sp = be_get_initial_reg_value(irg, sp_reg);
	ir_type               *frame_type = get_irg_frame_type(irg);
	unsigned               frame_size = get_type_size_bytes(frame_type);

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

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

190
		edges_reroute_except(initial_sp, save, save);
191

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

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/**
 * Creates a constant from an immediate value.
 */
static ir_node *create_constant_from_immediate(ir_node *node, int offset)
{
	dbg_info *dbgi  = get_irn_dbg_info(node);
	ir_node  *block = get_nodes_block(node);
	ir_node  *high  = new_bd_sparc_SetHi(dbgi, block, NULL, offset);

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

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

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

		return low;
	}

	return high;
}

229
230
231
232
233
static void finish_sparc_Save(ir_node *node)
{
	sparc_attr_t *attr = get_sparc_attr(node);
	int offset = attr->immediate_value;

Matthias Braun's avatar
Matthias Braun committed
234
	if (!sparc_is_value_imm_encodeable(offset)) {
235
236
237
238
239
240
241
242
243
244
245
246
247
		ir_node               *base     = get_irn_n(node, n_sparc_Save_stack);
		dbg_info              *dbgi     = get_irn_dbg_info(node);
		ir_node               *block    = get_nodes_block(node);
		ir_node               *constant = create_constant_from_immediate(node, offset);
		ir_node               *new_save = new_bd_sparc_Save_reg(dbgi, block, base, constant);
		const arch_register_t *reg      = arch_get_irn_register(node);

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

		sched_add_before(node, new_save);
		arch_set_irn_register(new_save, reg);
		be_peephole_exchange(node, new_save);
248
249
250
251
	}
}

/**
252
 * SPARC immediates are limited. Split IncSP with bigger immediates if
253
254
255
256
 * necessary.
 */
static void finish_be_IncSP(ir_node *node)
{
257
258
259
	int offset = be_get_IncSP_offset(node);

	/* we might have to break the IncSP apart if the constant has become too big */
Matthias Braun's avatar
Matthias Braun committed
260
261
262
263
264
265
	if (!sparc_is_value_imm_encodeable(offset) && !sparc_is_value_imm_encodeable(-offset)) {
		ir_node  *sp       = be_get_IncSP_pred(node);
		dbg_info *dbgi     = get_irn_dbg_info(node);
		ir_node  *block    = get_nodes_block(node);
		ir_node  *constant = create_constant_from_immediate(node, offset);
		ir_node  *sub      = new_bd_sparc_Sub_reg(dbgi, block, sp, constant);
266
267
268
269

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

/**
yb9976's avatar
yb9976 committed
274
275
276
 * Adjust sp-relative offsets.
 *
 * Split into multiple instructions if offset exceeds SPARC immediate range.
277
278
279
280
281
282
 */
static void finish_sparc_FrameAddr(ir_node *node)
{
	sparc_attr_t *attr   = get_sparc_attr(node);
	int           offset = attr->immediate_value;

Matthias Braun's avatar
Matthias Braun committed
283
	if (!sparc_is_value_imm_encodeable(offset)) {
284
285
286
287
288
289
		ir_node               *base          = get_irn_n(node, n_sparc_FrameAddr_base);
		dbg_info              *dbgi          = get_irn_dbg_info(node);
		ir_node               *block         = get_nodes_block(node);
		ir_node               *constant      = create_constant_from_immediate(node, offset);
		ir_node               *new_frameaddr = new_bd_sparc_Add_reg(dbgi, block, base, constant);
		const arch_register_t *reg           = arch_get_irn_register(node);
290

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

yb9976's avatar
yb9976 committed
297
298
299
300
301
302
static void finish_sparc_Ld(ir_node *node)
{
	sparc_attr_t                  *attr            = get_sparc_attr(node);
	int                            offset          = attr->immediate_value;
	const sparc_load_store_attr_t *load_store_attr = get_sparc_load_store_attr_const(node);

Matthias Braun's avatar
Matthias Braun committed
303
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
304
305
		return;

Matthias Braun's avatar
Matthias Braun committed
306
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
307
308
309
310
311
312
313
314
315
316
317
318
319
		ir_node                 *ptr             = get_irn_n(node, n_sparc_Ld_ptr);
		dbg_info                *dbgi            = get_irn_dbg_info(node);
		ir_node                 *block           = get_nodes_block(node);
		ir_node                 *mem             = get_irn_n(node, n_sparc_Ld_mem);
		ir_mode                 *load_store_mode = load_store_attr->load_store_mode;
		ir_node                 *constant        = create_constant_from_immediate(node, offset);
		ir_node                 *new_load        = new_bd_sparc_Ld_reg(dbgi, block, ptr, constant, mem, load_store_mode);
		sparc_load_store_attr_t *new_load_attr   = get_sparc_load_store_attr(new_load);

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

		sched_add_before(node, new_load);
320
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
321
322
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
323
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
324
325
326
327
	}

}

328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
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);
343
		ir_node  *const new_mem = be_new_Proj(new_load, pn_sparc_Ldf_M);
344
345
346
347
348
349
350
351
352
353
354
355
356
357

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

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

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

yb9976's avatar
yb9976 committed
358
359
360
361
362
363
static void finish_sparc_Ldf(ir_node *node)
{
	sparc_attr_t                  *attr            = get_sparc_attr(node);
	int                            offset          = attr->immediate_value;
	const sparc_load_store_attr_t *load_store_attr = get_sparc_load_store_attr_const(node);

Matthias Braun's avatar
Matthias Braun committed
364
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
365
366
		return;

Matthias Braun's avatar
Matthias Braun committed
367
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
368
369
370
371
372
373
374
375
376
377
378
379
380
381
		ir_node                 *ptr             = get_irn_n(node, n_sparc_Ldf_ptr);
		dbg_info                *dbgi            = get_irn_dbg_info(node);
		ir_node                 *block           = get_nodes_block(node);
		ir_node                 *mem             = get_irn_n(node, n_sparc_Ldf_mem);
		ir_mode                 *load_store_mode = load_store_attr->load_store_mode;
		ir_node                 *constant        = create_constant_from_immediate(node, offset);
		ir_node                 *new_ptr         = new_bd_sparc_Add_reg(dbgi, block, ptr, constant);
		ir_node                 *new_load        = new_bd_sparc_Ldf_s(dbgi, block, new_ptr, mem, load_store_mode, NULL, 0, true);
		sparc_load_store_attr_t *new_load_attr   = get_sparc_load_store_attr(new_load);

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

		sched_add_before(node, new_load);
382
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
383
384
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
385
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
386
387
388
389
390
391
392
393
394
395
	}

}

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

Matthias Braun's avatar
Matthias Braun committed
396
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
397
398
		return;

Matthias Braun's avatar
Matthias Braun committed
399
	if (!sparc_is_value_imm_encodeable(offset)) {
yb9976's avatar
yb9976 committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
		ir_node                 *ptr             = get_irn_n(node, n_sparc_St_ptr);
		dbg_info                *dbgi            = get_irn_dbg_info(node);
		ir_node                 *block           = get_nodes_block(node);
		ir_node                 *mem             = get_irn_n(node, n_sparc_St_mem);
		ir_node                 *value           = get_irn_n(node, n_sparc_St_val);
		ir_mode                 *load_store_mode = load_store_attr->load_store_mode;
		ir_node                 *constant        = create_constant_from_immediate(node, offset);
		ir_node                 *new_load        = new_bd_sparc_St_reg(dbgi, block, value, ptr, constant, mem, load_store_mode);
		sparc_load_store_attr_t *new_load_attr   = get_sparc_load_store_attr(new_load);

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

		sched_add_before(node, new_load);
414
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
415
416
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
417
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
418
419
420
421
422
423
424
425
426
427
	}

}

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

Matthias Braun's avatar
Matthias Braun committed
428
	if (!load_store_attr->is_frame_entity)
yb9976's avatar
yb9976 committed
429
430
		return;

Matthias Braun's avatar
Matthias Braun committed
431
432
433
434
435
436
437
438
439
440
441
	if (!sparc_is_value_imm_encodeable(offset)) {
		ir_node  *ptr             = get_irn_n(node, n_sparc_Stf_ptr);
		dbg_info *dbgi            = get_irn_dbg_info(node);
		ir_node  *block           = get_nodes_block(node);
		ir_node  *mem             = get_irn_n(node, n_sparc_Stf_mem);
		ir_node  *value           = get_irn_n(node, n_sparc_Stf_val);
		ir_mode  *load_store_mode = load_store_attr->load_store_mode;
		ir_node  *constant        = create_constant_from_immediate(node, offset);
		ir_node  *new_ptr         = new_bd_sparc_Add_reg(dbgi, block, ptr, constant);
		ir_node  *new_load        = new_bd_sparc_Stf_s(dbgi, block, value, new_ptr, mem, load_store_mode, NULL, 0, true);
		sparc_load_store_attr_t *new_load_attr = get_sparc_load_store_attr(new_load);
yb9976's avatar
yb9976 committed
442
443
444
445
446

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

		sched_add_before(node, new_load);
447
		be_foreach_out(node, i) {
yb9976's avatar
yb9976 committed
448
449
			arch_set_irn_register_out(new_load, i, arch_get_irn_register_out(node, i));
		}
450
		be_peephole_exchange(node, new_load);
yb9976's avatar
yb9976 committed
451
452
453
454
	}

}

455
456
457
458
459
460
static void peephole_be_IncSP(ir_node *node)
{
	node = be_peephole_IncSP_IncSP(node);
	if (!be_is_IncSP(node))
		return;

Matthias Braun's avatar
Matthias Braun committed
461
	ir_node *pred = be_get_IncSP_pred(node);
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
	if (is_sparc_Save(pred) && be_has_only_one_user(pred)) {
		int offset = -be_get_IncSP_offset(node);
		sparc_attr_t *attr = get_sparc_attr(pred);
		attr->immediate_value += offset;
		be_peephole_exchange(node, pred);
	}
}

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

477
478
479
/* output must not be local, or out reg. Since the destination of the restore
 * is the rotated register-file where only the old in-registers are still
 * visible (as out-registers) */
480
481
482
483
484
485
486
static bool is_restorezeroopt_reg(const arch_register_t *reg)
{
	unsigned index = reg->global_index;
	return (index >= REG_G0 && index <= REG_G7)
	    || (index >= REG_I0 && index <= REG_I7);
}

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

530
531
532
533
534
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);
}

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

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

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

		if (!mode_is_data(get_irn_mode(schedpoint)))
561
562
			return;

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

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

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

625
626
627
628
629
/**
 * Check whether the flags of the node are used.
 */
static bool has_flags_user(ir_node *node)
{
Christoph Mallon's avatar
Christoph Mallon committed
630
	return get_Proj_for_pn(node, pn_sparc_AddCC_flags) != NULL;
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
}

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

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

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

670
671
static void sparc_collect_frame_entity_nodes(ir_node *node, void *data)
{
672
673
674
675
676
677
678
679
680
681
682
683
684
	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;
	}
685

686
	if (!is_frame_load(node))
687
688
		return;

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

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

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

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

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

	sparc_introduce_prolog_epilog(irg);

	/* fix stack entity offsets */
745
	be_fix_stack_nodes(irg, &sparc_registers[REG_SP]);
746
	be_birg_from_irg(irg)->non_ssa_regs = NULL;
747
	sparc_fix_stack_bias(irg);
748

749
750
	heights = heights_new(irg);

751
	/* perform peephole optimizations */
Matthias Braun's avatar
Matthias Braun committed
752
	ir_clear_opcodes_generic_func();
753
754
755
	register_peephole_optimization(op_be_IncSP,        peephole_be_IncSP);
	register_peephole_optimization(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
	register_peephole_optimization(op_sparc_RestoreZero,
756
	                               peephole_sparc_RestoreZero);
757
758
759
	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);
760
761
	be_peephole_opt(irg);

762
	/* perform legalizations (mostly fix nodes with too big immediates) */
Matthias Braun's avatar
Matthias Braun committed
763
	ir_clear_opcodes_generic_func();
764
765
766
767
768
769
770
771
	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);
772
	be_peephole_opt(irg);
773

774
775
	heights_free(heights);

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

778
	be_remove_dead_nodes_from_schedule(irg);
779
}