bearch_arm.c 14.2 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
 */
Matthias Braun's avatar
Matthias Braun committed
11
12
#include "lc_opts.h"
#include "lc_opts_enum.h"
Michael Beck's avatar
Michael Beck committed
13

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

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

#include "bearch_arm_t.h"

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

50
51
52
53
54
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)) {
55
56
		const arm_SymConst_attr_t *frame_attr = get_arm_SymConst_attr_const(irn);
		return frame_attr->entity;
57
58
59
60
61
62
63
64
	}
	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;
		}
	}
65
66
67
68
69
70
71
	return NULL;
}

/**
 * This function is called by the generic backend to correct offsets for
 * nodes accessing the stack.
 */
72
static void arm_set_stack_bias(ir_node *irn, int bias)
73
{
74
	if (is_arm_FrameAddr(irn)) {
75
		arm_SymConst_attr_t *attr = get_arm_SymConst_attr(irn);
76
77
78
79
80
81
		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;
	}
82
83
}

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

92
93
/* fill register allocator interface */

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

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

112
	/* do local optimizations (mainly CSE) */
113
	local_optimize_graph(irg);
114
115

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

119
static void arm_collect_frame_entity_nodes(ir_node *node, void *data)
Matthias Braun's avatar
Matthias Braun committed
120
{
121
122
123
124
125
126
127
128
129
130
131
132
133
	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;
	}

Matthias Braun's avatar
Matthias Braun committed
134
	if (!is_arm_Ldf(node) && !is_arm_Ldr(node))
135
136
137
138
139
140
141
142
143
144
145
		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);
146
147
}

148
static void arm_set_frame_entity(ir_node *node, ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
149
{
150
151
152
153
154
155
	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;
	}
156
157
}

158
159
160
161
static void transform_Reload(ir_node *node)
{
	ir_node   *block  = get_nodes_block(node);
	dbg_info  *dbgi   = get_irn_dbg_info(node);
162
163
	ir_node   *ptr    = get_irn_n(node, n_be_Reload_frame);
	ir_node   *mem    = get_irn_n(node, n_be_Reload_mem);
164
	ir_mode   *mode   = get_irn_mode(node);
165
	ir_entity *entity = be_get_frame_entity(node);
166
167
	const arch_register_t *reg;
	ir_node   *proj;
168
169
	ir_node   *load;

170
	load = new_bd_arm_Ldr(dbgi, block, ptr, mem, mode, entity, false, 0, true);
171
	sched_replace(node, load);
172

173
	proj = new_rd_Proj(dbgi, load, mode, pn_arm_Ldr_res);
174
175
176
177
178
179
180
181
182
183
184

	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);
185
	ir_node   *ptr    = get_irn_n(node, n_be_Spill_frame);
186
	ir_graph  *irg    = get_irn_irg(node);
187
	ir_node   *mem    = get_irg_no_mem(irg);
188
	ir_node   *val    = get_irn_n(node, n_be_Spill_val);
189
190
191
192
193
194
	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);
195
	sched_replace(node, store);
196
197

	exchange(node, store);
198
199
}

200
static void arm_after_ra_walker(ir_node *block, void *data)
201
202
203
{
	(void) data;

204
	sched_foreach_reverse_safe(block, node) {
205
206
207
208
209
210
211
212
		if (be_is_Reload(node)) {
			transform_Reload(node);
		} else if (be_is_Spill(node)) {
			transform_Spill(node);
		}
	}
}

213
214
215
216
/**
 * Called immediately before emit phase.
 */
static void arm_finish_irg(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
217
{
218
219
220
	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);
221
222

	irg_walk_graph(irg, NULL, arm_collect_frame_entity_nodes, fec_env);
223
	be_assign_entities(fec_env, arm_set_frame_entity, at_begin);
224
	be_free_frame_entity_coalescer(fec_env);
225

226
	irg_block_walk_graph(irg, NULL, arm_after_ra_walker, NULL);
227
228
229
230
231
232
233
234
235
236
237
238

	/* 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
239
}
240
241
242
243
244
245

/**
 * 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
246
247
static void arm_handle_intrinsics(void)
{
248
249
250
	ir_type *tp, *int_tp, *uint_tp;
	i_record records[8];
	int n_records = 0;
251

Michael Beck's avatar
Michael Beck committed
252
253
	runtime_rt rt_iDiv, rt_uDiv, rt_iMod, rt_uMod;

254
255
#define ID(x) new_id_from_chars(x, sizeof(x)-1)

256
257
	int_tp  = get_type_for_mode(mode_Is);
	uint_tp = get_type_for_mode(mode_Iu);
258

Michael Beck's avatar
Michael Beck committed
259
	/* ARM has neither a signed div instruction ... */
260
261
262
	{
		i_instr_record *map_Div = &records[n_records++].i_instr;

263
		tp = new_type_method(2, 1);
264
265
266
267
		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
268
269
270
271
272
273
274
275
		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;
276

277
278
		add_entity_linkage(rt_iDiv.ent, IR_LINKAGE_CONSTANT);
		set_entity_visibility(rt_iDiv.ent, ir_visibility_external);
279
280
281
282

		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
283
		map_Div->ctx      = &rt_iDiv;
284
285
286
287
288
	}
	/* ... nor an unsigned div instruction ... */
	{
		i_instr_record *map_Div = &records[n_records++].i_instr;

289
		tp = new_type_method(2, 1);
290
291
292
293
		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
294
295
296
297
298
299
300
301
		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;
302

303
		set_entity_visibility(rt_uDiv.ent, ir_visibility_external);
304
305
306
307

		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
308
		map_Div->ctx      = &rt_uDiv;
309
	}
Michael Beck's avatar
Michael Beck committed
310
	/* ... nor a signed mod instruction ... */
311
312
313
	{
		i_instr_record *map_Mod = &records[n_records++].i_instr;

314
		tp = new_type_method(2, 1);
315
316
317
318
		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
319
320
321
322
323
324
325
326
		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;
327

328
		set_entity_visibility(rt_iMod.ent, ir_visibility_external);
329
330
331
332

		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
333
		map_Mod->ctx      = &rt_iMod;
334
335
336
337
338
	}
	/* ... nor an unsigned mod. */
	{
		i_instr_record *map_Mod = &records[n_records++].i_instr;

339
		tp = new_type_method(2, 1);
340
341
342
343
		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
344
345
346
347
348
349
350
351
		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;
352

353
		set_entity_visibility(rt_uMod.ent, ir_visibility_external);
354
355
356
357

		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
358
		map_Mod->ctx      = &rt_uMod;
359
360
361
	}

	if (n_records > 0)
362
		lower_intrinsics(records, n_records, /*part_block_used=*/0);
363
364
}

365
extern const arch_isa_if_t arm_isa_if;
366
static arm_isa_t arm_isa_template = {
Michael Beck's avatar
Michael Beck committed
367
	{
368
		&arm_isa_if,             /* isa interface */
369
370
		N_ARM_REGISTERS,
		arm_registers,
371
372
		N_ARM_CLASSES,
		arm_reg_classes,
373
374
		&arm_registers[REG_SP],  /* stack pointer */
		&arm_registers[REG_R11], /* base pointer */
375
376
377
378
		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
379
	},
380
	ARM_FPU_ARCH_FPE,          /* FPU architecture */
381
382
};

383
static void arm_init(void)
384
{
Matthias Braun's avatar
Matthias Braun committed
385
	arm_register_init();
Michael Beck's avatar
Michael Beck committed
386

Matthias Braun's avatar
Matthias Braun committed
387
	arm_create_opcodes(&arm_irn_ops);
388
389
}

Matthias Braun's avatar
Matthias Braun committed
390
391
392
393
394
static void arm_finish(void)
{
	arm_free_opcodes();
}

395
static arch_env_t *arm_begin_codegeneration(void)
396
397
398
{
	arm_isa_t *isa = XMALLOC(arm_isa_t);
	*isa = arm_isa_template;
399

400
401
	be_gas_emit_types = false;

402
	return &isa->base;
403
404
405
}

/**
Michael Beck's avatar
Michael Beck committed
406
 * Closes the output file and frees the ISA structure.
407
 */
408
static void arm_end_codegeneration(void *self)
409
{
410
411
412
	free(self);
}

Michael Beck's avatar
Michael Beck committed
413
414
415
416
/**
 * Allows or disallows the creation of Psi nodes for the given Phi nodes.
 * @return 1 if allowed, 0 otherwise
 */
417
418
419
420
421
422
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;
423
	return false;
Michael Beck's avatar
Michael Beck committed
424
425
}

426
static int arm_is_valid_clobber(const char *clobber)
427
428
{
	(void) clobber;
429
	return 0;
430
431
}

432
433
static void arm_lower_for_target(void)
{
434
	ir_mode *mode_gp = arm_reg_classes[CLASS_arm_gp].mode;
Michael Beck's avatar
Michael Beck committed
435
	size_t i, n_irgs = get_irp_n_irgs();
436

437
	/* lower compound param handling */
438
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
439

440
441
	for (i = 0; i < n_irgs; ++i) {
		ir_graph *irg = get_irp_irg(i);
442
		lower_switch(irg, 4, 256, mode_gp);
443
	}
444
445
446
447
448
449

	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. */
450
		lower_CopyB(irg, 31, 32, false);
451
	}
452
453
}

Michael Beck's avatar
Michael Beck committed
454
455
456
/**
 * Returns the libFirm configuration parameter for this backend.
 */
457
458
static const backend_params *arm_get_libfirm_params(void)
{
459
	static ir_settings_arch_dep_t ad = {
Michael Beck's avatar
Michael Beck committed
460
		1,    /* allow subs */
461
		1,    /* Muls are fast enough on ARM but ... */
Michael Beck's avatar
Michael Beck committed
462
463
464
465
466
		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
467
468
	};
	static backend_params p = {
469
		1,     /* big endian */
470
471
		1,     /* modulo shift efficient */
		0,     /* non-modulo shift not efficient */
472
		0,     /* PIC code not supported */
473
474
		&ad,   /* will be set later */
		arm_is_mux_allowed, /* allow_ifconv function */
475
		32,    /* machine size */
476
		NULL,  /* float arithmetic mode (TODO) */
477
478
479
		NULL,  /* long long type */
		NULL,  /* unsigned long long type */
		NULL,  /* long double type */
480
481
		0,     /* no trampoline support: size 0 */
		0,     /* no trampoline support: align 0 */
482
483
		NULL,  /* no trampoline support: no trampoline builder */
		4      /* alignment of stack parameter */
Michael Beck's avatar
Michael Beck committed
484
485
486
487
488
	};

	return &p;
}

Michael Beck's avatar
Michael Beck committed
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
/* 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
504
static const lc_opt_table_entry_t arm_options[] = {
Michael Beck's avatar
Michael Beck committed
505
	LC_OPT_ENT_ENUM_INT("fpunit",    "select the floating point unit", &arch_fpu_var),
506
	LC_OPT_LAST
Michael Beck's avatar
Michael Beck committed
507
};
508
509
510

const arch_isa_if_t arm_isa_if = {
	arm_init,
Matthias Braun's avatar
Matthias Braun committed
511
	arm_finish,
Michael Beck's avatar
Michael Beck committed
512
	arm_get_libfirm_params,
513
	arm_lower_for_target,
514
515
	arm_is_valid_clobber,

516
517
	arm_begin_codegeneration,
	arm_end_codegeneration,
518
	NULL,
519
520
	NULL,  /* get call abi */
	NULL,  /* mark remat */
521
	NULL,  /* get_pic_base */
522
523
524
525
526
	be_new_spill,
	be_new_reload,
	NULL,  /* register_saved_by */

	arm_handle_intrinsics, /* handle_intrinsics */
527
528
529
530
531
	NULL,  /* before_abi */
	arm_prepare_graph,
	arm_before_ra,
	arm_finish_irg,
	arm_gen_routine,
532
};
533

Matthias Braun's avatar
Matthias Braun committed
534
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_arm)
535
536
537
538
539
540
541
542
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);
543
544

	arm_init_transform();
545
	arm_init_emitter();
546
}