bearch_amd64.c 24.5 KB
Newer Older
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
4
5
6
7
8
9
 */

/**
 * @file
 * @brief    The main amd64 backend driver file.
 */
10
#include "beabihelper.h"
Matthias Braun's avatar
Matthias Braun committed
11
12
#include "bearch.h"
#include "beflags.h"
13
#include "begnuas.h"
Matthias Braun's avatar
Matthias Braun committed
14
#include "beirg.h"
15
#include "belistsched.h"
Matthias Braun's avatar
Matthias Braun committed
16
17
18
19
#include "belower.h"
#include "bemodule.h"
#include "benode.h"
#include "besched.h"
20
21
22
#include "bespillslots.h"
#include "bespillutil.h"
#include "bestack.h"
Matthias Braun's avatar
Matthias Braun committed
23
24
#include "be_t.h"
#include "debug.h"
Matthias Braun's avatar
Matthias Braun committed
25
#include "panic.h"
26
#include "irarch_t.h"
27
#include "ircons_t.h"
Matthias Braun's avatar
Matthias Braun committed
28
29
30
31
#include "irdump.h"
#include "irgmod.h"
#include "irgwalk.h"
#include "iropt_t.h"
32
#include "irprog_t.h"
Matthias Braun's avatar
Matthias Braun committed
33
#include "lower_alloc.h"
Matthias Braun's avatar
Matthias Braun committed
34
35
#include "lower_builtins.h"
#include "lower_calls.h"
Tobias Rapp's avatar
Tobias Rapp committed
36
#include "lower_mode_b.h"
Matthias Braun's avatar
Matthias Braun committed
37
#include "util.h"
38
39
40

#include "bearch_amd64_t.h"

41
#include "amd64_finish.h"
42
43
44
45
#include "amd64_new_nodes.h"
#include "gen_amd64_regalloc_if.h"
#include "amd64_transform.h"
#include "amd64_emitter.h"
46
#include "amd64_cconv.h"
47
48
49
50
51

DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

static ir_entity *amd64_get_frame_entity(const ir_node *node)
{
52
53
	if (!is_amd64_irn(node))
		return NULL;
Matthias Braun's avatar
Matthias Braun committed
54
55
56
57
	if (!amd64_has_addr_attr(node))
		return NULL;
	const amd64_addr_attr_t *attr = get_amd64_addr_attr_const(node);
	ir_entity *entity = attr->addr.immediate.entity;
58
59
	if (entity == NULL)
		return NULL;
60
61
62
63
64
65
66
67
	ir_type *owner = get_entity_owner(entity);
	if (is_frame_type(owner))
		return entity;
	ir_graph *irg = get_irn_irg(node);
	be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
	if (owner == layout->arg_type)
		return entity;
	return NULL;
68
69
}

70
71
72
73
74
75
76
77
78
79
80
static int get_insn_mode_bytes(amd64_insn_mode_t insn_mode)
{
	switch (insn_mode) {
	case INSN_MODE_8:  return 1;
	case INSN_MODE_16: return 2;
	case INSN_MODE_32: return 4;
	case INSN_MODE_64: return 8;
	}
	panic("bad insn mode");
}

81
82
83
84
/**
 * This function is called by the generic backend to correct offsets for
 * nodes accessing the stack.
 */
Matthias Braun's avatar
Matthias Braun committed
85
static void amd64_set_frame_offset(ir_node *node, int offset)
86
{
87
88
	if (!is_amd64_irn(node))
		return;
Matthias Braun's avatar
Matthias Braun committed
89
90
	amd64_addr_attr_t *attr = get_amd64_addr_attr(node);
	attr->addr.immediate.offset += offset;
91
92
93
	if (is_amd64_PopAM(node)) {
		ir_graph          *irg    = get_irn_irg(node);
		be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
Matthias Braun's avatar
Matthias Braun committed
94
95
		if (layout->sp_relative)
			attr->addr.immediate.offset -= get_insn_mode_bytes(attr->insn_mode);
96
	}
97
98
}

99
static int amd64_get_sp_bias(const ir_node *node)
100
{
101
	if (is_amd64_PushAM(node)) {
Matthias Braun's avatar
Matthias Braun committed
102
103
		const amd64_addr_attr_t *attr = get_amd64_addr_attr_const(node);
		return get_insn_mode_bytes(attr->insn_mode);
104
105
	} else if (is_amd64_PushRbp(node)) {
		/* 64-bit register size */
106
		return AMD64_REGISTER_SIZE;
107
	} else if (is_amd64_PopAM(node)) {
Matthias Braun's avatar
Matthias Braun committed
108
109
		const amd64_addr_attr_t *attr = get_amd64_addr_attr_const(node);
		return -get_insn_mode_bytes(attr->insn_mode);
110
111
	} else if (is_amd64_Leave(node)) {
		return SP_BIAS_RESET;
112
	}
113

114
115
116
117
118
119
	return 0;
}

/* fill register allocator interface */

static const arch_irn_ops_t amd64_irn_ops = {
120
121
122
	.get_frame_entity = amd64_get_frame_entity,
	.set_frame_offset = amd64_set_frame_offset,
	.get_sp_bias      = amd64_get_sp_bias,
123
124
};

125
static void amd64_before_ra(ir_graph *irg)
126
{
127
	be_sched_fix_flags(irg, &amd64_reg_classes[CLASS_amd64_flags], NULL, NULL, NULL);
128
129

	be_add_missing_keeps(irg);
130
131
}

132
static const arch_register_req_t amd64_requirement_gp = {
133
134
135
136
137
138
	.cls             = &amd64_reg_classes[CLASS_amd64_gp],
	.limited         = NULL,
	.type            = arch_register_req_type_normal,
	.other_same      = 0,
	.other_different = 0,
	.width           = 1,
139
140
141
142
};

static const unsigned amd64_limited_gp_rsp [] = { (1 << REG_GP_RSP) };
static const arch_register_req_t amd64_single_reg_req_gp_rsp = {
143
144
145
146
147
148
	.type            = arch_register_req_type_limited,
	.cls             = &amd64_reg_classes[CLASS_amd64_gp],
	.limited         = amd64_limited_gp_rsp,
	.other_same      = 0,
	.other_different = 0,
	.width           = 1,
149
150
151
152
153
154
155
156
157
158
};

static const arch_register_req_t *am_pushpop_base_reqs[] = {
	&amd64_single_reg_req_gp_rsp,
	&amd64_requirement_gp,
	&arch_no_requirement,
};

static ir_node *create_push(ir_node *node, ir_node *schedpoint, ir_node *sp,
                            ir_node *mem, ir_entity *ent)
159
160
161
162
163
164
{
	dbg_info *dbgi  = get_irn_dbg_info(node);
	ir_node  *block = get_nodes_block(node);
	ir_graph *irg   = get_irn_irg(node);
	ir_node  *frame = get_irg_frame(irg);

Matthias Braun's avatar
Matthias Braun committed
165
166
	amd64_addr_t addr;
	memset(&addr, 0, sizeof(addr));
167
	addr.base_input       = 1;
Matthias Braun's avatar
Matthias Braun committed
168
169
	addr.index_input      = NO_INPUT;
	addr.immediate.entity = ent;
170
171
	ir_node *in[] = { sp, frame, mem };
	ir_node *push = new_bd_amd64_PushAM(dbgi, block, ARRAY_SIZE(in), in,
Matthias Braun's avatar
Matthias Braun committed
172
	                                    INSN_MODE_64, addr);
173
	arch_set_irn_register_reqs_in(push, am_pushpop_base_reqs);
174
175
176
177
178
179
180
181
182
183
184
	sched_add_before(schedpoint, push);
	return push;
}

static ir_node *create_pop(ir_node *node, ir_node *schedpoint, ir_node *sp, ir_entity *ent)
{
	dbg_info *dbgi  = get_irn_dbg_info(node);
	ir_node  *block = get_nodes_block(node);
	ir_graph *irg   = get_irn_irg(node);
	ir_node  *frame = get_irg_frame(irg);

Matthias Braun's avatar
Matthias Braun committed
185
186
	amd64_addr_t addr;
	memset(&addr, 0, sizeof(addr));
187
	addr.base_input  = 1;
Matthias Braun's avatar
Matthias Braun committed
188
189
	addr.index_input = NO_INPUT;
	addr.immediate.entity = ent;
190
191
192
	ir_node *in[] = { sp, frame, get_irg_no_mem(irg) };

	ir_node *pop = new_bd_amd64_PopAM(dbgi, block, ARRAY_SIZE(in), in,
Matthias Braun's avatar
Matthias Braun committed
193
	                                  INSN_MODE_64, addr);
194
	arch_set_irn_register_reqs_in(pop, am_pushpop_base_reqs);
195
196
197
198
199
200
201
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
	sched_add_before(schedpoint, pop);

	return pop;
}

static ir_node* create_spproj(ir_node *pred, int pos)
{
	const arch_register_t *spreg = &amd64_registers[REG_RSP];
	ir_mode               *spmode = spreg->reg_class->mode;
	ir_node               *sp     = new_r_Proj(pred, spmode, pos);
	arch_set_irn_register(sp, spreg);
	return sp;
}

/**
 * Transform MemPerm, currently we do this the ugly way and produce
 * push/pop into/from memory cascades. This is possible without using
 * any registers.
 */
static void transform_MemPerm(ir_node *node)
{
	ir_node  *block = get_nodes_block(node);
	ir_graph *irg   = get_irn_irg(node);
	ir_node  *sp    = be_get_initial_reg_value(irg, &amd64_registers[REG_RSP]);
	int       arity = be_get_MemPerm_entity_arity(node);
	ir_node **pops  = ALLOCAN(ir_node*, arity);
	ir_node  *in[1];
	ir_node  *keep;
	int       i;

	/* create Pushs */
	for (i = 0; i < arity; ++i) {
		ir_entity *inent = be_get_MemPerm_in_entity(node, i);
		ir_entity *outent = be_get_MemPerm_out_entity(node, i);
		ir_type *enttype = get_entity_type(inent);
		unsigned entsize = get_type_size_bytes(enttype);
		unsigned entsize2 = get_type_size_bytes(get_entity_type(outent));
		ir_node *mem = get_irn_n(node, i + 1);
		ir_node *push;

		/* work around cases where entities have different sizes */
		if (entsize2 < entsize)
			entsize = entsize2;
		/* spillslot should be 64bit size */
		assert(entsize == 8);

		push = create_push(node, node, sp, mem, inent);
		sp = create_spproj(push, pn_amd64_PushAM_stack);
		set_irn_n(node, i, new_r_Bad(irg, mode_X));
	}

	/* create pops */
Tobias Rapp's avatar
Tobias Rapp committed
247
	for (i = arity; i-- > 0; ) {
248
249
250
251
252
253
254
255
256
257
258
		ir_entity *inent = be_get_MemPerm_in_entity(node, i);
		ir_entity *outent = be_get_MemPerm_out_entity(node, i);
		ir_type *enttype = get_entity_type(outent);
		unsigned entsize = get_type_size_bytes(enttype);
		unsigned entsize2 = get_type_size_bytes(get_entity_type(inent));

		/* work around cases where entities have different sizes */
		if (entsize2 < entsize)
			entsize = entsize2;
		assert(entsize == 8);

Tobias Rapp's avatar
Tobias Rapp committed
259
		ir_node *pop = create_pop(node, node, sp, outent);
260
261
262
263
264
265
266
267
268
269
270
		sp = create_spproj(pop, pn_amd64_PopAM_stack);
		pops[i] = pop;
	}

	in[0] = sp;
	keep  = be_new_Keep(block, 1, in);
	sched_replace(node, keep);

	/* exchange memprojs */
	foreach_out_edge_safe(node, edge) {
		ir_node *proj = get_edge_src_irn(edge);
271
		int p = get_Proj_num(proj);
272
273
274
275

		assert(p < arity);

		set_Proj_pred(proj, pops[p]);
276
		set_Proj_num(proj, pn_amd64_PopAM_M);
277
278
279
280
281
282
	}

	/* remove memperm */
	kill_node(node);
}

283
284
285
286
static void amd64_after_ra_walker(ir_node *block, void *data)
{
	(void) data;

287
	sched_foreach_reverse_safe(block, node) {
Matthias Braun's avatar
Matthias Braun committed
288
		if (be_is_MemPerm(node)) {
289
			transform_MemPerm(node);
290
291
292
293
		}
	}
}

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/**
 * rewrite unsigned long -> float/double conversion
 * x86_64 only has a signed conversion
 */
static void rewrite_unsigned_float_Conv(ir_node *node)
{
	ir_graph *irg        = get_irn_irg(node);
	dbg_info *dbgi       = get_irn_dbg_info(node);
	ir_node *lower_block = get_nodes_block(node);
	ir_mode *dest_mode   = get_irn_mode(node);

	part_block(node);

	ir_node *block       = get_nodes_block(node);
	ir_node *unsigned_x  = get_Conv_op(node);
	ir_mode *mode_u      = get_irn_mode(unsigned_x);
	ir_mode *mode_s      = find_signed_mode(mode_u);
	ir_node *signed_x    = new_rd_Conv(dbgi, block, unsigned_x, mode_s);
	ir_node *zero        = new_r_Const_null(irg, mode_s);
313
	collect_new_start_block_node(zero);
314
315
316
317
318
319
320
321
322
323
324
325
	ir_node *cmp         = new_rd_Cmp(dbgi, block, signed_x, zero,
	                                 ir_relation_less);
	ir_node *cond        = new_rd_Cond(dbgi, block, cmp);
	ir_node *proj_true   = new_r_Proj(cond, mode_X, pn_Cond_true);
	ir_node *proj_false  = new_r_Proj(cond, mode_X, pn_Cond_false);
	ir_node *in_true[1]  = { proj_true };
	ir_node *in_false[1] = { proj_false };

	/* true block: Do some arithmetic to use the signed conversion */
	ir_node *true_block  = new_r_Block(irg, ARRAY_SIZE(in_true), in_true);
	ir_node *true_jmp    = new_r_Jmp(true_block);
	ir_node *one         = new_r_Const_one(irg, mode_u);
326
	collect_new_start_block_node(one);
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
	ir_node *and         = new_r_And(true_block, unsigned_x, one, mode_u);
	ir_node *shr         = new_r_Shr(true_block, unsigned_x, one, mode_u);
	ir_node *or          = new_r_Or(true_block, and, shr, mode_u);
	ir_node *or_signed   = new_rd_Conv(dbgi, true_block, or, mode_s);
	ir_node *half        = new_rd_Conv(dbgi, true_block, or_signed, dest_mode);
	ir_node *true_res    = new_r_Add(true_block, half, half, dest_mode);

	/* false block: Simply convert to floating point */
	ir_node *false_block = new_r_Block(irg, ARRAY_SIZE(in_false), in_false);
	ir_node *false_jmp   = new_r_Jmp(false_block);
	ir_node *false_res   = new_rd_Conv(dbgi, false_block, signed_x, dest_mode);

	/* lower block */
	ir_node *lower_in[2] = { true_jmp, false_jmp };
	ir_node *phi_in[2]   = { true_res, false_res };

	set_irn_in(lower_block, ARRAY_SIZE(lower_in), lower_in);
	ir_node *phi = new_r_Phi(lower_block, ARRAY_SIZE(phi_in), phi_in,
	                         dest_mode);
346
	collect_new_phi_node(phi);
347
348
349
	exchange(node, phi);
}

350
351
352
353
354
static ir_node *create_conv_const(ir_graph *irg, ir_mode *src_mode)
{
	assert(mode_is_float(src_mode));

	ir_node *result = NULL;
355
	if (get_mode_size_bits(src_mode) == 32) {
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
		double fconst = 1593835520;
		ir_tarval *tv = new_tarval_from_double(fconst, src_mode);
		result        = new_r_Const(irg, tv);
	} else if (get_mode_size_bits(src_mode) == 64) {
		double dconst = 1138753536;
		ir_tarval *tv = new_tarval_from_double(dconst, src_mode);
		result        = new_r_Const(irg, tv);
	}
	return result;
}

/* Creates a 64-bit constant with only the sign bit set,
 * i.e. returns 0x8000000000000000
 */
static ir_node *create_sign_bit_const(ir_graph *irg)
{
372
	ir_tarval *sign_tv = create_sign_tv(mode_Ls);
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
	return new_r_Const(irg, sign_tv);
}

/* rewrite float/double -> unsigned long conversion
 * x86_64 only has a signed conversion
 */
static void rewrite_float_unsigned_Conv(ir_node *node)
{
	ir_graph *irg        = get_irn_irg(node);
	dbg_info *dbgi       = get_irn_dbg_info(node);
	ir_node *lower_block = get_nodes_block(node);
	ir_mode *dest_mode   = get_irn_mode(node);

	part_block(node);

	ir_node *block       = get_nodes_block(node);
	ir_node *fp_x        = get_Conv_op(node);
	ir_mode *src_mode    = get_irn_mode(fp_x);
	ir_node *fp_const    = create_conv_const(irg, src_mode);
392
	collect_new_start_block_node(fp_const);
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408

	/* Test if the sign bit is needed */
	ir_node *cmp         = new_rd_Cmp(dbgi, block, fp_x, fp_const,
	                                 ir_relation_greater_equal);
	ir_node *cond        = new_rd_Cond(dbgi, block, cmp);
	ir_node *proj_true   = new_r_Proj(cond, mode_X, pn_Cond_true);
	ir_node *proj_false  = new_r_Proj(cond, mode_X, pn_Cond_false);
	ir_node *in_true[1]  = { proj_true };
	ir_node *in_false[1] = { proj_false };

	/* true block: Do some arithmetic to use the signed conversion */
	ir_node *true_block  = new_r_Block(irg, ARRAY_SIZE(in_true), in_true);
	ir_node *true_jmp    = new_r_Jmp(true_block);
	ir_node *sub         = new_r_Sub(true_block, fp_const, fp_x, src_mode);
	ir_node *sub_conv    = new_rd_Conv(dbgi, true_block, sub, mode_Ls);
	ir_node *sign_bit    = create_sign_bit_const(irg);
409
	collect_new_start_block_node(sign_bit);
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
	ir_node *xor         = new_r_Eor(true_block, sub_conv, sign_bit, mode_Ls);
	ir_node *true_res    = new_rd_Conv(dbgi, true_block, xor, dest_mode);

	/* false block: Simply convert */
	ir_node *false_block  = new_r_Block(irg, ARRAY_SIZE(in_false), in_false);
	ir_node *false_jmp    = new_r_Jmp(false_block);
	ir_node *false_signed = new_rd_Conv(dbgi, false_block, fp_x, mode_Ls);
	ir_node *false_res    = new_rd_Conv(dbgi, false_block, false_signed,
	                                    dest_mode);

	/* lower block */
	ir_node *lower_in[2] = { true_jmp, false_jmp };
	ir_node *phi_in[2]   = { true_res, false_res };

	set_irn_in(lower_block, ARRAY_SIZE(lower_in), lower_in);
	ir_node *phi = new_r_Phi(lower_block, ARRAY_SIZE(phi_in), phi_in,
	                         dest_mode);
427
	collect_new_phi_node(phi);
428
429
430
	exchange(node, phi);
}

431
432
433
434
435
436
437
438
439
440
441
442
443
444
static bool amd64_rewrite_Conv(ir_node *node)
{
	ir_mode *to_mode    = get_irn_mode(node);
	ir_node *op         = get_Conv_op(node);
	ir_mode *from_mode  = get_irn_mode(op);
	bool     to_float   = mode_is_float(to_mode);
	bool     from_float = mode_is_float(from_mode);

	if (to_float && !from_float && !mode_is_signed(from_mode)
	    && get_mode_size_bits(from_mode) == 64) {
		rewrite_unsigned_float_Conv(node);
		return true;
	} else if (from_float && !to_float && !mode_is_signed(to_mode)
	           && get_mode_size_bits(to_mode) == 64) {
445
		rewrite_float_unsigned_Conv(node);
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
		return true;
	}

	return false;
}

static void amd64_intrinsics_walker(ir_node *node, void *data)
{
	bool *changed = (bool*)data;
	if (is_Conv(node)) {
		if (amd64_rewrite_Conv(node))
			*changed = true;
	}
}

static void amd64_handle_intrinsics(ir_graph *irg)
{
	ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST);
464
	collect_phiprojs_and_start_block_nodes(irg);
465
466
467
468
469
470
471
472
473
474
475
476
477
	bool changed = false;
	irg_walk_graph(irg, amd64_intrinsics_walker, NULL, &changed);
	ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST);

	if (changed) {
		confirm_irg_properties(irg,
		        IR_GRAPH_PROPERTY_NO_BADS
		        | IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES
		        | IR_GRAPH_PROPERTY_MANY_RETURNS
		        | IR_GRAPH_PROPERTY_ONE_RETURN);
	}
}

478
479
static void amd64_set_frame_entity(ir_node *node, ir_entity *entity,
                                   const ir_type *type)
480
{
481
	(void)type;
Matthias Braun's avatar
Matthias Braun committed
482
	assert(is_amd64_Store(node) || is_amd64_Mov(node)
Tobias Rapp's avatar
Tobias Rapp committed
483
484
	    || is_amd64_Movs(node) || is_amd64_xMovs(node)
	    || is_amd64_xStores(node));
Matthias Braun's avatar
Matthias Braun committed
485
486
	amd64_addr_attr_t *attr = get_amd64_addr_attr(node);
	attr->addr.immediate.entity = entity;
487
488
}

489
490
static bool is_frame_load(const ir_node *node)
{
Tobias Rapp's avatar
Tobias Rapp committed
491
	return is_amd64_Mov(node) || is_amd64_Movs(node) || is_amd64_xMovs(node);
492
493
}

494
495
496
497
498
/**
 * Collects nodes that need frame entities assigned.
 */
static void amd64_collect_frame_entity_nodes(ir_node *node, void *data)
{
499
	/* we are only interested to report Load nodes */
500
	if (!is_frame_load(node))
Matthias Braun's avatar
Matthias Braun committed
501
502
		return;

Matthias Braun's avatar
Matthias Braun committed
503
504
	const amd64_addr_attr_t *attr = get_amd64_addr_attr_const(node);
	if (attr->needs_frame_ent) {
505
		be_fec_env_t  *env   = (be_fec_env_t*)data;
Matthias Braun's avatar
Matthias Braun committed
506
		const ir_mode *mode  = mode_Lu; /* TODO: improve */
507
508
		const ir_type *type  = get_type_for_mode(mode);
		be_load_needs_frame_entity(env, node, type);
509
510
511
	}
}

512
513
514
515
516
517
518
519
520
521
static int determine_rbp_input(ir_node *ret)
{
	const arch_register_t *bp = &amd64_registers[REG_RSP];
	foreach_irn_in(ret, i, input) {
		if (arch_get_irn_register(input) == bp)
			return i;
	}
    panic("no rbp input found at %+F", ret);
}

522
523
524
static void introduce_epilogue(ir_node *ret)
{
	const arch_register_t *sp         = &amd64_registers[REG_RSP];
525
	const arch_register_t *bp         = &amd64_registers[REG_RBP];
526
527
528
529
530
531
	ir_graph              *irg        = get_irn_irg(ret);
	ir_node               *start      = get_irg_start(irg);
	ir_node               *block      = get_nodes_block(start);
	ir_type               *frame_type = get_irg_frame_type(irg);
	unsigned               frame_size = get_type_size_bytes(frame_type);
	be_stack_layout_t     *layout     = be_get_irg_stack_layout(irg);
532
	ir_node               *first_sp   = get_irn_n(ret, n_amd64_Return_stack);
533
	ir_node               *curr_sp    = first_sp;
534
	ir_mode               *mode_gp    = mode_Lu;
535

536
	if (!layout->sp_relative) {
537
538
539
540
541
542
543
544
545
546
547
		int n_rbp = determine_rbp_input(ret);
		ir_node *curr_bp = get_irn_n(ret, n_rbp);

		ir_node *leave = new_bd_amd64_Leave(NULL, block, curr_bp);
		curr_bp        = new_r_Proj(leave, mode_gp, pn_amd64_Leave_frame);
		curr_sp        = new_r_Proj(leave, mode_gp, pn_amd64_Leave_stack);
		arch_set_irn_register(curr_bp, bp);
		arch_set_irn_register(curr_sp, sp);
		sched_add_before(ret, leave);

		set_irn_n(ret, n_rbp, curr_bp);
548
549
	} else {
		if (frame_size > 0) {
550
551
			ir_node *incsp = amd64_new_IncSP(block, curr_sp,
			                                 -(int)frame_size, 0);
552
553
554
555
			sched_add_before(ret, incsp);
			curr_sp = incsp;
		}
	}
556
	set_irn_n(ret, n_amd64_Return_stack, curr_sp);
557
558
559
560
561

	/* keep verifier happy... */
	if (get_irn_n_edges(first_sp) == 0 && is_Proj(first_sp)) {
		kill_node(first_sp);
	}
562
563
564
565
566
}

static void introduce_prologue_epilogue(ir_graph *irg)
{
	const arch_register_t *sp         = &amd64_registers[REG_RSP];
567
	const arch_register_t *bp         = &amd64_registers[REG_RBP];
568
569
570
571
572
573
	ir_node               *start      = get_irg_start(irg);
	ir_node               *block      = get_nodes_block(start);
	ir_type               *frame_type = get_irg_frame_type(irg);
	unsigned               frame_size = get_type_size_bytes(frame_type);
	be_stack_layout_t     *layout     = be_get_irg_stack_layout(irg);
	ir_node               *initial_sp = be_get_initial_reg_value(irg, sp);
574
575
576
577
	ir_mode               *mode_gp    = mode_Lu;

	if (is_Deleted(start))
		return;
578
579

	if (!layout->sp_relative) {
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
		/* push rbp */
		ir_node *push = new_bd_amd64_PushRbp(NULL, block, initial_sp);
		ir_node *curr_sp = new_r_Proj(push, mode_gp, pn_amd64_PushRbp_stack);

		arch_set_irn_register(curr_sp, sp);
		sched_add_after(start, push);

		/* move rsp to rbp */
		ir_node *const curr_bp = be_new_Copy(block, curr_sp);
		sched_add_after(push, curr_bp);
		be_set_constr_single_reg_out(curr_bp, 0,
		                             bp, arch_register_req_type_ignore);
		curr_sp = be_new_CopyKeep_single(block, curr_sp, curr_bp);
		sched_add_after(curr_bp, curr_sp);
		be_set_constr_single_reg_out(curr_sp, 0,
		                             sp, arch_register_req_type_produces_sp);

597
		ir_node *incsp = amd64_new_IncSP(block, curr_sp, frame_size, 0);
598
599
600
601
602
603
604
605
606
607
		sched_add_after(curr_sp, incsp);

		/* make sure the initial IncSP is really used by someone */
		if (get_irn_n_edges(incsp) <= 1) {
			ir_node *in[] = { incsp };
			ir_node *keep = be_new_Keep(block, 1, in);
			sched_add_after(incsp, keep);
		}

		layout->initial_bias = -8;
608
609
	} else {
		if (frame_size > 0) {
610
611
			ir_node *const incsp = amd64_new_IncSP(block, initial_sp,
			                                       frame_size, 0);
612
613
614
615
616
617
			sched_add_after(start, incsp);
		}
	}

	/* introduce epilogue for every return node */
	foreach_irn_in(get_irg_end_block(irg), i, ret) {
618
		assert(is_amd64_Return(ret));
619
620
621
622
		introduce_epilogue(ret);
	}
}

623
624
625
/**
 * Called immediatly before emit phase.
 */
626
static void amd64_finish_graph(ir_graph *irg)
627
{
628
	be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
629
	bool               at_begin     = stack_layout->sp_relative;
630
	be_fec_env_t      *fec_env      = be_new_frame_entity_coalescer(irg);
631
632
633

	/* create and coalesce frame entities */
	irg_walk_graph(irg, NULL, amd64_collect_frame_entity_nodes, fec_env);
634
	be_assign_entities(fec_env, amd64_set_frame_entity, at_begin);
635
	be_free_frame_entity_coalescer(fec_env);
636

637
	irg_block_walk_graph(irg, NULL, amd64_after_ra_walker, NULL);
638

639
640
	introduce_prologue_epilogue(irg);

641
642
643
	/* fix stack entity offsets */
	be_abi_fix_stack_nodes(irg);
	be_abi_fix_stack_bias(irg);
644
645
646

	/* Fix 2-address code constraints. */
	amd64_finish_irg(irg);
647
648
649

	/* emit code */
	amd64_emit_function(irg);
650
}
651

652
extern const arch_isa_if_t amd64_isa_if;
653
static amd64_isa_t amd64_isa_template = {
654
655
656
657
658
659
660
661
662
663
	.base = {
		.impl               = &amd64_isa_if,
		.n_registers        = N_AMD64_REGISTERS,
		.registers          = amd64_registers,
		.n_register_classes = N_AMD64_CLASSES,
		.register_classes   = amd64_reg_classes,
		.sp                 = &amd64_registers[REG_RSP],
		.bp                 = &amd64_registers[REG_RBP],
		.spill_cost         = 7,
		.reload_cost        = 5,
664
665
666
	},
};

667
static void amd64_init(void)
668
669
670
{
	amd64_register_init();
	amd64_create_opcodes(&amd64_irn_ops);
671
	amd64_cconv_init();
672
673
}

Matthias Braun's avatar
Matthias Braun committed
674
675
676
677
678
static void amd64_finish(void)
{
	amd64_free_opcodes();
}

679
static arch_env_t *amd64_begin_codegeneration(void)
680
681
{
	amd64_isa_t *isa = XMALLOC(amd64_isa_t);
682
683
	*isa             = amd64_isa_template;
	isa->constants   = pmap_create();
684

685
	return &isa->base;
686
687
688
689
690
}

/**
 * Closes the output file and frees the ISA structure.
 */
691
static void amd64_end_codegeneration(void *self)
692
{
693
694
695
	amd64_isa_t *isa = (amd64_isa_t*)self;
	pmap_destroy(isa->constants);
	free(isa);
696
697
}

698
699
700
701
/**
 * prepare graph and perform code selection.
 */
static void amd64_prepare_graph(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
702
{
703
704
705
706
	be_timer_push(T_CODEGEN);
	amd64_transform_graph(irg);
	be_timer_pop(T_CODEGEN);

707
	be_dump(DUMP_BE, irg, "code-selection");
Matthias Braun's avatar
Matthias Braun committed
708
709
}

710
711
static void amd64_lower_for_target(void)
{
712
	/* lower compound param handling */
713
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
714
	be_after_irp_transform("lower-calls");
715

716
	foreach_irp_irg(i, irg) {
717
		lower_switch(irg, 4, 256, mode_Iu);
718
		be_after_transform(irg, "lower-switch");
719
720
	}

Tobias Rapp's avatar
Tobias Rapp committed
721
722
723
724
	foreach_irp_irg(i, irg) {
		/* lower for mode_b stuff */
		ir_lower_mode_b(irg, mode_Lu);
		be_after_transform(irg, "lower-modeb");
Matthias Braun's avatar
Matthias Braun committed
725
726
		lower_alloc(irg, AMD64_PO2_STACK_ALIGNMENT);
		be_after_transform(irg, "lower-alloc");
Tobias Rapp's avatar
Tobias Rapp committed
727
728
	}

729
	foreach_irp_irg(i, irg) {
730
731
732
733
		/* Turn all small CopyBs into loads/stores, and turn all bigger
		 * CopyBs into memcpy calls, because we cannot handle CopyB nodes
		 * during code generation yet.
		 * TODO:  Adapt this once custom CopyB handling is implemented. */
734
		lower_CopyB(irg, 64, 65, true);
735
		be_after_transform(irg, "lower-copyb");
736
	}
737

738
739
740
741
742
743
	ir_builtin_kind supported[1];
	size_t  s = 0;
	supported[s++] = ir_bk_saturating_increment;

	assert(s <= ARRAY_SIZE(supported));
	lower_builtins(s, supported);
744
	be_after_irp_transform("lower-builtins");
745
746
}

747
748
749
static int amd64_is_mux_allowed(ir_node *sel, ir_node *mux_false,
                                ir_node *mux_true)
{
Matthias Braun's avatar
Matthias Braun committed
750
751
752
	/* optimizable by middleend */
	if (ir_is_optimizable_mux(sel, mux_false, mux_true))
		return true;
753
754
755
	return false;
}

756
static const ir_settings_arch_dep_t amd64_arch_dep = {
757
758
759
760
761
762
763
	.also_use_subs        = true,
	.maximum_shifts       = 4,
	.highest_shift_amount = 63,
	.evaluate             = NULL,
	.allow_mulhs          = true,
	.allow_mulhu          = true,
	.max_bits_for_mulh    = 32,
764
};
765
766
767
768
769
/**
 * Returns the libFirm configuration parameter for this backend.
 */
static const backend_params *amd64_get_backend_params(void) {
	static backend_params p = {
770
771
772
773
774
775
776
777
778
779
780
781
782
		.byte_order_big_endian         = false,
		.pic_supported                 = false,
		.unaligned_memaccess_supported = true,
		.modulo_shift                  = 32,
		.dep_param                     = &amd64_arch_dep,
		.allow_ifconv                  = amd64_is_mux_allowed,
		.machine_size                  = 64,
		.mode_float_arithmetic         = NULL,  /* will be set later */
		.type_long_long                = NULL,  /* will be set later */
		.type_unsigned_long_long       = NULL,  /* will be set later */
		.type_long_double              = NULL,  /* will be set later */
		.stack_param_align             = 8,
		.float_int_overflow            = ir_overflow_indefinite
783
784
785
786
787
788
789
790
791
792
793
	};
	return &p;
}

static int amd64_is_valid_clobber(const char *clobber)
{
	(void) clobber;
	return 0;
}

const arch_isa_if_t amd64_isa_if = {
794
795
796
797
798
799
800
801
802
803
804
805
806
	.init                 = amd64_init,
	.finish               = amd64_finish,
	.get_params           = amd64_get_backend_params,
	.lower_for_target     = amd64_lower_for_target,
	.is_valid_clobber     = amd64_is_valid_clobber,
	.begin_codegeneration = amd64_begin_codegeneration,
	.end_codegeneration   = amd64_end_codegeneration,
	.new_spill            = amd64_new_spill,
	.new_reload           = amd64_new_reload,
	.handle_intrinsics    = amd64_handle_intrinsics,
	.prepare_graph        = amd64_prepare_graph,
	.before_ra            = amd64_before_ra,
	.emit                 = amd64_finish_graph,
807
808
};

Matthias Braun's avatar
Matthias Braun committed
809
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_amd64)
810
811
812
813
void be_init_arch_amd64(void)
{
	be_register_isa_if("amd64", &amd64_isa_if);
	FIRM_DBG_REGISTER(dbg, "firm.be.amd64.cg");
814
815

	amd64_init_finish();
816
817
	amd64_init_transform();
}