benode.c 22.3 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

Sebastian Hack's avatar
Sebastian Hack committed
6
/**
Christian Würdig's avatar
Christian Würdig committed
7
8
9
 * @file
 * @brief       Backend node support for generic backend nodes.
 * @author      Sebastian Hack
Sebastian Hack's avatar
Sebastian Hack committed
10
 *
11
 * Backend node support for generic backend nodes.
Sebastian Hack's avatar
Sebastian Hack committed
12
13
14
 */
#include <stdlib.h>

Matthias Braun's avatar
Matthias Braun committed
15
16
17
18
#include "array.h"
#include "be_t.h"
#include "bearch.h"
#include "bedump.h"
19
#include "beirg.h"
Matthias Braun's avatar
Matthias Braun committed
20
21
#include "belive.h"
#include "benode.h"
22
#include "besched.h"
Matthias Braun's avatar
Matthias Braun committed
23
#include "bitfiddle.h"
24
#include "fourcc.h"
Matthias Braun's avatar
Matthias Braun committed
25
#include "irbackedge_t.h"
26
#include "ircons_t.h"
Matthias Braun's avatar
Matthias Braun committed
27
#include "irgopt.h"
Sebastian Hack's avatar
Sebastian Hack committed
28
#include "irgwalk.h"
Matthias Braun's avatar
Matthias Braun committed
29
30
31
#include "irmode_t.h"
#include "irnode_t.h"
#include "irop_t.h"
Michael Beck's avatar
Michael Beck committed
32
#include "iropt_t.h"
Matthias Braun's avatar
Matthias Braun committed
33
#include "irprintf.h"
34
#include "irverify_t.h"
Matthias Braun's avatar
Matthias Braun committed
35
36
37
38
39
40
#include "obst.h"
#include "panic.h"
#include "pmap.h"
#include "raw_bitset.h"
#include "set.h"
#include "util.h"
Sebastian Hack's avatar
Sebastian Hack committed
41

Michael Beck's avatar
Michael Beck committed
42
/** The be_IncSP attribute type. */
Sebastian Hack's avatar
Sebastian Hack committed
43
typedef struct {
44
	be_node_attr_t base;
Matthias Braun's avatar
Matthias Braun committed
45
46
	int            offset; /**< The offset by which the stack shall be
	                            expanded/shrinked. */
47
	unsigned       align;  /**< alignment after the IncSP (0=no alignment) */
Michael Beck's avatar
Michael Beck committed
48
} be_incsp_attr_t;
Sebastian Hack's avatar
Sebastian Hack committed
49

50
typedef struct {
51
52
53
	be_node_attr_t base;
	ir_entity    **in_entities;
	ir_entity    **out_entities;
54
	int            offset;
Matthias Braun's avatar
Matthias Braun committed
55
} be_memperm_attr_t;
56

57
58
59
60
61
typedef struct be_relocation_attr_t {
	ir_entity *entity;
	unsigned   kind;
} be_relocation_attr_t;

62
ir_op *op_be_Asm;
63
ir_op *op_be_Copy;
Sebastian Hack's avatar
Sebastian Hack committed
64
ir_op *op_be_CopyKeep;
65
ir_op *op_be_IncSP;
Matthias Braun's avatar
Matthias Braun committed
66
67
68
ir_op *op_be_Keep;
ir_op *op_be_MemPerm;
ir_op *op_be_Perm;
69
ir_op *op_be_Relocation;
Christoph Mallon's avatar
Christoph Mallon committed
70
ir_op *op_be_Start;
Sebastian Hack's avatar
Sebastian Hack committed
71

72
73
#define be_op_tag FOURCC('B', 'E', '\0', '\0')

74
75
76
77
78
79
80
static int be_asm_attr_equal(ir_node const *const a, ir_node const *const b)
{
	be_asm_attr_t const *const attr_a = get_be_asm_attr_const(a);
	be_asm_attr_t const *const attr_b = get_be_asm_attr_const(b);
	return attr_a->text == attr_b->text && attr_a->operands == attr_b->operands;
}

Michael Beck's avatar
Michael Beck committed
81
82
83
/**
 * Compare the attributes of two be_IncSP nodes.
 */
84
static int be_incsp_attrs_equal(const ir_node *a, const ir_node *b)
85
{
Matthias Braun's avatar
Matthias Braun committed
86
87
88
89
	const be_incsp_attr_t *attr_a
		= (const be_incsp_attr_t*)get_irn_generic_attr_const(a);
	const be_incsp_attr_t *attr_b
		= (const be_incsp_attr_t*)get_irn_generic_attr_const(b);
90
	return attr_a->offset == attr_b->offset && attrs_equal_be_node(a, b);
91
92
}

93
94
95
96
97
98
99
100
101
static int be_relocation_attrs_equal(ir_node const *a, ir_node const *b)
{
	be_relocation_attr_t const *attr_a
		= (be_relocation_attr_t const*)get_irn_generic_attr_const(a);
	be_relocation_attr_t const *attr_b
		= (be_relocation_attr_t const*)get_irn_generic_attr_const(b);
	return attr_a->entity == attr_b->entity && attr_a->kind == attr_b->kind;
}

102
103
104
105
106
107
arch_register_req_t const **be_allocate_in_reqs(ir_graph *const irg, unsigned const n)
{
	struct obstack *const obst = be_get_be_obst(irg);
	return OALLOCN(obst, arch_register_req_t const*, n);
}

108
static arch_register_req_t *allocate_reg_req(ir_graph *const irg)
Matthias Braun's avatar
Matthias Braun committed
109
{
110
	struct obstack *obst = be_get_be_obst(irg);
111
	arch_register_req_t *req = OALLOCZ(obst, arch_register_req_t);
112
113
	return req;
}
Matthias Braun's avatar
Matthias Braun committed
114

Matthias Braun's avatar
Matthias Braun committed
115
116
static void be_node_set_register_req_in(ir_node *const node, int const pos,
                                        arch_register_req_t const *const req)
117
{
118
119
120
	backend_info_t *info = be_get_info(node);
	assert(pos < get_irn_arity(node));
	info->in_reqs[pos] = req;
121
}
Matthias Braun's avatar
Matthias Braun committed
122

123
/**
124
 * Initializes the generic attribute of all be nodes and return it.
125
 */
126
static void init_node_attr(ir_node *const node, unsigned const n_outputs, arch_irn_flags_t const flags)
Sebastian Hack's avatar
Sebastian Hack committed
127
{
128
129
	ir_graph       *irg  = get_irn_irg(node);
	backend_info_t *info = be_get_info(node);
Sebastian Hack's avatar
Sebastian Hack committed
130

131
	unsigned                    const arity   = get_irn_arity(node);
132
133
	arch_register_req_t const **const in_reqs =
		is_irn_dynamic(node) ? NEW_ARR_F(arch_register_req_t const*, arity) :
134
		arity != 0           ? be_allocate_in_reqs(irg, arity) :
135
136
137
		NULL;
	for (unsigned i = 0; i < arity; ++i) {
		in_reqs[i] = arch_no_register_req;
138
	}
139
	info->in_reqs = in_reqs;
140

141
	struct obstack *const obst = be_get_be_obst(irg);
142
	info->out_infos = NEW_ARR_DZ(reg_out_info_t, obst, n_outputs);
Matthias Braun's avatar
Matthias Braun committed
143
	for (unsigned i = 0; i < n_outputs; ++i) {
144
		info->out_infos[i].req = arch_no_register_req;
Sebastian Hack's avatar
Sebastian Hack committed
145
	}
Matthias Braun's avatar
Matthias Braun committed
146
	info->flags = flags;
Sebastian Hack's avatar
Sebastian Hack committed
147
}
148

Matthias Braun's avatar
Matthias Braun committed
149
150
151
ir_node *be_new_Perm(arch_register_class_t const *const cls,
                     ir_node *const block, int const n,
                     ir_node *const *const in)
Sebastian Hack's avatar
Sebastian Hack committed
152
{
153
	ir_graph *irg = get_irn_irg(block);
Matthias Braun's avatar
Matthias Braun committed
154
	ir_node  *irn = new_ir_node(NULL, irg, block, op_be_Perm, mode_T, n, in);
155
	init_node_attr(irn, n, arch_irn_flags_none);
Matthias Braun's avatar
Matthias Braun committed
156
	be_node_attr_t *attr = (be_node_attr_t*)get_irn_generic_attr(irn);
157
	attr->exc.pinned = true;
Matthias Braun's avatar
Matthias Braun committed
158
	for (int i = 0; i < n; ++i) {
159
160
161
		const ir_node             *input = in[i];
		const arch_register_req_t *req   = arch_get_irn_register_req(input);
		if (req->width == 1) {
Matthias Braun's avatar
Matthias Braun committed
162
163
			be_node_set_register_req_in(irn, i, cls->class_req);
			arch_set_irn_register_req_out(irn, i, cls->class_req);
164
		} else {
165
			arch_register_req_t *const new_req = allocate_reg_req(irg);
166
167
168
			new_req->cls     = cls;
			new_req->width   = req->width;
			new_req->aligned = req->aligned;
Matthias Braun's avatar
Matthias Braun committed
169
170
			be_node_set_register_req_in(irn, i, new_req);
			arch_set_irn_register_req_out(irn, i, new_req);
171
		}
Sebastian Hack's avatar
Sebastian Hack committed
172
173
	}

Sebastian Hack's avatar
Sebastian Hack committed
174
175
	return irn;
}
176

177
ir_node *be_new_MemPerm(ir_node *const block, int n, ir_node *const *const in)
Matthias Braun's avatar
Matthias Braun committed
178
{
179
180
	ir_graph *const irg = get_irn_irg(block);
	ir_node  *const irn = new_ir_node(NULL, irg, block, op_be_MemPerm, mode_T, n, in);
Matthias Braun's avatar
Matthias Braun committed
181

182
	init_node_attr(irn, n, arch_irn_flags_none);
183
184
185
186
	for (int i = 0; i < n; ++i) {
		be_node_set_register_req_in(  irn, i, arch_memory_req);
		arch_set_irn_register_req_out(irn, i, arch_memory_req);
	}
Matthias Braun's avatar
Matthias Braun committed
187

Matthias Braun's avatar
Matthias Braun committed
188
	be_memperm_attr_t *attr = (be_memperm_attr_t*)get_irn_generic_attr(irn);
189
190
	attr->in_entities  = OALLOCNZ(get_irg_obstack(irg), ir_entity*, n);
	attr->out_entities = OALLOCNZ(get_irg_obstack(irg), ir_entity*, n);
191
	attr->offset       = 0;
Matthias Braun's avatar
Matthias Braun committed
192
193
194
	return irn;
}

195
196
197
198
static void set_copy_info(ir_node *const irn, ir_graph *const irg, ir_node *const op, arch_irn_flags_t const flags)
{
	init_node_attr(irn, 1, flags);
	be_node_attr_t *const attr = (be_node_attr_t*)get_irn_generic_attr(irn);
199
	attr->exc.pinned = false;
200
201
202
203
204
205
206
207
208
209
210
211
212
213

	arch_register_req_t   const *const op_req = arch_get_irn_register_req(op);
	arch_register_class_t const *const cls    = op_req->cls;

	be_node_set_register_req_in(irn, 0, cls->class_req);

	arch_register_req_t *const out_req = allocate_reg_req(irg);
	out_req->cls            = cls;
	out_req->should_be_same = 1U << 0;
	out_req->aligned        = op_req->aligned;
	out_req->width          = op_req->width;
	arch_set_irn_register_req_out(irn, 0, out_req);
}

214
ir_node *be_new_d_Copy(dbg_info *const dbgi, ir_node *const block, ir_node *const op)
Sebastian Hack's avatar
Sebastian Hack committed
215
{
216
217
218
	ir_graph *const irg  = get_irn_irg(block);
	ir_node  *const in[] = { op };
	ir_node  *const res  = new_ir_node(dbgi, irg, block, op_be_Copy, get_irn_mode(op), ARRAY_SIZE(in), in);
219
	set_copy_info(res, irg, op, arch_irn_flags_none);
Sebastian Hack's avatar
Sebastian Hack committed
220
	return res;
221
222
}

223
224
225
226
227
ir_node *be_new_Copy(ir_node *const bl, ir_node *const op)
{
	return be_new_d_Copy(NULL, bl, op);
}

228
229
ir_node *be_get_Copy_op(const ir_node *cpy)
{
230
	return get_irn_n(cpy, n_be_Copy_op);
231
232
}

233
234
235
236
237
238
239
240
241
ir_node *be_new_Copy_before_reg(ir_node *const val, ir_node *const before, arch_register_t const *const reg)
{
	ir_node *const block = get_nodes_block(before);
	ir_node *const copy  = be_new_Copy(block, val);
	sched_add_before(before, copy);
	arch_set_irn_register_out(copy, 0, reg);
	return copy;
}

Matthias Braun's avatar
Matthias Braun committed
242
243
ir_node *be_new_Keep(ir_node *const block, int const n,
                     ir_node *const *const in)
Sebastian Hack's avatar
Sebastian Hack committed
244
{
245
	ir_graph *irg = get_irn_irg(block);
246
	ir_node  *res = new_ir_node(NULL, irg, block, op_be_Keep, mode_ANY, n, in);
247
	init_node_attr(res, 1, arch_irn_flag_schedule_first);
Matthias Braun's avatar
Matthias Braun committed
248
	be_node_attr_t *attr = (be_node_attr_t*) get_irn_generic_attr(res);
249
	attr->exc.pinned = true;
Sebastian Hack's avatar
Sebastian Hack committed
250

Matthias Braun's avatar
Matthias Braun committed
251
	for (int i = 0; i < n; ++i) {
252
253
		arch_register_req_t const *const req = arch_get_irn_register_req(in[i]);
		be_node_set_register_req_in(res, i, req->cls->class_req);
Sebastian Hack's avatar
Sebastian Hack committed
254
	}
255
256
257
258
	keep_alive(res);
	return res;
}

259
260
261
262
263
264
265
ir_node *be_new_Keep_one(ir_node *const kept)
{
	ir_node *const in[]  = { kept };
	ir_node *const block = get_nodes_block(kept);
	return be_new_Keep(block, ARRAY_SIZE(in), in);
}

266
ir_node *be_new_IncSP(const arch_register_t *sp, ir_node *bl,
267
                      ir_node *old_sp, int offset, unsigned align)
Sebastian Hack's avatar
Sebastian Hack committed
268
{
269
	ir_graph *irg = get_irn_irg(bl);
Matthias Braun's avatar
Matthias Braun committed
270
	ir_node  *in[] = { old_sp };
Matthias Braun's avatar
Matthias Braun committed
271
272
	ir_node  *irn  = new_ir_node(NULL, irg, bl, op_be_IncSP, sp->cls->mode,
	                             ARRAY_SIZE(in), in);
273
	init_node_attr(irn, 1, arch_irn_flags_none);
274
275
276
277
	be_incsp_attr_t *a = (be_incsp_attr_t*)get_irn_generic_attr(irn);
	a->offset          = offset;
	a->align           = align;
	a->base.exc.pinned = true;
Sebastian Hack's avatar
Sebastian Hack committed
278
279

	/* Set output constraint to stack register. */
Matthias Braun's avatar
Matthias Braun committed
280
	be_node_set_register_req_in(irn, 0, sp->cls->class_req);
281
	arch_copy_irn_out_info(irn, 0, old_sp);
Sebastian Hack's avatar
Sebastian Hack committed
282
	return irn;
Sebastian Hack's avatar
Sebastian Hack committed
283
}
Sebastian Hack's avatar
Sebastian Hack committed
284

285
ir_node *be_new_CopyKeep(ir_node *const bl, ir_node *const src, int const n, ir_node *const *const in_keep)
Sebastian Hack's avatar
Sebastian Hack committed
286
{
Matthias Braun's avatar
Matthias Braun committed
287
	ir_mode  *mode  = get_irn_mode(src);
288
	ir_graph *irg   = get_irn_irg(bl);
Matthias Braun's avatar
Matthias Braun committed
289
290
	int       arity = n+1;
	ir_node **in    = ALLOCAN(ir_node*, arity);
Sebastian Hack's avatar
Sebastian Hack committed
291
	in[0] = src;
Christoph Mallon's avatar
Christoph Mallon committed
292
	MEMCPY(&in[1], in_keep, n);
Matthias Braun's avatar
Matthias Braun committed
293
	ir_node *irn = new_ir_node(NULL, irg, bl, op_be_CopyKeep, mode, arity, in);
294
	set_copy_info(irn, irg, src, arch_irn_flag_schedule_first);
295
296
	for (int i = 0; i < n; ++i) {
		ir_node *pred = in_keep[i];
297
298
		arch_register_req_t const *const req = arch_get_irn_register_req(pred);
		be_node_set_register_req_in(irn, i + 1, req->cls->class_req);
299
	}
Sebastian Hack's avatar
Sebastian Hack committed
300
301
302
	return irn;
}

303
304
ir_node *be_get_CopyKeep_op(const ir_node *cpy)
{
305
	return get_irn_n(cpy, n_be_CopyKeep_op);
306
307
}

308
void be_set_MemPerm_in_entity(const ir_node *irn, unsigned n, ir_entity *ent)
Matthias Braun's avatar
Matthias Braun committed
309
{
310
	assert(n < be_get_MemPerm_entity_arity(irn));
Matthias Braun's avatar
Matthias Braun committed
311
312
	const be_memperm_attr_t *attr
		= (const be_memperm_attr_t*)get_irn_generic_attr_const(irn);
Matthias Braun's avatar
Matthias Braun committed
313
314
315
	attr->in_entities[n] = ent;
}

316
ir_entity* be_get_MemPerm_in_entity(const ir_node* irn, unsigned n)
Matthias Braun's avatar
Matthias Braun committed
317
{
318
	assert(n < be_get_MemPerm_entity_arity(irn));
Matthias Braun's avatar
Matthias Braun committed
319
320
	const be_memperm_attr_t *attr
		= (const be_memperm_attr_t*)get_irn_generic_attr_const(irn);
Matthias Braun's avatar
Matthias Braun committed
321
322
323
	return attr->in_entities[n];
}

324
void be_set_MemPerm_out_entity(const ir_node *irn, unsigned n, ir_entity *ent)
Matthias Braun's avatar
Matthias Braun committed
325
{
326
	assert(n < be_get_MemPerm_entity_arity(irn));
Matthias Braun's avatar
Matthias Braun committed
327
328
	const be_memperm_attr_t *attr
		= (const be_memperm_attr_t*)get_irn_generic_attr_const(irn);
Matthias Braun's avatar
Matthias Braun committed
329
330
331
	attr->out_entities[n] = ent;
}

332
ir_entity* be_get_MemPerm_out_entity(const ir_node* irn, unsigned n)
Matthias Braun's avatar
Matthias Braun committed
333
{
334
	assert(n < be_get_MemPerm_entity_arity(irn));
Matthias Braun's avatar
Matthias Braun committed
335
336
	const be_memperm_attr_t *attr
		= (const be_memperm_attr_t*)get_irn_generic_attr_const(irn);
Matthias Braun's avatar
Matthias Braun committed
337
338
339
	return attr->out_entities[n];
}

340
341
342
void be_set_MemPerm_offset(ir_node *irn, int offset)
{
	assert(be_is_MemPerm(irn));
Matthias Braun's avatar
Matthias Braun committed
343
	be_memperm_attr_t *attr = (be_memperm_attr_t*)get_irn_generic_attr(irn);
344
345
346
347
348
349
	attr->offset = offset;
}

int be_get_MemPerm_offset(const ir_node *irn)
{
	assert(be_is_MemPerm(irn));
Matthias Braun's avatar
Matthias Braun committed
350
351
	const be_memperm_attr_t *attr
		= (const be_memperm_attr_t*)get_irn_generic_attr_const(irn);
352
353
354
	return attr->offset;
}

355
unsigned be_get_MemPerm_entity_arity(const ir_node *irn)
356
{
Matthias Braun's avatar
Matthias Braun committed
357
	assert(be_is_MemPerm(irn));
358
	return get_irn_arity(irn);
359
360
}

361
const arch_register_req_t *be_create_reg_req(struct obstack *obst,
362
363
                                             const arch_register_t *reg,
                                             bool ignore)
Sebastian Hack's avatar
Sebastian Hack committed
364
{
365
	arch_register_class_t const *cls     = reg->cls;
Matthias Braun's avatar
Matthias Braun committed
366
367
	unsigned                    *limited
		= rbitset_obstack_alloc(obst, cls->n_regs);
Matthias Braun's avatar
Matthias Braun committed
368
	rbitset_set(limited, reg->index);
369
	arch_register_req_t *req = OALLOCZ(obst, arch_register_req_t);
370
	req->cls     = cls;
Matthias Braun's avatar
Matthias Braun committed
371
	req->limited = limited;
372
	req->width   = 1;
373
	req->ignore  = ignore;
374
	return req;
375
376
}

377
378
ir_node *be_get_IncSP_pred(ir_node *irn)
{
Michael Beck's avatar
BugFix:    
Michael Beck committed
379
	assert(be_is_IncSP(irn));
380
	return get_irn_n(irn, n_be_IncSP_pred);
Michael Beck's avatar
BugFix:    
Michael Beck committed
381
382
}

383
384
void be_set_IncSP_pred(ir_node *incsp, ir_node *pred)
{
385
	assert(be_is_IncSP(incsp));
386
	set_irn_n(incsp, n_be_IncSP_pred, pred);
387
388
}

389
void be_set_IncSP_offset(ir_node *irn, int offset)
Sebastian Hack's avatar
Sebastian Hack committed
390
391
{
	assert(be_is_IncSP(irn));
Matthias Braun's avatar
Matthias Braun committed
392
	be_incsp_attr_t *a = (be_incsp_attr_t*)get_irn_generic_attr(irn);
Sebastian Hack's avatar
Sebastian Hack committed
393
394
	a->offset = offset;
}
395

396
int be_get_IncSP_offset(const ir_node *irn)
Sebastian Hack's avatar
Sebastian Hack committed
397
{
Sebastian Hack's avatar
Sebastian Hack committed
398
	assert(be_is_IncSP(irn));
Matthias Braun's avatar
Matthias Braun committed
399
400
	const be_incsp_attr_t *a
		= (const be_incsp_attr_t*)get_irn_generic_attr_const(irn);
Sebastian Hack's avatar
Sebastian Hack committed
401
402
	return a->offset;
}
Sebastian Hack's avatar
Sebastian Hack committed
403

404
unsigned be_get_IncSP_align(const ir_node *irn)
405
406
{
	assert(be_is_IncSP(irn));
Matthias Braun's avatar
Matthias Braun committed
407
408
	const be_incsp_attr_t *a
		= (const be_incsp_attr_t*)get_irn_generic_attr_const(irn);
409
410
411
	return a->align;
}

412
ir_node *be_new_Phi(ir_node *block, int n_ins, ir_node **ins, ir_mode *mode,
413
                    const arch_register_req_t *req)
414
{
Matthias Braun's avatar
Matthias Braun committed
415
416
	ir_graph *irg  = get_irn_irg(block);
	ir_node  *phi = new_ir_node(NULL, irg, block, op_Phi, mode, n_ins, ins);
417
	phi->attr.phi.u.backedge = new_backedge_arr(get_irg_obstack(irg), n_ins);
Matthias Braun's avatar
Matthias Braun committed
418
419
	struct obstack *obst = be_get_be_obst(irg);
	backend_info_t *info = be_get_info(phi);
420
	info->out_infos = NEW_ARR_DZ(reg_out_info_t, obst, 1);
421
	info->in_reqs   = be_allocate_in_reqs(irg, n_ins);
422
423

	info->out_infos[0].req = req;
Matthias Braun's avatar
Matthias Braun committed
424
	for (int i = 0; i < n_ins; ++i) {
425
		info->in_reqs[i] = req;
426
	}
427
	verify_new_node(phi);
428
	phi = optimize_node(phi);
429
430
431
	return phi;
}

432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
ir_node *be_new_Phi0(ir_node *const block, ir_mode *const mode, arch_register_req_t const *const req)
{
	ir_graph *const irg = get_irn_irg(block);
	ir_node  *const phi = new_ir_node(NULL, irg, block, op_Phi, mode, 0, NULL);
	struct obstack *const obst = be_get_be_obst(irg);
	backend_info_t *const info = be_get_info(phi);
	info->out_infos = NEW_ARR_DZ(reg_out_info_t, obst, 1);
	info->out_infos[0].req = req;
	return phi;
}

ir_node *be_complete_Phi(ir_node *const phi, unsigned const n_ins, ir_node **const ins)
{
	assert(is_Phi(phi) && get_Phi_n_preds(phi) == 0);

	ir_graph *const irg = get_irn_irg(phi);
	phi->attr.phi.u.backedge = new_backedge_arr(get_irg_obstack(irg), n_ins);
	set_irn_in(phi, n_ins, ins);

451
	arch_register_req_t const **const in_reqs = be_allocate_in_reqs(irg, n_ins);
452
453
454
455
456
457
458
	arch_register_req_t const  *const req     = arch_get_irn_register_req(phi);
	for (unsigned i = 0; i < n_ins; ++i) {
		in_reqs[i] = req;
	}
	backend_info_t *const info = be_get_info(phi);
	info->in_reqs = in_reqs;

459
	verify_new_node(phi);
460
461
462
	return optimize_node(phi);
}

463
void be_set_phi_reg_req(ir_node *node, const arch_register_req_t *req)
464
{
Matthias Braun's avatar
Matthias Braun committed
465
	assert(mode_is_data(get_irn_mode(node)));
466
467
	backend_info_t *info = be_get_info(node);
	info->out_infos[0].req = req;
Matthias Braun's avatar
Matthias Braun committed
468
	for (int i = 0, arity = get_irn_arity(node); i < arity; ++i) {
469
470
		info->in_reqs[i] = req;
	}
471
472
}

473
ir_node *be_new_Asm(dbg_info *const dbgi, ir_node *const block, int const n_ins, ir_node **const ins, arch_register_req_t const **const in_reqs, int const n_outs, ident *const text, void *const operands)
474
475
476
{
	ir_graph *const irg  = get_irn_irg(block);
	ir_node  *const asmn = new_ir_node(dbgi, irg, block, op_be_Asm, mode_T, n_ins, ins);
477
	be_info_init_irn(asmn, arch_irn_flags_none, in_reqs, n_outs);
478
479
480
481
482
483
484
485

	be_asm_attr_t *const attr = (be_asm_attr_t*)get_irn_generic_attr(asmn);
	attr->text     = text;
	attr->operands = operands;

	return asmn;
}

486
487
ir_node *be_new_Relocation(ir_graph *irg, unsigned kind, ir_entity *entity,
                           ir_mode *mode)
488
489
490
{
	ir_node *const block = get_irg_start_block(irg);
	ir_node *const node  = new_ir_node(NULL, irg, block, op_be_Relocation,
491
	                                   mode, 0, NULL);
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
	be_relocation_attr_t *const attr
		= (be_relocation_attr_t*)get_irn_generic_attr(node);
	attr->entity = entity;
	attr->kind   = kind;
	ir_node *const optimized = optimize_node(node);
	return optimized;
}

unsigned be_get_Relocation_kind(ir_node const* const node)
{
	assert(be_is_Relocation(node));
	be_relocation_attr_t const *const attr
		= (be_relocation_attr_t const*)get_irn_generic_attr_const(node);
	return attr->kind;
}

ir_entity *be_get_Relocation_entity(ir_node const* const node)
{
	assert(be_is_Relocation(node));
	be_relocation_attr_t const *const attr
		= (be_relocation_attr_t const*)get_irn_generic_attr_const(node);
	return attr->entity;
}

Christoph Mallon's avatar
Christoph Mallon committed
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
ir_node *be_new_Start(ir_graph *const irg, be_start_out const *const outs)
{
	ir_node *const block  = get_irg_start_block(irg);
	ir_node *const start  = new_ir_node(NULL, irg, block, op_be_Start, mode_T, 0, NULL);
	unsigned const n_regs = isa_if->n_registers;

	/* Count the number of outsputs. */
	unsigned k = 1; /* +1 for memory */
	for (unsigned i = 0; i != n_regs; ++i) {
		if (outs[i] != BE_START_NO)
			++k;
	}

	be_info_init_irn(start, arch_irn_flag_schedule_first, NULL, k);

	/* Set out requirements and registers. */
	unsigned l = 0;
	arch_set_irn_register_req_out(start, l++, arch_memory_req);
	arch_register_t const *const regs = isa_if->registers;
	for (unsigned i = 0; i != n_regs; ++i) {
		if (outs[i] != BE_START_NO) {
			arch_register_t     const *const reg = &regs[i];
			arch_register_req_t const *const req = outs[i] == BE_START_IGNORE
				? be_create_reg_req(be_get_be_obst(irg), reg, true)
				: reg->single_req;
			arch_set_irn_register_req_out(start, l, req);
			arch_set_irn_register_out(    start, l, reg);
			++l;
		}
	}
	assert(l == k);

	return start;
}

ir_node *be_get_Start_mem(ir_graph *const irg)
{
	ir_node *const start = get_irg_start(irg);
	return be_get_or_make_Proj_for_pn(start, 0);
}

ir_node *be_get_Start_proj(ir_graph *const irg, arch_register_t const *const reg)
{
	ir_node *const start = get_irg_start(irg);
	/* do a naive linear search... */
	be_foreach_out(start, i) {
		arch_register_t const *const out_reg = arch_get_irn_register_out(start, i);
		if (out_reg == reg)
			return be_get_or_make_Proj_for_pn(start, i);
	}
	panic("tried querying undefined register '%s' at Start", reg->name);
}

569
570
571
572
573
574
ir_node *be_new_Proj(ir_node *const pred, unsigned const pos)
{
	arch_register_req_t const *const req = arch_get_irn_register_req_out(pred, pos);
	return new_r_Proj(pred, req->cls->mode, pos);
}

575
576
577
578
579
580
ir_node *be_new_Proj_reg(ir_node *const pred, unsigned const pos, arch_register_t const *const reg)
{
	arch_set_irn_register_out(pred, pos, reg);
	return be_new_Proj(pred, pos);
}

581
582
583
584
585
586
ir_node *be_get_or_make_Proj_for_pn(ir_node *const irn, unsigned const pn)
{
	ir_node *const proj = get_Proj_for_pn(irn, pn);
	return proj ? proj : be_new_Proj(irn, pn);
}

587
588
589
/**
 * ir_op-Operation: dump a be node to file
 */
590
static void dump_node(FILE *f, const ir_node *irn, dump_reason_t reason)
591
{
592
593
	assert(is_be_node(irn));

594
	switch (reason) {
Matthias Braun's avatar
Matthias Braun committed
595
596
597
	case dump_node_opcode_txt:
		fputs(get_irn_opname(irn), f);
		break;
598
599
600
601
	case dump_node_mode_txt: {
		ir_mode *const mode = get_irn_mode(irn);
		if (mode != mode_ANY && mode != mode_T)
			fprintf(f, "%s", get_mode_name(mode));
Matthias Braun's avatar
Matthias Braun committed
602
		break;
603
	}
Matthias Braun's avatar
Matthias Braun committed
604
	case dump_node_nodeattr_txt:
605
		if (be_is_IncSP(irn)) {
Matthias Braun's avatar
Matthias Braun committed
606
607
			const be_incsp_attr_t *attr
				= (const be_incsp_attr_t*)get_irn_generic_attr_const(irn);
Matthias Braun's avatar
Matthias Braun committed
608
609
610
611
			fprintf(f, " [%d] ", attr->offset);
		}
		break;
	case dump_node_info_txt:
612
		if (be_is_IncSP(irn)) {
Matthias Braun's avatar
Matthias Braun committed
613
614
			const be_incsp_attr_t *a
				= (const be_incsp_attr_t*)get_irn_generic_attr_const(irn);
615
			fprintf(f, "align: %u\n", a->align);
Matthias Braun's avatar
Matthias Braun committed
616
			fprintf(f, "offset: %d\n", a->offset);
617
		} else if (be_is_MemPerm(irn)) {
618
			for (unsigned i = 0; i < be_get_MemPerm_entity_arity(irn); ++i) {
Matthias Braun's avatar
Matthias Braun committed
619
620
621
				ir_entity *in  = be_get_MemPerm_in_entity(irn, i);
				ir_entity *out = be_get_MemPerm_out_entity(irn, i);
				if (in != NULL)
622
					ir_fprintf(f, "\nin[%u]: %F\n", i, in);
Matthias Braun's avatar
Matthias Braun committed
623
				if (out != NULL)
624
					ir_fprintf(f, "\nout[%u]: %F\n", i, out);
625
			}
Matthias Braun's avatar
Matthias Braun committed
626
		}
627
		break;
628
629
630
	}
}

631
void be_copy_attr(ir_graph *const irg, ir_node const *const old_node, ir_node *const new_node)
Sebastian Hack's avatar
Sebastian Hack committed
632
{
633
634
	void const *const old_attr = get_irn_generic_attr_const(old_node);
	void       *const new_attr = get_irn_generic_attr(new_node);
Sebastian Hack's avatar
Sebastian Hack committed
635
	memcpy(new_attr, old_attr, get_op_attr_size(get_irn_op(old_node)));
636
637
638
639
640
641
642
643

	backend_info_t *const old_info = be_get_info(old_node);
	backend_info_t *const new_info = be_get_info(new_node);
	*new_info = *old_info;
	memset(&new_info->sched_info, 0, sizeof(new_info->sched_info));
	if (new_info->out_infos) {
		struct obstack *const obst = be_get_be_obst(irg);
		new_info->out_infos = DUP_ARR_D(reg_out_info_t, obst, new_info->out_infos);
Sebastian Hack's avatar
Sebastian Hack committed
644
	}
Sebastian Hack's avatar
Sebastian Hack committed
645
646
}

647
648
649
650
651
bool is_be_node(const ir_node *irn)
{
	return get_op_tag(get_irn_op(irn)) == be_op_tag;
}

652
653
654
655
static ir_op *new_be_op(unsigned code, const char *name, op_pin_state p,
                        irop_flags flags, op_arity opar, size_t attr_size)
{
	ir_op *res = new_ir_op(code, name, p, flags, opar, 0, attr_size);
Matthias Braun's avatar
Matthias Braun committed
656
	set_op_dump(res, dump_node);
657
	set_op_copy_attr(res, be_copy_attr);
658
	set_op_tag(res, be_op_tag);
659
660
661
	return res;
}

662
663
void be_init_op(void)
{
664
	assert(op_be_Perm == NULL);
Matthias Braun's avatar
Matthias Braun committed
665

Matthias Braun's avatar
Matthias Braun committed
666
	/* Acquire all needed opcodes. */
667
	unsigned const o = get_next_ir_opcodes(beo_last + 1);
668
669
670
671
672
673
674
675
	op_be_Asm        = new_be_op(o+beo_Asm,        "be_Asm",        op_pin_state_exc_pinned, irop_flag_none,                            oparity_any,      sizeof(be_asm_attr_t));
	op_be_Copy       = new_be_op(o+beo_Copy,       "be_Copy",       op_pin_state_exc_pinned, irop_flag_none,                            oparity_any,      sizeof(be_node_attr_t));
	op_be_CopyKeep   = new_be_op(o+beo_CopyKeep,   "be_CopyKeep",   op_pin_state_exc_pinned, irop_flag_keep,                            oparity_variable, sizeof(be_node_attr_t));
	op_be_IncSP      = new_be_op(o+beo_IncSP,      "be_IncSP",      op_pin_state_exc_pinned, irop_flag_none,                            oparity_any,      sizeof(be_incsp_attr_t));
	op_be_Keep       = new_be_op(o+beo_Keep,       "be_Keep",       op_pin_state_exc_pinned, irop_flag_keep,                            oparity_variable, sizeof(be_node_attr_t));
	op_be_MemPerm    = new_be_op(o+beo_MemPerm,    "be_MemPerm",    op_pin_state_exc_pinned, irop_flag_none,                            oparity_variable, sizeof(be_memperm_attr_t));
	op_be_Perm       = new_be_op(o+beo_Perm,       "be_Perm",       op_pin_state_exc_pinned, irop_flag_none,                            oparity_variable, sizeof(be_node_attr_t));
	op_be_Relocation = new_be_op(o+beo_Relocation, "be_Relocation", op_pin_state_floats,     irop_flag_constlike|irop_flag_start_block, oparity_any,      sizeof(be_relocation_attr_t));
Christoph Mallon's avatar
Christoph Mallon committed
676
	op_be_Start      = new_be_op(o+beo_Start,      "be_Start",      op_pin_state_pinned,     irop_flag_start_block,                     oparity_variable, sizeof(be_node_attr_t));
677
678
679
680
681
682
683
684
685

	set_op_attrs_equal(op_be_Asm,        be_asm_attr_equal);
	set_op_attrs_equal(op_be_Copy,       attrs_equal_be_node);
	set_op_attrs_equal(op_be_CopyKeep,   attrs_equal_be_node);
	set_op_attrs_equal(op_be_IncSP,      be_incsp_attrs_equal);
	set_op_attrs_equal(op_be_Keep,       attrs_equal_be_node);
	set_op_attrs_equal(op_be_MemPerm,    attrs_equal_be_node);
	set_op_attrs_equal(op_be_Perm,       attrs_equal_be_node);
	set_op_attrs_equal(op_be_Relocation, be_relocation_attrs_equal);
Matthias Braun's avatar
Matthias Braun committed
686
}
Matthias Braun's avatar
Matthias Braun committed
687
688
689

void be_finish_op(void)
{
Matthias Braun's avatar
Matthias Braun committed
690
691
692
	free_ir_op(op_be_Copy);     op_be_Copy     = NULL;
	free_ir_op(op_be_CopyKeep); op_be_CopyKeep = NULL;
	free_ir_op(op_be_IncSP);    op_be_IncSP    = NULL;
Matthias Braun's avatar
Matthias Braun committed
693
694
695
	free_ir_op(op_be_Keep);     op_be_Keep     = NULL;
	free_ir_op(op_be_MemPerm);  op_be_MemPerm  = NULL;
	free_ir_op(op_be_Perm);     op_be_Perm     = NULL;
Matthias Braun's avatar
Matthias Braun committed
696
}