bearch_arm.c 11.8 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
#include "irgwalk.h"
15
#include "irprog_t.h"
16
17
#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"
Matthias Braun's avatar
Matthias Braun committed
21
#include "lower_builtins.h"
22
#include "lower_calls.h"
23
#include "lower_softfloat.h"
Matthias Braun's avatar
Matthias Braun committed
24
#include "panic.h"
25
#include "debug.h"
26
#include "array.h"
Michael Beck's avatar
Michael Beck committed
27
#include "irtools.h"
Matthias Braun's avatar
Matthias Braun committed
28
#include "util.h"
29

30
31
32
33
#include "bearch.h"
#include "benode.h"
#include "belower.h"
#include "besched.h"
34
#include "be.h"
35
36
37
#include "bemodule.h"
#include "beirg.h"
#include "bespillutil.h"
38
#include "beutil.h"
39
40
41
42
#include "begnuas.h"
#include "belistsched.h"
#include "beflags.h"
#include "bestack.h"
Matthias Braun's avatar
Matthias Braun committed
43
#include "betranshlp.h"
44
45
46

#include "bearch_arm_t.h"

47
48
#include "arm_new_nodes.h"
#include "gen_arm_regalloc_if.h"
49
#include "arm_transform.h"
50
#include "arm_optimize.h"
51
52
#include "arm_emitter.h"

53
54
arm_codegen_config_t arm_cg_config;

55
56
57
ir_mode *arm_mode_gp;
ir_mode *arm_mode_flags;

Matthias Braun's avatar
Matthias Braun committed
58
59
static const backend_params *arm_get_libfirm_params(void);

60
61
62
63
64
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)) {
65
		const arm_Address_attr_t *frame_attr = get_arm_Address_attr_const(irn);
66
		return frame_attr->entity;
67
68
69
70
71
72
73
74
	}
	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;
		}
	}
75
76
77
78
79
80
81
	return NULL;
}

/**
 * This function is called by the generic backend to correct offsets for
 * nodes accessing the stack.
 */
82
static void arm_set_stack_bias(ir_node *irn, int bias)
83
{
84
	if (is_arm_FrameAddr(irn)) {
85
		arm_Address_attr_t *attr = get_arm_Address_attr(irn);
86
87
88
89
90
91
		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;
	}
92
93
}

94
static int arm_get_sp_bias(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
95
{
96
	(void)node;
97
98
99
	return 0;
}

100
101
/* fill register allocator interface */

Matthias Braun's avatar
Matthias Braun committed
102
const arch_irn_ops_t arm_irn_ops = {
103
	arm_get_frame_entity,
104
	arm_set_stack_bias,
105
	arm_get_sp_bias,
106
107
108
	NULL,    /* get_op_estimated_cost   */
	NULL,    /* possible_memory_operand */
	NULL,    /* perform_memory_operand  */
109
110
111
};

/**
112
 * Transforms the standard Firm graph into an ARM firm graph.
113
 */
114
static void arm_prepare_graph(ir_graph *irg)
115
{
116
	/* transform nodes into assembler instructions */
117
	be_timer_push(T_CODEGEN);
118
	arm_transform_graph(irg);
119
	be_timer_pop(T_CODEGEN);
120
	be_dump(DUMP_BE, irg, "code-selection");
121

122
	/* do local optimizations (mainly CSE) */
123
	local_optimize_graph(irg);
124
125

	/* do code placement, to optimize the position of constants */
126
	place_code(irg);
127
}
128

129
static ir_node *arm_new_reload(ir_node *value, ir_node *spill, ir_node *before)
130
{
Matthias Braun's avatar
Matthias Braun committed
131
132
133
134
135
136
137
	ir_node  *block  = get_block(before);
	ir_graph *irg    = get_Block_irg(block);
	ir_node  *frame  = get_irg_frame(irg);
	ir_mode  *mode   = get_irn_mode(value);
	ir_node  *load   = new_bd_arm_Ldr(NULL, block, frame, spill, mode, NULL,
	                                  false, 0, true);
	ir_node  *proj   = new_r_Proj(load, mode, pn_arm_Ldr_res);
138
139
140
	arch_add_irn_flags(load, arch_irn_flag_reload);
	sched_add_before(before, load);
	return proj;
141
142
}

143
static ir_node *arm_new_spill(ir_node *value, ir_node *after)
144
{
145
146
147
148
149
150
151
152
153
154
	ir_node  *block  = get_block(after);
	ir_graph *irg    = get_Block_irg(block);
	ir_node  *frame  = get_irg_frame(irg);
	ir_node  *mem    = get_irg_no_mem(irg);
	ir_mode  *mode   = get_irn_mode(value);
	ir_node  *store  = new_bd_arm_Str(NULL, block, frame, value, mem, mode,
	                                  NULL, false, 0, true);
	arch_add_irn_flags(store, arch_irn_flag_spill);
	sched_add_after(after, store);
	return store;
155
156
}

157
static void arm_emit(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
158
{
159
	arm_finish_graph(irg);
160
	arm_emit_function(irg);
161
162
163
164
165
}

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
166
}
167

Matthias Braun's avatar
Matthias Braun committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
static ir_entity *divsi3;
static ir_entity *udivsi3;
static ir_entity *modsi3;
static ir_entity *umodsi3;

static void handle_intrinsic(ir_node *node, void *data)
{
	(void)data;
	if (is_Div(node)) {
		ir_mode *mode = get_Div_resmode(node);
		if (get_mode_arithmetic(mode) == irma_twos_complement) {
			ir_entity *entity = mode_is_signed(mode) ? divsi3 : udivsi3;
			be_map_exc_node_to_runtime_call(node, mode, entity, pn_Div_M,
			                                pn_Div_X_regular, pn_Div_X_except,
			                                pn_Div_res);
		}
Matthias Braun's avatar
Matthias Braun committed
184
	} else if (is_Mod(node)) {
Matthias Braun's avatar
Matthias Braun committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
		ir_mode *mode = get_Mod_resmode(node);
		assert(get_mode_arithmetic(mode) == irma_twos_complement);
		ir_entity *entity = mode_is_signed(mode) ? modsi3 : umodsi3;
		be_map_exc_node_to_runtime_call(node, mode, entity, pn_Mod_M,
		                                pn_Mod_X_regular, pn_Mod_X_except,
		                                pn_Mod_res);
	}
}

static void arm_create_runtime_entities(void)
{
	if (divsi3 != NULL)
		return;

Matthias Braun's avatar
Matthias Braun committed
199
200
201
202
203
204
205
206
	unsigned modulo_shift = arm_get_libfirm_params()->modulo_shift;
	ir_mode *mode_int = new_int_mode("arm_be_int", irma_twos_complement, 32,
	                                 true, modulo_shift);
	ir_mode *mode_uint = new_int_mode("arm_be_int", irma_twos_complement, 32,
	                                  false, modulo_shift);

	ir_type *int_tp  = get_type_for_mode(mode_int);
	ir_type *uint_tp = get_type_for_mode(mode_uint);
Matthias Braun's avatar
Matthias Braun committed
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

	ir_type *tp_divsi3 = new_type_method(2, 1);
	set_method_param_type(tp_divsi3, 0, int_tp);
	set_method_param_type(tp_divsi3, 1, int_tp);
	set_method_res_type(tp_divsi3, 0, int_tp);
	divsi3 = create_compilerlib_entity(new_id_from_str("__divsi3"), tp_divsi3);

	ir_type *tp_udivsi3 = new_type_method(2, 1);
	set_method_param_type(tp_udivsi3, 0, uint_tp);
	set_method_param_type(tp_udivsi3, 1, uint_tp);
	set_method_res_type(tp_udivsi3, 0, uint_tp);
	udivsi3 = create_compilerlib_entity(new_id_from_str("__udivsi3"), tp_udivsi3);

	ir_type *tp_modsi3 = new_type_method(2, 1);
	set_method_param_type(tp_modsi3, 0, int_tp);
	set_method_param_type(tp_modsi3, 1, int_tp);
	set_method_res_type(tp_modsi3, 0, int_tp);
	modsi3 = create_compilerlib_entity(new_id_from_str("__modsi3"), tp_modsi3);

	ir_type *tp_umodsi3 = new_type_method(2, 1);
	set_method_param_type(tp_umodsi3, 0, uint_tp);
	set_method_param_type(tp_umodsi3, 1, uint_tp);
	set_method_res_type(tp_umodsi3, 0, uint_tp);
	umodsi3 = create_compilerlib_entity(new_id_from_str("__umodsi3"), tp_umodsi3);
}

233
234
235
236
237
/**
 * 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
238
static void arm_handle_intrinsics(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
239
{
Matthias Braun's avatar
Matthias Braun committed
240
241
	arm_create_runtime_entities();
	irg_walk_graph(irg, handle_intrinsic, NULL, NULL);
242
243
}

244
extern const arch_isa_if_t arm_isa_if;
245
static arm_isa_t arm_isa_template = {
Michael Beck's avatar
Michael Beck committed
246
	{
247
		&arm_isa_if,             /* isa interface */
248
249
		N_ARM_REGISTERS,
		arm_registers,
250
251
		N_ARM_CLASSES,
		arm_reg_classes,
252
253
		&arm_registers[REG_SP],  /* stack pointer */
		&arm_registers[REG_R11], /* base pointer */
254
		3,                       /* power of two stack alignment for calls, 2^3 == 8 */
255
256
		7,                       /* spill costs */
		5,                       /* reload costs */
Michael Beck's avatar
Michael Beck committed
257
	},
258
};
259
260
261
262
263
static int arm_fpu = ARM_FPU_ARCH_SOFTFLOAT;

static void arm_setup_cg_config(void)
{
	memset(&arm_cg_config, 0, sizeof(arm_cg_config));
264
	arm_cg_config.variant = ARM_VARIANT_6;
265
266
267
268
269
	if (arm_fpu == ARM_FPU_SOFTFLOAT) {
		arm_cg_config.use_softfloat = true;
	}
	arm_cg_config.use_fpa = arm_fpu & ARM_FPU_FPA_EXT_V1;
	arm_cg_config.use_vfp = arm_fpu & ARM_FPU_VFP_EXT_V1xD;
Matthias Braun's avatar
Matthias Braun committed
270
	arm_cg_config.big_endian = arm_get_libfirm_params()->byte_order_big_endian;
271
}
272

273
static void arm_init(void)
274
{
275
276
277
	arm_mode_gp    = new_int_mode("arm_gp", irma_twos_complement, 32, 0, 256);
	arm_mode_flags = new_non_arithmetic_mode("arm_flags");

Matthias Braun's avatar
Matthias Braun committed
278
	arm_register_init();
Matthias Braun's avatar
Matthias Braun committed
279
	arm_create_opcodes(&arm_irn_ops);
280
	arm_setup_cg_config();
281
282
}

Matthias Braun's avatar
Matthias Braun committed
283
284
285
286
287
static void arm_finish(void)
{
	arm_free_opcodes();
}

288
static arch_env_t *arm_begin_codegeneration(void)
289
290
291
{
	arm_isa_t *isa = XMALLOC(arm_isa_t);
	*isa = arm_isa_template;
292

293
	be_gas_emit_types = false;
294
	be_gas_elf_type_char = '%';
295

296
297
	arm_emit_file_prologue();

298
	return &isa->base;
299
300
301
}

/**
Michael Beck's avatar
Michael Beck committed
302
 * Closes the output file and frees the ISA structure.
303
 */
304
static void arm_end_codegeneration(void *self)
305
{
306
307
308
	free(self);
}

Michael Beck's avatar
Michael Beck committed
309
310
311
312
/**
 * Allows or disallows the creation of Psi nodes for the given Phi nodes.
 * @return 1 if allowed, 0 otherwise
 */
313
314
315
static int arm_is_mux_allowed(ir_node *sel, ir_node *mux_false,
                              ir_node *mux_true)
{
Matthias Braun's avatar
Matthias Braun committed
316
317
318
	(void)sel;
	(void)mux_false;
	(void)mux_true;
319
	return false;
Michael Beck's avatar
Michael Beck committed
320
321
}

322
static int arm_is_valid_clobber(const char *clobber)
323
{
Matthias Braun's avatar
Matthias Braun committed
324
325
	(void)clobber;
	return false;
326
327
}

328
329
static void arm_lower_for_target(void)
{
330
	/* lower compound param handling */
331
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
332
	be_after_irp_transform("lower-calls");
333

334
	foreach_irp_irg(i, irg) {
335
		/* Turn all small CopyBs into loads/stores and all bigger CopyBs into
336
		 * memcpy calls. */
337
		lower_CopyB(irg, 31, 32, false);
338
		be_after_transform(irg, "lower-copyb");
339
	}
340
341
342
343
344
	if (arm_cg_config.use_softfloat) {
		lower_floating_point();
		be_after_irp_transform("lower-fp");
	}

Matthias Braun's avatar
Matthias Braun committed
345
346
347
348
349
350
351
	ir_builtin_kind supported[1];
	size_t s = 0;
	supported[s++] = ir_bk_clz;
	assert(s <= ARRAY_SIZE(supported));
	lower_builtins(s, supported);
	be_after_irp_transform("lower-builtins");

352
	foreach_irp_irg(i, irg) {
353
		lower_switch(irg, 4, 256, arm_mode_gp);
354
355
		be_after_transform(irg, "lower-switch");
	}
Matthias Braun's avatar
Matthias Braun committed
356
357
358

	arm_lower_64bit();
	be_after_irp_transform("lower-64");
359
360
}

Michael Beck's avatar
Michael Beck committed
361
362
363
/**
 * Returns the libFirm configuration parameter for this backend.
 */
364
365
static const backend_params *arm_get_libfirm_params(void)
{
366
	static ir_settings_arch_dep_t ad = {
Michael Beck's avatar
Michael Beck committed
367
		1,    /* allow subs */
368
		1,    /* Muls are fast enough on ARM but ... */
Michael Beck's avatar
Michael Beck committed
369
370
371
372
373
		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
374
375
	};
	static backend_params p = {
Matthias Braun's avatar
Matthias Braun committed
376
		false, /* big endian */
377
378
		false, /* PIC code not supported */
		false, /* unaligned memory access */
Matthias Braun's avatar
Matthias Braun committed
379
		256,   /* modulo shift */
380
381
		&ad,   /* will be set later */
		arm_is_mux_allowed, /* allow_ifconv function */
382
		32,    /* machine size */
383
		NULL,  /* float arithmetic mode (TODO) */
384
385
386
		NULL,  /* long long type */
		NULL,  /* unsigned long long type */
		NULL,  /* long double type */
387
388
		0,     /* no trampoline support: size 0 */
		0,     /* no trampoline support: align 0 */
389
		NULL,  /* no trampoline support: no trampoline builder */
390
391
		4,     /* alignment of stack parameter */
		ir_overflow_min_max
Michael Beck's avatar
Michael Beck committed
392
393
394
395
396
	};

	return &p;
}

Michael Beck's avatar
Michael Beck committed
397
398
399
400
401
402
403
404
405
406
407
408
/* 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 = {
409
	&arm_fpu, arm_fpu_items
Michael Beck's avatar
Michael Beck committed
410
411
};

Michael Beck's avatar
Michael Beck committed
412
static const lc_opt_table_entry_t arm_options[] = {
Matthias Braun's avatar
Matthias Braun committed
413
	LC_OPT_ENT_ENUM_INT("fpunit", "select the floating point unit", &arch_fpu_var),
414
	LC_OPT_LAST
Michael Beck's avatar
Michael Beck committed
415
};
416
417
418

const arch_isa_if_t arm_isa_if = {
	arm_init,
Matthias Braun's avatar
Matthias Braun committed
419
	arm_finish,
Michael Beck's avatar
Michael Beck committed
420
	arm_get_libfirm_params,
421
	arm_lower_for_target,
422
423
	arm_is_valid_clobber,

424
425
426
427
	arm_begin_codegeneration,
	arm_end_codegeneration,
	NULL,  /* get call abi */
	NULL,  /* mark remat */
428
429
	arm_new_spill,
	arm_new_reload,
430
431
432
	NULL,  /* register_saved_by */

	arm_handle_intrinsics, /* handle_intrinsics */
433
434
	arm_prepare_graph,
	arm_before_ra,
435
	arm_emit,
436
};
437

Matthias Braun's avatar
Matthias Braun committed
438
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_arm)
439
440
441
442
443
444
445
446
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);
447
448

	arm_init_transform();
449
	arm_init_emitter();
450
}