bearch_arm.c 10.5 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
13
14
15
16
17
18
19
#include "arm_emitter.h"
#include "arm_new_nodes.h"
#include "arm_transform.h"
#include "be_t.h"
#include "bearch_arm_t.h"
#include "beflags.h"
#include "begnuas.h"
#include "bemodule.h"
#include "benode.h"
20
#include "bera.h"
21
22
23
#include "besched.h"
#include "betranshlp.h"
#include "gen_arm_regalloc_if.h"
24
#include "irarch_t.h"
25
#include "irgopt.h"
26
#include "irgwalk.h"
27
#include "irprog_t.h"
28
29
#include "irtools.h"
#include "lc_opts_enum.h"
Matthias Braun's avatar
Matthias Braun committed
30
#include "lower_builtins.h"
31
#include "lower_calls.h"
32
#include "lower_softfloat.h"
33
#include "lowering.h"
Matthias Braun's avatar
Matthias Braun committed
34
#include "util.h"
35

36
37
38
#define ARM_MODULO_SHIFT 256
#define ARM_MACHINE_SIZE 32

39
40
arm_codegen_config_t arm_cg_config;

41
42
43
ir_mode *arm_mode_gp;
ir_mode *arm_mode_flags;

44
/**
45
 * Transforms the standard Firm graph into an ARM firm graph.
46
 */
47
static void arm_select_instructions(ir_graph *irg)
48
{
49
	/* transform nodes into assembler instructions */
50
	be_timer_push(T_CODEGEN);
51
	arm_transform_graph(irg);
52
	be_timer_pop(T_CODEGEN);
53
	be_dump(DUMP_BE, irg, "code-selection");
54

55
	/* do local optimizations (mainly CSE) */
56
	local_optimize_graph(irg);
57
58

	/* do code placement, to optimize the position of constants */
59
	place_code(irg);
60
}
61

62
static ir_node *arm_new_reload(ir_node *value, ir_node *spill, ir_node *before)
63
{
Matthias Braun's avatar
Matthias Braun committed
64
	ir_node  *block  = get_block(before);
65
	ir_graph *irg    = get_irn_irg(before);
Matthias Braun's avatar
Matthias Braun committed
66
67
68
69
70
	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);
71
72
73
	arch_add_irn_flags(load, arch_irn_flag_reload);
	sched_add_before(before, load);
	return proj;
74
75
}

76
static ir_node *arm_new_spill(ir_node *value, ir_node *after)
77
{
78
	ir_node  *block  = get_block(after);
79
	ir_graph *irg    = get_irn_irg(after);
80
81
82
83
84
85
86
87
	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;
88
89
}

Matthias Braun's avatar
Matthias Braun committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
106
	} else if (is_Mod(node)) {
Matthias Braun's avatar
Matthias Braun committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
		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;

121
122
123
124
125
	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
126
127
128

	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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

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

155
156
157
158
159
/**
 * 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
160
static void arm_handle_intrinsics(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
161
{
Matthias Braun's avatar
Matthias Braun committed
162
163
	arm_create_runtime_entities();
	irg_walk_graph(irg, handle_intrinsic, NULL, NULL);
164
165
}

166
167
168
169
170
171
172
static const regalloc_if_t arm_regalloc_if = {
	.spill_cost  = 7,
	.reload_cost = 5,
	.new_spill   = arm_new_spill,
	.new_reload  = arm_new_reload,
};

173
static void arm_generate_code(FILE *output, const char *cup_name)
174
{
175
	be_gas_emit_types = false;
176
	be_gas_elf_type_char = '%';
177

178
179
	be_begin(output, cup_name);

180
	arm_emit_file_prologue();
181

182
183
184
185
186
187
188
189
190
191
192
193
	foreach_irp_irg(i, irg) {
		if (!be_step_first(irg))
			continue;

		arm_select_instructions(irg);

		be_step_schedule(irg);

		be_timer_push(T_RA_PREPARATION);
		be_sched_fix_flags(irg, &arm_reg_classes[CLASS_arm_flags], NULL, NULL, NULL);
		be_timer_pop(T_RA_PREPARATION);

194
		be_step_regalloc(irg, &arm_regalloc_if);
195
196
197
198
199
200
201
202
203
204

		be_timer_push(T_EMIT);
		arm_finish_graph(irg);
		arm_emit_function(irg);
		be_timer_pop(T_EMIT);

		be_step_last(irg);
	}

	be_finish();
205
206
}

Michael Beck's avatar
Michael Beck committed
207
/**
208
 * Allows or disallows the creation of Mux nodes for the given Phi nodes.
Michael Beck's avatar
Michael Beck committed
209
210
 * @return 1 if allowed, 0 otherwise
 */
211
212
213
static int arm_is_mux_allowed(ir_node *sel, ir_node *mux_false,
                              ir_node *mux_true)
{
Matthias Braun's avatar
Matthias Braun committed
214
215
216
	(void)sel;
	(void)mux_false;
	(void)mux_true;
217
	return false;
Michael Beck's avatar
Michael Beck committed
218
219
}

220
static int arm_is_valid_clobber(const char *clobber)
221
{
Matthias Braun's avatar
Matthias Braun committed
222
223
	(void)clobber;
	return false;
224
225
}

226
227
static void arm_lower_for_target(void)
{
228
	/* lower compound param handling */
229
	lower_calls_with_compounds(LF_RETURN_HIDDEN);
230
	be_after_irp_transform("lower-calls");
231

232
	foreach_irp_irg(i, irg) {
233
		/* Turn all small CopyBs into loads/stores and all bigger CopyBs into
234
		 * memcpy calls. */
235
		lower_CopyB(irg, 31, 32, false);
236
		be_after_transform(irg, "lower-copyb");
237
	}
238
	if (arm_cg_config.fpu == ARM_FPU_SOFTFLOAT) {
239
240
241
242
		lower_floating_point();
		be_after_irp_transform("lower-fp");
	}

Matthias Braun's avatar
Matthias Braun committed
243
244
245
246
247
248
249
	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");

250
	foreach_irp_irg(i, irg) {
251
		lower_switch(irg, 4, 256, arm_mode_gp);
252
253
		be_after_transform(irg, "lower-switch");
	}
Matthias Braun's avatar
Matthias Braun committed
254
255
256

	arm_lower_64bit();
	be_after_irp_transform("lower-64");
257
258
}

259
static const ir_settings_arch_dep_t arm_arch_dep = {
260
261
262
263
264
265
266
	.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,
267
268
};
static backend_params arm_backend_params = {
269
270
271
272
273
274
275
276
277
278
279
280
281
	.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,
282
283
284
285
286
287
288
};

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

289
290
static const backend_params *arm_get_libfirm_params(void)
{
291
	return &arm_backend_params;
Michael Beck's avatar
Michael Beck committed
292
293
}

294
295
296
297
static void arm_init(void)
{
	arm_mode_gp    = new_int_mode("arm_gp", irma_twos_complement,
	                              ARM_MACHINE_SIZE, 0, ARM_MODULO_SHIFT);
298
	arm_mode_flags = new_non_arithmetic_mode("arm_flags", 32);
Michael Beck's avatar
Michael Beck committed
299

300
	arm_register_init();
301
	arm_create_opcodes();
302
303
	arm_init_backend_params();
}
304

305
306
307
308
309
static void arm_finish(void)
{
	arm_free_opcodes();
}

310
311
312
313
314
315
static unsigned arm_get_op_estimated_cost(const ir_node *node)
{
	(void)node; /* TODO */
	return 1;
}

316
static arch_isa_if_t const arm_isa_if = {
317
318
319
320
321
322
323
324
325
326
327
328
	.n_registers           = N_ARM_REGISTERS,
	.registers             = arm_registers,
	.n_register_classes    = N_ARM_CLASSES,
	.register_classes      = arm_reg_classes,
	.init                  = arm_init,
	.finish                = arm_finish,
	.get_params            = arm_get_libfirm_params,
	.generate_code         = arm_generate_code,
	.lower_for_target      = arm_lower_for_target,
	.is_valid_clobber      = arm_is_valid_clobber,
	.handle_intrinsics     = arm_handle_intrinsics,
	.get_op_estimated_cost = arm_get_op_estimated_cost,
329
};
330

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
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)
359
{
360
361
362
363
	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;
364

365
366
	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");
367
	lc_opt_add_table(arm_grp, arm_options);
368
}
369

370
371
372
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_arm)
void be_init_arch_arm(void)
{
373
	arm_init_transform();
374
	arm_init_emitter();
375
376
377
	arm_init_architecture();

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