bearch_arm.c 14.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
 */

6
7
8
/**
 * @file
 * @brief   The main arm backend driver file.
9
 * @author  Matthias Braun, Oliver Richter, Tobias Gneist
10
 */
11
12
#include "config.h"

Matthias Braun's avatar
Matthias Braun committed
13
14
#include "lc_opts.h"
#include "lc_opts_enum.h"
Michael Beck's avatar
Michael Beck committed
15

16
17
18
19
#include "irgwalk.h"
#include "irprog.h"
#include "ircons.h"
#include "irgmod.h"
20
#include "irgopt.h"
Matthias Braun's avatar
Matthias Braun committed
21
#include "iroptimize.h"
22
#include "irdump.h"
23
#include "lower_calls.h"
24
#include "error.h"
25
#include "debug.h"
26
#include "array_t.h"
Michael Beck's avatar
Michael Beck committed
27
#include "irtools.h"
28

29
30
31
32
#include "bearch.h"
#include "benode.h"
#include "belower.h"
#include "besched.h"
33
#include "be.h"
34
35
36
37
38
39
40
41
#include "bemodule.h"
#include "beirg.h"
#include "bespillslots.h"
#include "bespillutil.h"
#include "begnuas.h"
#include "belistsched.h"
#include "beflags.h"
#include "bestack.h"
42
43
44

#include "bearch_arm_t.h"

45
46
#include "arm_new_nodes.h"
#include "gen_arm_regalloc_if.h"
47
#include "arm_transform.h"
48
#include "arm_optimize.h"
49
50
51
#include "arm_emitter.h"
#include "arm_map_regs.h"

52
53
54
55
56
static ir_entity *arm_get_frame_entity(const ir_node *irn)
{
	const arm_attr_t *attr = get_arm_attr_const(irn);

	if (is_arm_FrameAddr(irn)) {
57
58
		const arm_SymConst_attr_t *frame_attr = get_arm_SymConst_attr_const(irn);
		return frame_attr->entity;
59
60
61
62
63
64
65
66
	}
	if (attr->is_load_store) {
		const arm_load_store_attr_t *load_store_attr
			= get_arm_load_store_attr_const(irn);
		if (load_store_attr->is_frame_entity) {
			return load_store_attr->entity;
		}
	}
67
68
69
70
71
72
73
	return NULL;
}

/**
 * This function is called by the generic backend to correct offsets for
 * nodes accessing the stack.
 */
74
static void arm_set_stack_bias(ir_node *irn, int bias)
75
{
76
	if (is_arm_FrameAddr(irn)) {
77
		arm_SymConst_attr_t *attr = get_arm_SymConst_attr(irn);
78
79
80
81
82
83
		attr->fp_offset += bias;
	} else {
		arm_load_store_attr_t *attr = get_arm_load_store_attr(irn);
		assert(attr->base.is_load_store);
		attr->offset += bias;
	}
84
85
}

86
static int arm_get_sp_bias(const ir_node *irn)
Matthias Braun's avatar
Matthias Braun committed
87
{
88
	/* We don't have any nodes changing the stack pointer.
89
	   We probably want to support post-/pre increment/decrement later */
Matthias Braun's avatar
Matthias Braun committed
90
	(void) irn;
91
92
93
	return 0;
}

94
95
/* fill register allocator interface */

Matthias Braun's avatar
Matthias Braun committed
96
static const arch_irn_ops_t arm_irn_ops = {
97
	arm_get_frame_entity,
98
	arm_set_stack_bias,
99
	arm_get_sp_bias,
100
101
102
	NULL,    /* get_op_estimated_cost   */
	NULL,    /* possible_memory_operand */
	NULL,    /* perform_memory_operand  */
103
104
105
};

/**
Michael Beck's avatar
Michael Beck committed
106
107
 * Transforms the standard Firm graph into
 * a ARM firm graph.
108
 */
109
static void arm_prepare_graph(ir_graph *irg)
110
{
111
	/* transform nodes into assembler instructions */
112
	arm_transform_graph(irg);
113

114
	/* do local optimizations (mainly CSE) */
115
	local_optimize_graph(irg);
116
117

	/* do code placement, to optimize the position of constants */
118
	place_code(irg);
119
}
120

121
static void arm_collect_frame_entity_nodes(ir_node *node, void *data)
Matthias Braun's avatar
Matthias Braun committed
122
{
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
	be_fec_env_t  *env = (be_fec_env_t*)data;
	const ir_mode *mode;
	int            align;
	ir_entity     *entity;
	const arm_load_store_attr_t *attr;

	if (be_is_Reload(node) && be_get_frame_entity(node) == NULL) {
		mode  = get_irn_mode(node);
		align = get_mode_size_bytes(mode);
		be_node_needs_frame_entity(env, node, mode, align);
		return;
	}

	switch (get_arm_irn_opcode(node)) {
	case iro_arm_Ldf:
	case iro_arm_Ldr:
		break;
	default:
		return;
	}

	attr   = get_arm_load_store_attr_const(node);
	entity = attr->entity;
	mode   = attr->load_store_mode;
	align  = get_mode_size_bytes(mode);
	if (entity != NULL)
		return;
	if (!attr->is_frame_entity)
		return;
	be_node_needs_frame_entity(env, node, mode, align);
153
154
}

155
static void arm_set_frame_entity(ir_node *node, ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
156
{
157
158
159
160
161
162
	if (is_be_node(node)) {
		be_node_set_frame_entity(node, entity);
	} else {
		arm_load_store_attr_t *attr = get_arm_load_store_attr(node);
		attr->entity = entity;
	}
163
164
}

165
166
167
168
static void transform_Reload(ir_node *node)
{
	ir_node   *block  = get_nodes_block(node);
	dbg_info  *dbgi   = get_irn_dbg_info(node);
169
170
	ir_node   *ptr    = get_irn_n(node, n_be_Reload_frame);
	ir_node   *mem    = get_irn_n(node, n_be_Reload_mem);
171
	ir_mode   *mode   = get_irn_mode(node);
172
	ir_entity *entity = be_get_frame_entity(node);
173
174
	const arch_register_t *reg;
	ir_node   *proj;
175
176
	ir_node   *load;

177
	load = new_bd_arm_Ldr(dbgi, block, ptr, mem, mode, entity, false, 0, true);
178
	sched_replace(node, load);
179

180
	proj = new_rd_Proj(dbgi, load, mode, pn_arm_Ldr_res);
181
182
183
184
185
186
187
188
189
190
191

	reg = arch_get_irn_register(node);
	arch_set_irn_register(proj, reg);

	exchange(node, proj);
}

static void transform_Spill(ir_node *node)
{
	ir_node   *block  = get_nodes_block(node);
	dbg_info  *dbgi   = get_irn_dbg_info(node);
192
	ir_node   *ptr    = get_irn_n(node, n_be_Spill_frame);
193
	ir_graph  *irg    = get_irn_irg(node);
194
	ir_node   *mem    = get_irg_no_mem(irg);
195
	ir_node   *val    = get_irn_n(node, n_be_Spill_val);
196
197
198
199
200
201
	ir_mode   *mode   = get_irn_mode(val);
	ir_entity *entity = be_get_frame_entity(node);
	ir_node   *store;

	store = new_bd_arm_Str(dbgi, block, ptr, val, mem, mode, entity, false, 0,
	                       true);
202
	sched_replace(node, store);
203
204

	exchange(node, store);
205
206
}

207
static void arm_after_ra_walker(ir_node *block, void *data)
208
209
210
{
	(void) data;

211
	sched_foreach_reverse_safe(block, node) {
212
213
214
215
216
217
218
219
		if (be_is_Reload(node)) {
			transform_Reload(node);
		} else if (be_is_Spill(node)) {
			transform_Spill(node);
		}
	}
}

220
221
222
223
/**
 * Called immediately before emit phase.
 */
static void arm_finish_irg(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
224
{
225
226
227
	be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
	bool               at_begin     = stack_layout->sp_relative ? true : false;
	be_fec_env_t      *fec_env      = be_new_frame_entity_coalescer(irg);
228
229

	irg_walk_graph(irg, NULL, arm_collect_frame_entity_nodes, fec_env);
230
	be_assign_entities(fec_env, arm_set_frame_entity, at_begin);
231
	be_free_frame_entity_coalescer(fec_env);
232

233
	irg_block_walk_graph(irg, NULL, arm_after_ra_walker, NULL);
234
235
236
237
238
239
240
241
242
243
244
245

	/* fix stack entity offsets */
	be_abi_fix_stack_nodes(irg);
	be_abi_fix_stack_bias(irg);

	/* do peephole optimizations and fix stack offsets */
	arm_peephole_optimization(irg);
}

static void arm_before_ra(ir_graph *irg)
{
	be_sched_fix_flags(irg, &arm_reg_classes[CLASS_arm_flags], NULL, NULL);
Michael Beck's avatar
Michael Beck committed
246
}
247
248
249
250
251
252

/**
 * Maps all intrinsic calls that the backend support
 * and map all instructions the backend did not support
 * to runtime calls.
 */
Matthias Braun's avatar
Matthias Braun committed
253
254
static void arm_handle_intrinsics(void)
{
255
256
257
	ir_type *tp, *int_tp, *uint_tp;
	i_record records[8];
	int n_records = 0;
258

Michael Beck's avatar
Michael Beck committed
259
260
	runtime_rt rt_iDiv, rt_uDiv, rt_iMod, rt_uMod;

261
262
#define ID(x) new_id_from_chars(x, sizeof(x)-1)

263
264
	int_tp  = get_type_for_mode(mode_Is);
	uint_tp = get_type_for_mode(mode_Iu);
265

Michael Beck's avatar
Michael Beck committed
266
	/* ARM has neither a signed div instruction ... */
267
268
269
	{
		i_instr_record *map_Div = &records[n_records++].i_instr;

270
		tp = new_type_method(2, 1);
271
272
273
274
		set_method_param_type(tp, 0, int_tp);
		set_method_param_type(tp, 1, int_tp);
		set_method_res_type(tp, 0, int_tp);

Michael Beck's avatar
Michael Beck committed
275
276
277
278
279
280
281
282
		rt_iDiv.ent             = new_entity(get_glob_type(), ID("__divsi3"), tp);
		set_entity_ld_ident(rt_iDiv.ent, ID("__divsi3"));
		rt_iDiv.mode            = mode_T;
		rt_iDiv.res_mode        = mode_Is;
		rt_iDiv.mem_proj_nr     = pn_Div_M;
		rt_iDiv.regular_proj_nr = pn_Div_X_regular;
		rt_iDiv.exc_proj_nr     = pn_Div_X_except;
		rt_iDiv.res_proj_nr     = pn_Div_res;
283

284
285
		add_entity_linkage(rt_iDiv.ent, IR_LINKAGE_CONSTANT);
		set_entity_visibility(rt_iDiv.ent, ir_visibility_external);
286
287
288
289

		map_Div->kind     = INTRINSIC_INSTR;
		map_Div->op       = op_Div;
		map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
Michael Beck's avatar
Michael Beck committed
290
		map_Div->ctx      = &rt_iDiv;
291
292
293
294
295
	}
	/* ... nor an unsigned div instruction ... */
	{
		i_instr_record *map_Div = &records[n_records++].i_instr;

296
		tp = new_type_method(2, 1);
297
298
299
300
		set_method_param_type(tp, 0, uint_tp);
		set_method_param_type(tp, 1, uint_tp);
		set_method_res_type(tp, 0, uint_tp);

Michael Beck's avatar
Michael Beck committed
301
302
303
304
305
306
307
308
		rt_uDiv.ent             = new_entity(get_glob_type(), ID("__udivsi3"), tp);
		set_entity_ld_ident(rt_uDiv.ent, ID("__udivsi3"));
		rt_uDiv.mode            = mode_T;
		rt_uDiv.res_mode        = mode_Iu;
		rt_uDiv.mem_proj_nr     = pn_Div_M;
		rt_uDiv.regular_proj_nr = pn_Div_X_regular;
		rt_uDiv.exc_proj_nr     = pn_Div_X_except;
		rt_uDiv.res_proj_nr     = pn_Div_res;
309

310
		set_entity_visibility(rt_uDiv.ent, ir_visibility_external);
311
312
313
314

		map_Div->kind     = INTRINSIC_INSTR;
		map_Div->op       = op_Div;
		map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
Michael Beck's avatar
Michael Beck committed
315
		map_Div->ctx      = &rt_uDiv;
316
	}
Michael Beck's avatar
Michael Beck committed
317
	/* ... nor a signed mod instruction ... */
318
319
320
	{
		i_instr_record *map_Mod = &records[n_records++].i_instr;

321
		tp = new_type_method(2, 1);
322
323
324
325
		set_method_param_type(tp, 0, int_tp);
		set_method_param_type(tp, 1, int_tp);
		set_method_res_type(tp, 0, int_tp);

Michael Beck's avatar
Michael Beck committed
326
327
328
329
330
331
332
333
		rt_iMod.ent             = new_entity(get_glob_type(), ID("__modsi3"), tp);
		set_entity_ld_ident(rt_iMod.ent, ID("__modsi3"));
		rt_iMod.mode            = mode_T;
		rt_iMod.res_mode        = mode_Is;
		rt_iMod.mem_proj_nr     = pn_Mod_M;
		rt_iMod.regular_proj_nr = pn_Mod_X_regular;
		rt_iMod.exc_proj_nr     = pn_Mod_X_except;
		rt_iMod.res_proj_nr     = pn_Mod_res;
334

335
		set_entity_visibility(rt_iMod.ent, ir_visibility_external);
336
337
338
339

		map_Mod->kind     = INTRINSIC_INSTR;
		map_Mod->op       = op_Mod;
		map_Mod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
Michael Beck's avatar
Michael Beck committed
340
		map_Mod->ctx      = &rt_iMod;
341
342
343
344
345
	}
	/* ... nor an unsigned mod. */
	{
		i_instr_record *map_Mod = &records[n_records++].i_instr;

346
		tp = new_type_method(2, 1);
347
348
349
350
		set_method_param_type(tp, 0, uint_tp);
		set_method_param_type(tp, 1, uint_tp);
		set_method_res_type(tp, 0, uint_tp);

Michael Beck's avatar
Michael Beck committed
351
352
353
354
355
356
357
358
		rt_uMod.ent             = new_entity(get_glob_type(), ID("__umodsi3"), tp);
		set_entity_ld_ident(rt_uMod.ent, ID("__umodsi3"));
		rt_uMod.mode            = mode_T;
		rt_uMod.res_mode        = mode_Iu;
		rt_uMod.mem_proj_nr     = pn_Mod_M;
		rt_uMod.regular_proj_nr = pn_Mod_X_regular;
		rt_uMod.exc_proj_nr     = pn_Mod_X_except;
		rt_uMod.res_proj_nr     = pn_Mod_res;
359

360
		set_entity_visibility(rt_uMod.ent, ir_visibility_external);
361
362
363
364

		map_Mod->kind     = INTRINSIC_INSTR;
		map_Mod->op       = op_Mod;
		map_Mod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
Michael Beck's avatar
Michael Beck committed
365
		map_Mod->ctx      = &rt_uMod;
366
367
368
	}

	if (n_records > 0)
369
		lower_intrinsics(records, n_records, /*part_block_used=*/0);
370
371
}

372
extern const arch_isa_if_t arm_isa_if;
373
static arm_isa_t arm_isa_template = {
Michael Beck's avatar
Michael Beck committed
374
	{
375
		&arm_isa_if,             /* isa interface */
376
377
		N_ARM_REGISTERS,
		arm_registers,
378
379
		N_ARM_CLASSES,
		arm_reg_classes,
380
381
		&arm_registers[REG_SP],  /* stack pointer */
		&arm_registers[REG_R11], /* base pointer */
382
383
384
385
		2,                       /* power of two stack alignment for calls, 2^2 == 4 */
		7,                       /* spill costs */
		5,                       /* reload costs */
		true,                    /* we do have custom abi handling */
Michael Beck's avatar
Michael Beck committed
386
	},
387
	ARM_FPU_ARCH_FPE,          /* FPU architecture */
388
389
};

390
static void arm_init(void)
391
{
Matthias Braun's avatar
Matthias Braun committed
392
	arm_register_init();
Michael Beck's avatar
Michael Beck committed
393

Matthias Braun's avatar
Matthias Braun committed
394
	arm_create_opcodes(&arm_irn_ops);
395
396
}

Matthias Braun's avatar
Matthias Braun committed
397
398
399
400
401
static void arm_finish(void)
{
	arm_free_opcodes();
}

402
static arch_env_t *arm_begin_codegeneration(void)
403
404
405
{
	arm_isa_t *isa = XMALLOC(arm_isa_t);
	*isa = arm_isa_template;
406

407
408
	be_gas_emit_types = false;

409
	return &isa->base;
410
411
412
}

/**
Michael Beck's avatar
Michael Beck committed
413
 * Closes the output file and frees the ISA structure.
414
 */
415
static void arm_end_codegeneration(void *self)
416
{
417
418
419
	free(self);
}

Michael Beck's avatar
Michael Beck committed
420
421
422
423
/**
 * Allows or disallows the creation of Psi nodes for the given Phi nodes.
 * @return 1 if allowed, 0 otherwise
 */
424
425
426
427
428
429
static int arm_is_mux_allowed(ir_node *sel, ir_node *mux_false,
                              ir_node *mux_true)
{
	(void) sel;
	(void) mux_false;
	(void) mux_true;
430
	return false;
Michael Beck's avatar
Michael Beck committed
431
432
}

433
static int arm_is_valid_clobber(const char *clobber)
434
435
{
	(void) clobber;
436
	return 0;
437
438
}

439
440
static void arm_lower_for_target(void)
{
441
	ir_mode *mode_gp = arm_reg_classes[CLASS_arm_gp].mode;
Michael Beck's avatar
Michael Beck committed
442
	size_t i, n_irgs = get_irp_n_irgs();
443

444
	/* lower compound param handling */
445
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
446

447
448
	for (i = 0; i < n_irgs; ++i) {
		ir_graph *irg = get_irp_irg(i);
449
		lower_switch(irg, 4, 256, mode_gp);
450
	}
451
452
453
454
455
456

	for (i = 0; i < n_irgs; ++i) {
		ir_graph *irg = get_irp_irg(i);
		/* Turn all small CopyBs into loads/stores and all bigger CopyBs into
		 * memcpy calls.
		 * TODO:  These constants need arm-specific tuning. */
457
		lower_CopyB(irg, 31, 32, false);
458
	}
459
460
}

Michael Beck's avatar
Michael Beck committed
461
462
463
/**
 * Returns the libFirm configuration parameter for this backend.
 */
464
465
static const backend_params *arm_get_libfirm_params(void)
{
466
	static ir_settings_arch_dep_t ad = {
Michael Beck's avatar
Michael Beck committed
467
		1,    /* allow subs */
468
		1,    /* Muls are fast enough on ARM but ... */
Michael Beck's avatar
Michael Beck committed
469
470
471
472
473
		31,   /* ... one shift would be possible better */
		NULL, /* no evaluator function */
		0,    /* SMUL is needed, only in Arch M */
		0,    /* UMUL is needed, only in Arch M */
		32,   /* SMUL & UMUL available for 32 bit */
Michael Beck's avatar
Michael Beck committed
474
475
	};
	static backend_params p = {
476
		1,     /* support Rotl nodes */
477
		1,     /* big endian */
478
479
		1,     /* modulo shift efficient */
		0,     /* non-modulo shift not efficient */
480
481
		&ad,   /* will be set later */
		arm_is_mux_allowed, /* allow_ifconv function */
482
		32,    /* machine size */
483
		NULL,  /* float arithmetic mode (TODO) */
484
485
486
		NULL,  /* long long type */
		NULL,  /* unsigned long long type */
		NULL,  /* long double type */
487
488
		0,     /* no trampoline support: size 0 */
		0,     /* no trampoline support: align 0 */
489
490
		NULL,  /* no trampoline support: no trampoline builder */
		4      /* alignment of stack parameter */
Michael Beck's avatar
Michael Beck committed
491
492
493
494
495
	};

	return &p;
}

Michael Beck's avatar
Michael Beck committed
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
/* fpu set architectures. */
static const lc_opt_enum_int_items_t arm_fpu_items[] = {
	{ "softfloat", ARM_FPU_ARCH_SOFTFLOAT },
	{ "fpe",       ARM_FPU_ARCH_FPE },
	{ "fpa",       ARM_FPU_ARCH_FPA },
	{ "vfp1xd",    ARM_FPU_ARCH_VFP_V1xD },
	{ "vfp1",      ARM_FPU_ARCH_VFP_V1 },
	{ "vfp2",      ARM_FPU_ARCH_VFP_V2 },
	{ NULL,        0 }
};

static lc_opt_enum_int_var_t arch_fpu_var = {
	&arm_isa_template.fpu_arch, arm_fpu_items
};

Michael Beck's avatar
Michael Beck committed
511
static const lc_opt_table_entry_t arm_options[] = {
Michael Beck's avatar
Michael Beck committed
512
	LC_OPT_ENT_ENUM_INT("fpunit",    "select the floating point unit", &arch_fpu_var),
513
	LC_OPT_LAST
Michael Beck's avatar
Michael Beck committed
514
};
515
516
517

const arch_isa_if_t arm_isa_if = {
	arm_init,
Matthias Braun's avatar
Matthias Braun committed
518
	arm_finish,
Michael Beck's avatar
Michael Beck committed
519
	arm_get_libfirm_params,
520
	arm_lower_for_target,
521
522
	arm_is_valid_clobber,

523
524
	arm_begin_codegeneration,
	arm_end_codegeneration,
525
	NULL,
526
527
	NULL,  /* get call abi */
	NULL,  /* mark remat */
528
	NULL,  /* get_pic_base */
529
530
531
532
533
	be_new_spill,
	be_new_reload,
	NULL,  /* register_saved_by */

	arm_handle_intrinsics, /* handle_intrinsics */
534
535
536
537
538
	NULL,  /* before_abi */
	arm_prepare_graph,
	arm_before_ra,
	arm_finish_irg,
	arm_gen_routine,
539
};
540

Matthias Braun's avatar
Matthias Braun committed
541
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_arm)
542
543
544
545
546
547
548
549
void be_init_arch_arm(void)
{
	lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
	lc_opt_entry_t *arm_grp = lc_opt_get_grp(be_grp, "arm");

	lc_opt_add_table(arm_grp, arm_options);

	be_register_isa_if("arm", &arm_isa_if);
550
551

	arm_init_transform();
552
	arm_init_emitter();
553
}