arm_bearch.c 10.6 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
#include "arm_bearch_t.h"

13
14
15
16
#include "arm_emitter.h"
#include "arm_new_nodes.h"
#include "arm_transform.h"
#include "be_t.h"
17
#include "beirg.h"
18
19
20
21
#include "beflags.h"
#include "begnuas.h"
#include "bemodule.h"
#include "benode.h"
22
#include "bera.h"
23
24
25
#include "besched.h"
#include "betranshlp.h"
#include "gen_arm_regalloc_if.h"
26
#include "irarch_t.h"
27
#include "irgopt.h"
28
#include "irgwalk.h"
29
#include "irprog_t.h"
30
31
#include "irtools.h"
#include "lc_opts_enum.h"
Matthias Braun's avatar
Matthias Braun committed
32
#include "lower_builtins.h"
33
#include "lower_calls.h"
34
#include "lower_softfloat.h"
35
#include "lowering.h"
Matthias Braun's avatar
Matthias Braun committed
36
#include "util.h"
37

38
39
40
#define ARM_MODULO_SHIFT 256
#define ARM_MACHINE_SIZE 32

41
42
arm_codegen_config_t arm_cg_config;

43
44
45
ir_mode *arm_mode_gp;
ir_mode *arm_mode_flags;

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

57
	/* do local optimizations (mainly CSE) */
58
	local_optimize_graph(irg);
59
60

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

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

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

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

118
119
static ir_type *make_divmod_type(ir_type *const tp)
{
120
	ir_type *const mtp = new_type_method(2, 1, false, cc_cdecl_set, mtp_no_property);
121
122
123
124
125
126
	set_method_param_type(mtp, 0, tp);
	set_method_param_type(mtp, 1, tp);
	set_method_res_type(mtp, 0, tp);
	return mtp;
}

Matthias Braun's avatar
Matthias Braun committed
127
128
129
130
131
static void arm_create_runtime_entities(void)
{
	if (divsi3 != NULL)
		return;

132
133
134
135
136
	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
137
138
139

	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
140

141
142
143
144
145
146
147
	ir_type *const mtps = make_divmod_type(int_tp);
	divsi3 = create_compilerlib_entity(new_id_from_str("__divsi3"), mtps);
	modsi3 = create_compilerlib_entity(new_id_from_str("__modsi3"), mtps);

	ir_type *const mtpu = make_divmod_type(uint_tp);
	udivsi3 = create_compilerlib_entity(new_id_from_str("__udivsi3"), mtpu);
	umodsi3 = create_compilerlib_entity(new_id_from_str("__umodsi3"), mtpu);
Matthias Braun's avatar
Matthias Braun committed
148
149
}

150
151
152
153
154
/**
 * 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
155
static void arm_handle_intrinsics(ir_graph *irg)
Matthias Braun's avatar
Matthias Braun committed
156
{
Matthias Braun's avatar
Matthias Braun committed
157
158
	arm_create_runtime_entities();
	irg_walk_graph(irg, handle_intrinsic, NULL, NULL);
159
160
}

161
162
163
164
165
166
167
static const regalloc_if_t arm_regalloc_if = {
	.spill_cost  = 7,
	.reload_cost = 5,
	.new_spill   = arm_new_spill,
	.new_reload  = arm_new_reload,
};

168
static void arm_generate_code(FILE *output, const char *cup_name)
169
{
170
	be_gas_emit_types = false;
171
	be_gas_elf_type_char = '%';
172

173
	be_begin(output, cup_name);
174
	unsigned *const sp_is_non_ssa = rbitset_alloca(N_ARM_REGISTERS);
175
	rbitset_set(sp_is_non_ssa, REG_SP);
176

177
	arm_emit_file_prologue();
178

179
180
181
182
	foreach_irp_irg(i, irg) {
		if (!be_step_first(irg))
			continue;

183
184
185
		struct obstack *obst = be_get_be_obst(irg);
		be_birg_from_irg(irg)->isa_link = OALLOCZ(obst, arm_irg_data_t);

186
		be_birg_from_irg(irg)->non_ssa_regs = sp_is_non_ssa;
187
188
189
190
191
192
193
194
		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);

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

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

		be_step_last(irg);
	}

	be_finish();
206
207
}

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

221
222
static void arm_lower_for_target(void)
{
223
	/* lower compound param handling */
224
	lower_calls_with_compounds(LF_RETURN_HIDDEN, NULL);
225
	be_after_irp_transform("lower-calls");
226

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

Matthias Braun's avatar
Matthias Braun committed
238
239
240
241
242
243
244
	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");

245
	foreach_irp_irg(i, irg) {
246
		lower_switch(irg, 4, 256, arm_mode_gp);
247
248
		be_after_transform(irg, "lower-switch");
	}
Matthias Braun's avatar
Matthias Braun committed
249
250
251

	arm_lower_64bit();
	be_after_irp_transform("lower-64");
252
253
}

254
static const ir_settings_arch_dep_t arm_arch_dep = {
255
256
257
258
259
260
261
	.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,
262
263
};
static backend_params arm_backend_params = {
264
	.experimental                  = "the arm backend is highly experimental and unfinished",
265
266
267
268
269
270
271
272
273
274
275
276
277
	.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,
278
279
280
281
	.vararg                        = {
		.va_list_type = NULL,
		.lower_va_arg = NULL,
	},
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
301
	set_modeP(new_reference_mode("p32", irma_twos_complement, ARM_MACHINE_SIZE, ARM_MODULO_SHIFT));

302
	arm_register_init();
303
	arm_create_opcodes();
304
305
	arm_init_backend_params();
}
306

307
308
309
310
311
static void arm_finish(void)
{
	arm_free_opcodes();
}

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

318
static arch_isa_if_t const arm_isa_if = {
319
320
321
322
323
324
325
326
327
	.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,
328
	.is_valid_clobber      = be_default_is_valid_clobber,
329
330
	.handle_intrinsics     = arm_handle_intrinsics,
	.get_op_estimated_cost = arm_get_op_estimated_cost,
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
359
360
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)
361
{
362
363
364
365
	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;
366

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

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

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