bearch_arm.c 10.9 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 "irarch_t.h"
15
#include "irgwalk.h"
16
#include "irprog_t.h"
17
18
#include "ircons.h"
#include "irgmod.h"
19
#include "irgopt.h"
Matthias Braun's avatar
Matthias Braun committed
20
#include "iroptimize.h"
21
#include "irdump.h"
Matthias Braun's avatar
Matthias Braun committed
22
#include "lower_builtins.h"
23
#include "lower_calls.h"
24
#include "lower_softfloat.h"
Matthias Braun's avatar
Matthias Braun committed
25
#include "panic.h"
26
#include "debug.h"
27
#include "array.h"
Michael Beck's avatar
Michael Beck committed
28
#include "irtools.h"
Matthias Braun's avatar
Matthias Braun committed
29
#include "util.h"
30

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

#include "bearch_arm_t.h"

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

54
55
56
#define ARM_MODULO_SHIFT 256
#define ARM_MACHINE_SIZE 32

57
58
arm_codegen_config_t arm_cg_config;

59
60
61
ir_mode *arm_mode_gp;
ir_mode *arm_mode_flags;

62
63
/* fill register allocator interface */

Matthias Braun's avatar
Matthias Braun committed
64
const arch_irn_ops_t arm_irn_ops = {
65
66
67
};

/**
68
 * Transforms the standard Firm graph into an ARM firm graph.
69
 */
70
static void arm_prepare_graph(ir_graph *irg)
71
{
72
	/* transform nodes into assembler instructions */
73
	be_timer_push(T_CODEGEN);
74
	arm_transform_graph(irg);
75
	be_timer_pop(T_CODEGEN);
76
	be_dump(DUMP_BE, irg, "code-selection");
77

78
	/* do local optimizations (mainly CSE) */
79
	local_optimize_graph(irg);
80
81

	/* do code placement, to optimize the position of constants */
82
	place_code(irg);
83
}
84

85
static ir_node *arm_new_reload(ir_node *value, ir_node *spill, ir_node *before)
86
{
Matthias Braun's avatar
Matthias Braun committed
87
	ir_node  *block  = get_block(before);
88
	ir_graph *irg    = get_irn_irg(before);
Matthias Braun's avatar
Matthias Braun committed
89
90
91
92
93
	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);
94
95
96
	arch_add_irn_flags(load, arch_irn_flag_reload);
	sched_add_before(before, load);
	return proj;
97
98
}

99
static ir_node *arm_new_spill(ir_node *value, ir_node *after)
100
{
101
	ir_node  *block  = get_block(after);
102
	ir_graph *irg    = get_irn_irg(after);
103
104
105
106
107
108
109
110
	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;
111
112
}

113
static void arm_emit(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
114
{
115
	arm_finish_graph(irg);
116
	arm_emit_function(irg);
117
118
119
120
}

static void arm_before_ra(ir_graph *irg)
{
121
	be_sched_fix_flags(irg, &arm_reg_classes[CLASS_arm_flags], NULL, NULL, NULL);
Michael Beck's avatar
Michael Beck committed
122
}
123

Matthias Braun's avatar
Matthias Braun committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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
140
	} else if (is_Mod(node)) {
Matthias Braun's avatar
Matthias Braun committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
		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;

155
156
157
158
159
	ir_mode *mode_int = new_int_mode("arm_be_int", irma_twos_complement,
	                                 ARM_MACHINE_SIZE, true, ARM_MODULO_SHIFT);
	ir_mode *mode_uint = new_int_mode("arm_be_int", irma_twos_complement,
	                                  ARM_MACHINE_SIZE, false,
	                                  ARM_MODULO_SHIFT);
Matthias Braun's avatar
Matthias Braun committed
160
161
162

	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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

	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);
}

189
190
191
192
193
/**
 * 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
194
static void arm_handle_intrinsics(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
195
{
Matthias Braun's avatar
Matthias Braun committed
196
197
	arm_create_runtime_entities();
	irg_walk_graph(irg, handle_intrinsic, NULL, NULL);
198
199
}

200
extern const arch_isa_if_t arm_isa_if;
201
static arm_isa_t arm_isa_template = {
202
203
204
205
206
207
208
209
	.base = {
		.impl               = &arm_isa_if,
		.n_registers        = N_ARM_REGISTERS,
		.registers          = arm_registers,
		.n_register_classes = N_ARM_CLASSES,
		.register_classes   = arm_reg_classes,
		.spill_cost         = 7,
		.reload_cost        = 5,
Michael Beck's avatar
Michael Beck committed
210
	},
211
};
Matthias Braun's avatar
Matthias Braun committed
212

213
static arch_env_t *arm_begin_codegeneration(void)
214
215
216
{
	arm_isa_t *isa = XMALLOC(arm_isa_t);
	*isa = arm_isa_template;
217

218
	be_gas_emit_types = false;
219
	be_gas_elf_type_char = '%';
220

221
222
	arm_emit_file_prologue();

223
	return &isa->base;
224
225
226
}

/**
Michael Beck's avatar
Michael Beck committed
227
 * Closes the output file and frees the ISA structure.
228
 */
229
static void arm_end_codegeneration(void *self)
230
{
231
232
233
	free(self);
}

Michael Beck's avatar
Michael Beck committed
234
/**
235
 * Allows or disallows the creation of Mux nodes for the given Phi nodes.
Michael Beck's avatar
Michael Beck committed
236
237
 * @return 1 if allowed, 0 otherwise
 */
238
239
240
static int arm_is_mux_allowed(ir_node *sel, ir_node *mux_false,
                              ir_node *mux_true)
{
Matthias Braun's avatar
Matthias Braun committed
241
242
243
	(void)sel;
	(void)mux_false;
	(void)mux_true;
244
	return false;
Michael Beck's avatar
Michael Beck committed
245
246
}

247
static int arm_is_valid_clobber(const char *clobber)
248
{
Matthias Braun's avatar
Matthias Braun committed
249
250
	(void)clobber;
	return false;
251
252
}

253
254
static void arm_lower_for_target(void)
{
255
	/* lower compound param handling */
256
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
257
	be_after_irp_transform("lower-calls");
258

259
	foreach_irp_irg(i, irg) {
260
		/* Turn all small CopyBs into loads/stores and all bigger CopyBs into
261
		 * memcpy calls. */
262
		lower_CopyB(irg, 31, 32, false);
263
		be_after_transform(irg, "lower-copyb");
264
	}
265
	if (arm_cg_config.fpu == ARM_FPU_SOFTFLOAT) {
266
267
268
269
		lower_floating_point();
		be_after_irp_transform("lower-fp");
	}

Matthias Braun's avatar
Matthias Braun committed
270
271
272
273
274
275
276
	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");

277
	foreach_irp_irg(i, irg) {
278
		lower_switch(irg, 4, 256, arm_mode_gp);
279
280
		be_after_transform(irg, "lower-switch");
	}
Matthias Braun's avatar
Matthias Braun committed
281
282
283

	arm_lower_64bit();
	be_after_irp_transform("lower-64");
284
285
}

286
static const ir_settings_arch_dep_t arm_arch_dep = {
287
288
289
290
291
292
293
	.also_use_subs        = true,
	.maximum_shifts       = 1,
	.highest_shift_amount = 31,
	.evaluate             = NULL,
	.allow_mulhs          = false,
	.allow_mulhu          = false,
	.max_bits_for_mulh    = ARM_MACHINE_SIZE,
294
295
};
static backend_params arm_backend_params = {
296
297
298
299
300
301
302
303
304
305
306
307
308
	.byte_order_big_endian         = false,
	.pic_supported                 = false,
	.unaligned_memaccess_supported = false,
	.modulo_shift                  = ARM_MODULO_SHIFT,
	.dep_param                     = &arm_arch_dep,
	.allow_ifconv                  = arm_is_mux_allowed,
	.machine_size                  = ARM_MACHINE_SIZE,
	.mode_float_arithmetic         = NULL,
	.type_long_long                = NULL,
	.type_unsigned_long_long       = NULL,
	.type_long_double              = NULL,
	.stack_param_align             = 4,
	.float_int_overflow            = ir_overflow_min_max,
309
310
311
312
313
314
315
};

static void arm_init_backend_params(void)
{
	arm_backend_params.byte_order_big_endian = arm_cg_config.big_endian;
}

316
317
static const backend_params *arm_get_libfirm_params(void)
{
318
	return &arm_backend_params;
Michael Beck's avatar
Michael Beck committed
319
320
}

321
322
323
324
static void arm_finish(void)
{
	arm_free_opcodes();
}
Michael Beck's avatar
Michael Beck committed
325

326
327
328
329
330
static void arm_init(void)
{
	arm_mode_gp    = new_int_mode("arm_gp", irma_twos_complement,
	                              ARM_MACHINE_SIZE, 0, ARM_MODULO_SHIFT);
	arm_mode_flags = new_non_arithmetic_mode("arm_flags");
Michael Beck's avatar
Michael Beck committed
331

332
333
334
335
	arm_register_init();
	arm_create_opcodes(&arm_irn_ops);
	arm_init_backend_params();
}
336
337

const arch_isa_if_t arm_isa_if = {
338
339
340
341
342
343
344
345
346
347
348
349
350
	.init                 = arm_init,
	.finish               = arm_finish,
	.get_params           = arm_get_libfirm_params,
	.lower_for_target     = arm_lower_for_target,
	.is_valid_clobber     = arm_is_valid_clobber,
	.begin_codegeneration = arm_begin_codegeneration,
	.end_codegeneration   = arm_end_codegeneration,
	.new_spill            = arm_new_spill,
	.new_reload           = arm_new_reload,
	.handle_intrinsics    = arm_handle_intrinsics,
	.prepare_graph        = arm_prepare_graph,
	.before_ra            = arm_before_ra,
	.emit                 = arm_emit,
351
};
352

353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
static const lc_opt_enum_int_items_t arm_fpu_items[] = {
	{ "softfloat", ARM_FPU_SOFTFLOAT },
	{ "fpa",       ARM_FPU_FPA       },
	{ NULL,        0                 },
};
static lc_opt_enum_int_var_t arch_fpu_var = {
	(int*)&arm_cg_config.fpu, arm_fpu_items
};

static const lc_opt_enum_int_items_t arm_arch_items[] = {
	{ "armv4",   ARM_VARIANT_4   },
	{ "armv5t",  ARM_VARIANT_5T  },
	{ "armv6",   ARM_VARIANT_6   },
	{ "armv6t2", ARM_VARIANT_6T2 },
	{ "armv7",   ARM_VARIANT_7   },
	{ NULL,      0               },
};
static lc_opt_enum_int_var_t arch_var = {
	(int*)&arm_cg_config.variant, arm_arch_items
};

static const lc_opt_table_entry_t arm_options[] = {
	LC_OPT_ENT_ENUM_INT("fpu", "select the floating point unit", &arch_fpu_var),
	LC_OPT_ENT_ENUM_INT("arch", "select architecture variant", &arch_var),
	LC_OPT_LAST
};

static void arm_init_architecture(void)
381
{
382
383
384
385
	memset(&arm_cg_config, 0, sizeof(arm_cg_config));
	arm_cg_config.variant    = ARM_VARIANT_6T2;
	arm_cg_config.fpu        = ARM_FPU_SOFTFLOAT;
	arm_cg_config.big_endian = false;
386

387
388
	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");
389
	lc_opt_add_table(arm_grp, arm_options);
390
}
391

392
393
394
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_arm)
void be_init_arch_arm(void)
{
395
	arm_init_transform();
396
	arm_init_emitter();
397
398
399
	arm_init_architecture();

	be_register_isa_if("arm", &arm_isa_if);
400
}