bearch_amd64.c 24.2 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 "ircons_t.h"
Matthias Braun's avatar
Matthias Braun committed
27
28
29
30
#include "irdump.h"
#include "irgmod.h"
#include "irgwalk.h"
#include "iropt_t.h"
31
#include "irprog_t.h"
Matthias Braun's avatar
Matthias Braun committed
32
33
#include "lower_builtins.h"
#include "lower_calls.h"
Tobias Rapp's avatar
Tobias Rapp committed
34
#include "lower_mode_b.h"
Matthias Braun's avatar
Matthias Braun committed
35
#include "util.h"
36
37
38

#include "bearch_amd64_t.h"

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

DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

static ir_entity *amd64_get_frame_entity(const ir_node *node)
{
50
51
	if (!is_amd64_irn(node))
		return NULL;
Matthias Braun's avatar
Matthias Braun committed
52
53
54
55
	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;
56
57
	if (entity == NULL)
		return NULL;
58
59
60
61
62
63
64
65
	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;
66
67
}

68
69
70
71
72
73
74
75
76
77
78
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");
}

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

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

112
113
114
115
116
117
118
119
120
121
122
123
124
125
	return 0;
}

/* fill register allocator interface */

static const arch_irn_ops_t amd64_irn_ops = {
	amd64_get_frame_entity,
	amd64_set_frame_offset,
	amd64_get_sp_bias,
	NULL,    /* get_op_estimated_cost   */
	NULL,    /* possible_memory_operand */
	NULL,    /* perform_memory_operand  */
};

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

	be_add_missing_keeps(irg);
131
132
}

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
static const arch_register_req_t amd64_requirement_gp = {
	arch_register_req_type_normal,
	&amd64_reg_classes[CLASS_amd64_gp],
	NULL,
	0,
	0,
	1
};

static const unsigned amd64_limited_gp_rsp [] = { (1 << REG_GP_RSP) };
static const arch_register_req_t amd64_single_reg_req_gp_rsp = {
	arch_register_req_type_limited,
	&amd64_reg_classes[CLASS_amd64_gp],
	amd64_limited_gp_rsp,
	0,
	0,
	1
};

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)
160
161
162
163
164
165
{
	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
166
167
	amd64_addr_t addr;
	memset(&addr, 0, sizeof(addr));
168
	addr.base_input       = 1;
Matthias Braun's avatar
Matthias Braun committed
169
170
	addr.index_input      = NO_INPUT;
	addr.immediate.entity = ent;
171
172
	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
173
	                                    INSN_MODE_64, addr);
174
	arch_set_irn_register_reqs_in(push, am_pushpop_base_reqs);
175
176
177
178
179
180
181
182
183
184
185
	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
186
187
	amd64_addr_t addr;
	memset(&addr, 0, sizeof(addr));
188
	addr.base_input  = 1;
Matthias Braun's avatar
Matthias Braun committed
189
190
	addr.index_input = NO_INPUT;
	addr.immediate.entity = ent;
191
192
193
	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
194
	                                  INSN_MODE_64, addr);
195
	arch_set_irn_register_reqs_in(pop, am_pushpop_base_reqs);
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
247
	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
248
	for (i = arity; i-- > 0; ) {
249
250
251
252
253
254
255
256
257
258
259
		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
260
		ir_node *pop = create_pop(node, node, sp, outent);
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
		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);
		int p = get_Proj_proj(proj);

		assert(p < arity);

		set_Proj_pred(proj, pops[p]);
		set_Proj_proj(proj, pn_amd64_PopAM_M);
	}

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

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

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

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/**
 * 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);
	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);
	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);

	assert(get_Block_phis(lower_block) == NULL);
	set_Block_phis(lower_block, phi);
	set_Phi_next(phi, NULL);

	exchange(node, phi);
}

353
354
355
356
357
static ir_node *create_conv_const(ir_graph *irg, ir_mode *src_mode)
{
	assert(mode_is_float(src_mode));

	ir_node *result = NULL;
358
	if (get_mode_size_bits(src_mode) == 32) {
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
		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)
{
375
376
377
	const char *sign_str = "0x8000000000000000";
	ir_tarval *sign_tv = new_tarval_from_str(sign_str, strlen(sign_str),
	                                         mode_Ls);
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
	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);

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

	assert(get_Block_phis(lower_block) == NULL);
	set_Block_phis(lower_block, phi);
	set_Phi_next(phi, NULL);

	exchange(node, phi);
}

438
439
440
441
442
443
444
445
446
447
448
449
450
451
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) {
452
		rewrite_float_unsigned_Conv(node);
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
		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);
	collect_phiprojs(irg);
	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);
	}
}

485
486
static void amd64_set_frame_entity(ir_node *node, ir_entity *entity,
                                   const ir_type *type)
487
{
488
	(void)type;
Matthias Braun's avatar
Matthias Braun committed
489
	assert(is_amd64_Store(node) || is_amd64_Mov(node)
Tobias Rapp's avatar
Tobias Rapp committed
490
491
	    || is_amd64_Movs(node) || is_amd64_xMovs(node)
	    || is_amd64_xStores(node));
Matthias Braun's avatar
Matthias Braun committed
492
493
	amd64_addr_attr_t *attr = get_amd64_addr_attr(node);
	attr->addr.immediate.entity = entity;
494
495
}

496
497
static bool is_frame_load(const ir_node *node)
{
Tobias Rapp's avatar
Tobias Rapp committed
498
	return is_amd64_Mov(node) || is_amd64_Movs(node) || is_amd64_xMovs(node);
499
500
}

501
502
503
504
505
/**
 * Collects nodes that need frame entities assigned.
 */
static void amd64_collect_frame_entity_nodes(ir_node *node, void *data)
{
506
	/* we are only interested to report Load nodes */
507
	if (!is_frame_load(node))
Matthias Braun's avatar
Matthias Braun committed
508
509
		return;

Matthias Braun's avatar
Matthias Braun committed
510
511
	const amd64_addr_attr_t *attr = get_amd64_addr_attr_const(node);
	if (attr->needs_frame_ent) {
512
		be_fec_env_t  *env   = (be_fec_env_t*)data;
Matthias Braun's avatar
Matthias Braun committed
513
		const ir_mode *mode  = mode_Lu; /* TODO: improve */
514
515
		const ir_type *type  = get_type_for_mode(mode);
		be_load_needs_frame_entity(env, node, type);
516
517
518
	}
}

519
520
521
522
523
524
525
526
527
528
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);
}

529
530
531
static void introduce_epilogue(ir_node *ret)
{
	const arch_register_t *sp         = &amd64_registers[REG_RSP];
532
	const arch_register_t *bp         = &amd64_registers[REG_RBP];
533
534
535
536
537
538
539
540
	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);
	ir_node               *first_sp   = get_irn_n(ret, n_be_Return_sp);
	ir_node               *curr_sp    = first_sp;
541
	ir_mode               *mode_gp    = mode_Lu;
542

543
	if (!layout->sp_relative) {
544
545
546
547
548
549
550
551
552
553
554
		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);
555
556
557
558
559
560
561
562
563
	} else {
		if (frame_size > 0) {
			ir_node *incsp = be_new_IncSP(sp, block, curr_sp,
			                              - (int) frame_size, 0);
			sched_add_before(ret, incsp);
			curr_sp = incsp;
		}
	}
	set_irn_n(ret, n_be_Return_sp, curr_sp);
564
565
566
567
568

	/* keep verifier happy... */
	if (get_irn_n_edges(first_sp) == 0 && is_Proj(first_sp)) {
		kill_node(first_sp);
	}
569
570
571
572
573
}

static void introduce_prologue_epilogue(ir_graph *irg)
{
	const arch_register_t *sp         = &amd64_registers[REG_RSP];
574
	const arch_register_t *bp         = &amd64_registers[REG_RBP];
575
576
577
578
579
580
	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);
581
582
583
584
	ir_mode               *mode_gp    = mode_Lu;

	if (is_Deleted(start))
		return;
585
586

	if (!layout->sp_relative) {
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
		/* 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);

		ir_node *incsp = be_new_IncSP(sp, block, curr_sp, frame_size, 0);
		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;
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
	} else {
		if (frame_size > 0) {
			ir_node *const incsp = be_new_IncSP(sp, block, initial_sp,
			                                    frame_size, 0);
			sched_add_after(start, incsp);
		}
	}

	/* introduce epilogue for every return node */
	foreach_irn_in(get_irg_end_block(irg), i, ret) {
		assert(be_is_Return(ret) || is_amd64_Return(ret));
		introduce_epilogue(ret);
	}
}

630
631
632
/**
 * Called immediatly before emit phase.
 */
633
static void amd64_finish_graph(ir_graph *irg)
634
{
635
	be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
636
	bool               at_begin     = stack_layout->sp_relative;
637
	be_fec_env_t      *fec_env      = be_new_frame_entity_coalescer(irg);
638
639
640

	/* create and coalesce frame entities */
	irg_walk_graph(irg, NULL, amd64_collect_frame_entity_nodes, fec_env);
641
	be_assign_entities(fec_env, amd64_set_frame_entity, at_begin);
642
	be_free_frame_entity_coalescer(fec_env);
643

644
	irg_block_walk_graph(irg, NULL, amd64_after_ra_walker, NULL);
645

646
647
	introduce_prologue_epilogue(irg);

648
649
650
	/* fix stack entity offsets */
	be_abi_fix_stack_nodes(irg);
	be_abi_fix_stack_bias(irg);
651
652
653

	/* Fix 2-address code constraints. */
	amd64_finish_irg(irg);
654
655
656

	/* emit code */
	amd64_emit_function(irg);
657
}
658

659
extern const arch_isa_if_t amd64_isa_if;
660
661
662
static amd64_isa_t amd64_isa_template = {
	{
		&amd64_isa_if,             /* isa interface implementation */
663
664
		N_AMD64_REGISTERS,
		amd64_registers,
665
666
		N_AMD64_CLASSES,
		amd64_reg_classes,
667
668
		&amd64_registers[REG_RSP], /* stack pointer register */
		&amd64_registers[REG_RBP], /* base pointer register */
669
		4,                         /* power of two stack alignment for calls */
670
671
		7,                         /* costs for a spill instruction */
		5,                         /* costs for a reload instruction */
672
	},
673
	NULL,                              /* constants */
674
675
};

676
static void amd64_init(void)
677
678
679
{
	amd64_register_init();
	amd64_create_opcodes(&amd64_irn_ops);
680
	amd64_cconv_init();
681
682
}

Matthias Braun's avatar
Matthias Braun committed
683
684
685
686
687
static void amd64_finish(void)
{
	amd64_free_opcodes();
}

688
static arch_env_t *amd64_begin_codegeneration(void)
689
690
{
	amd64_isa_t *isa = XMALLOC(amd64_isa_t);
691
692
	*isa             = amd64_isa_template;
	isa->constants   = pmap_create();
693

694
	return &isa->base;
695
696
697
698
699
}

/**
 * Closes the output file and frees the ISA structure.
 */
700
static void amd64_end_codegeneration(void *self)
701
{
702
703
704
	amd64_isa_t *isa = (amd64_isa_t*)self;
	pmap_destroy(isa->constants);
	free(isa);
705
706
}

707
708
709
710
/**
 * prepare graph and perform code selection.
 */
static void amd64_prepare_graph(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
711
{
712
713
714
715
	be_timer_push(T_CODEGEN);
	amd64_transform_graph(irg);
	be_timer_pop(T_CODEGEN);

716
	be_dump(DUMP_BE, irg, "code-selection");
Matthias Braun's avatar
Matthias Braun committed
717
718
}

719
720
static void amd64_lower_for_target(void)
{
721
	/* lower compound param handling */
722
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
723
	be_after_irp_transform("lower-calls");
724

725
	foreach_irp_irg(i, irg) {
726
		lower_switch(irg, 4, 256, mode_Iu);
727
		be_after_transform(irg, "lower-switch");
728
729
	}

Tobias Rapp's avatar
Tobias Rapp committed
730
731
732
733
734
735
	foreach_irp_irg(i, irg) {
		/* lower for mode_b stuff */
		ir_lower_mode_b(irg, mode_Lu);
		be_after_transform(irg, "lower-modeb");
	}

736
	foreach_irp_irg(i, irg) {
737
738
739
740
		/* 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. */
741
		lower_CopyB(irg, 64, 65, true);
742
		be_after_transform(irg, "lower-copyb");
743
	}
744

745
746
747
748
749
750
	ir_builtin_kind supported[1];
	size_t  s = 0;
	supported[s++] = ir_bk_saturating_increment;

	assert(s <= ARRAY_SIZE(supported));
	lower_builtins(s, supported);
751
	be_after_irp_transform("lower-builtins");
752
753
}

754
755
756
static int amd64_is_mux_allowed(ir_node *sel, ir_node *mux_false,
                                ir_node *mux_true)
{
Matthias Braun's avatar
Matthias Braun committed
757
758
759
	/* optimizable by middleend */
	if (ir_is_optimizable_mux(sel, mux_false, mux_true))
		return true;
760
761
762
	return false;
}

763
764
765
766
767
768
769
770
771
772
static const ir_settings_arch_dep_t amd64_arch_dep = {
	1,     /* also use subs */
	4,     /* maximum shifts */
	63,    /* maximum shift amount */
	NULL,  /* evaluate the instruction sequence */

	1,  /* allow Mulhs */
	1,  /* allow Mulus */
	32, /* Mulh allowed up to 32 bit */
};
773
774
775
776
777
/**
 * Returns the libFirm configuration parameter for this backend.
 */
static const backend_params *amd64_get_backend_params(void) {
	static backend_params p = {
778
779
780
		false,     /* little endian */
		false,     /* PIC code not supported */
		true,      /* unaligned memory */
781
		32,    /* modulo shift */
782
		&amd64_arch_dep,
783
		amd64_is_mux_allowed,  /* parameter for if conversion */
784
		64,    /* machine size */
785
		NULL,  /* float arithmetic mode */
786
787
788
		NULL,  /* long long type */
		NULL,  /* unsigned long long type */
		NULL,  /* long double type (not supported yet) */
789
790
791
		0,     /* no trampoline support: size 0 */
		0,     /* no trampoline support: align 0 */
		NULL,  /* no trampoline support: no trampoline builder */
792
793
		8,     /* alignment of stack parameter: typically 4 (32bit) or 8 (64bit) */
		ir_overflow_indefinite
794
795
796
797
798
799
800
801
802
803
804
805
	};
	return &p;
}

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

const arch_isa_if_t amd64_isa_if = {
	amd64_init,
Matthias Braun's avatar
Matthias Braun committed
806
	amd64_finish,
807
    amd64_get_backend_params,
808
	amd64_lower_for_target,
809
810
	amd64_is_valid_clobber,

811
812
	amd64_begin_codegeneration,
	amd64_end_codegeneration,
813
	NULL,
814
	NULL,              /* mark remat */
Matthias Braun's avatar
Matthias Braun committed
815
816
	amd64_new_spill,
	amd64_new_reload,
817
	NULL,
818

819
	amd64_handle_intrinsics,
820
821
	amd64_prepare_graph,
	amd64_before_ra,
822
	amd64_finish_graph,
823
824
};

Matthias Braun's avatar
Matthias Braun committed
825
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_amd64)
826
827
828
829
void be_init_arch_amd64(void)
{
	be_register_isa_if("amd64", &amd64_isa_if);
	FIRM_DBG_REGISTER(dbg, "firm.be.amd64.cg");
830
831

	amd64_init_finish();
832
833
	amd64_init_transform();
}