bearch_arm.c 11 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 = {
Matthias Braun's avatar
Matthias Braun committed
65
66
	.get_op_estimated_cost  = NULL,
	.perform_memory_operand = NULL,
67
68
69
};

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

80
	/* do local optimizations (mainly CSE) */
81
	local_optimize_graph(irg);
82
83

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

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

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

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

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

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

157
158
159
160
161
	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
162
163
164

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

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

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

202
extern const arch_isa_if_t arm_isa_if;
203
static arm_isa_t arm_isa_template = {
204
205
206
207
208
209
210
211
	.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
212
	},
213
};
Matthias Braun's avatar
Matthias Braun committed
214

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

220
	be_gas_emit_types = false;
221
	be_gas_elf_type_char = '%';
222

223
224
	arm_emit_file_prologue();

225
	return &isa->base;
226
227
228
}

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

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

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

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

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

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

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

	arm_lower_64bit();
	be_after_irp_transform("lower-64");
286
287
}

288
static const ir_settings_arch_dep_t arm_arch_dep = {
289
290
291
292
293
294
295
	.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,
296
297
};
static backend_params arm_backend_params = {
298
299
300
301
302
303
304
305
306
307
308
309
310
	.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,
311
312
313
314
315
316
317
};

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

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

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

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

334
335
336
337
	arm_register_init();
	arm_create_opcodes(&arm_irn_ops);
	arm_init_backend_params();
}
338
339

const arch_isa_if_t arm_isa_if = {
340
341
342
343
344
345
346
347
348
349
350
351
352
	.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,
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
381
382
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)
383
{
384
385
386
387
	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;
388

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

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

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